来自用户提供类型的泛型事件生成器和处理程序
本文关键字:程序 处理 事件 泛型 用户 类型 | 更新日期: 2023-09-27 18:36:48
我正在尝试允许用户提供自定义数据并使用自定义类型管理数据。用户的算法将把时间同步事件推送到他们定义的事件处理程序中。
我不确定这是否可能,但这是我想要构建的"概念验证"代码。它不会在 for 循环中检测到 T:"找不到类型或命名空间名称'T'"
class Program
{
static void Main(string[] args)
{
Algorithm algo = new Algorithm();
Dictionary<Type, string[]> userDataSources = new Dictionary<Type, string[]>();
// "User" adding custom type and data source for algorithm to consume
userDataSources.Add(typeof(Weather), new string[] { "temperature data1", "temperature data2" });
for (int i = 0; i < 2; i++)
{
foreach (Type T in userDataSources.Keys)
{
string line = userDataSources[typeof(T)][i]; //Iterate over CSV data..
var userObj = new T(line);
algo.OnData < typeof(T) > (userObj);
}
}
}
//User's algorithm pattern.
interface IAlgorithm<TData> where TData : class
{
void OnData<TData>(TData data);
}
//User's algorithm.
class Algorithm : IAlgorithm<Weather> {
//Handle Custom User Data
public void OnData<Weather>(Weather data)
{
Console.WriteLine(data.date.ToString());
Console.ReadKey();
}
}
//Example "user" custom type.
public class Weather {
public DateTime date = new DateTime();
public double temperature = 0;
public Weather(string line) {
Console.WriteLine("Initializing weather object with: " + line);
date = DateTime.Now;
temperature = -1;
}
}
}
编辑:
string line = userDataSources[t][i]; //Iterate over CSV data..
var userObj = Activator.CreateInstance(t);
algo.OnData<t>(userObj);
同样的错误,但现在它在 OnData 上,所以它无法调用泛型事件,因为它无法将 T 识别为泛型类型?
typeof(x)
将返回由类型名称表示的Type
实例 x
。
在您的情况下,您已经有一个Type
实例;您的变量T
的类型为 Type
。因此,您不需要使用typeof
:
string line = userDataSources[T][i];
作为关于样式的建议,没有理由使用大写T
作为局部变量的名称;它是一个普通的局部变量,就像i
一样,所以只需称它为t
。 T
看起来像一个通用参数,但事实并非如此。
不过,接下来的两行不会那么容易:
var userObj = new T(line);
algo.OnData < typeof(T) > (userObj);
由于T
在编译时是未知的,因此您无法进行任何此类调用。您必须使用反射来执行这些调用 - 首先,使用 Activator
类创建当前引用的任何类型的实例T
(userObj
在编译时键入System.Object
)。
随后,检索algo
的OnData
方法的MethodInfo
实例并调用MakeGenericMethod
以获取插入T
的泛型版本。然后,可以调用其中一个Invoke
重载来实际执行OnData<T>
方法。
泛型有很多事情做错了:
-
算法接口及其实现看起来不像您已经定义了它们。指定 type 的泛型参数后,无需在方法中再次指定它。所以这将起作用:
//User's algorithm pattern. interface IAlgorithm<TData> where TData : class { void OnData(TData data); } //User's algorithm. class Algorithm : IAlgorithm<Weather> { //Handle Custom User Data public void OnData(Weather data) { Console.WriteLine(data.date.ToString()); Console.ReadKey(); } }
在这种情况下,用法是:
var userObj = Activator.CreateInstance(type, line); algo.OnData((Weather)userObj);
-
不能像使用通用参数那样使用密钥信息。泛型参数是编译时,类型实例 - 运行时。通过反思,有办法,但它们是丑陋和低效的。所以,没有新的T(线)。此外,即使你在这里有正确的泛型参数,你也只能使用默认构造函数创建它,并且只有在你对参数有 new() 约束的情况下。
-
没有算法。OnData
(userObj), 请参阅上一个项目符号。
我向您提出以下建议:
//User's algorithm pattern.
interface IAlgorithm
{
void OnData(object data);
}
abstract class BaseAlgorithm<TData> : IAlgorithm where TData : class
{
public void OnData(object data)
{
//perform type checks here, if necessary
OnData(data as TData);
}
protected abstract void OnData(TData data);
}
//User's algorithm.
class Algorithm : BaseAlgorithm<Weather>
{
//Handle Custom User Data
protected override void OnData(Weather data)
{
Console.WriteLine(data.date.ToString());
Console.ReadKey();
}
}
感谢 @O.R 映射器和@galenus :: 使用两个答案的组合,这很优雅,不需要太多思考。通过添加的假设,有一个包含日期时间的基本数据类 - 跨所有时间序列数据的通用索引。
class Program
{
static void Main(string[] args)
{
IAlgorithm algo = new Algorithm();
Dictionary<Type, string[]> userDataSources = new Dictionary<Type, string[]>();
userDataSources.Add(typeof(Weather), new string[] { "temperature data1", "temperature data2" });
for (int i = 0; i < 2; i++)
{
foreach (Type t in userDataSources.Keys)
{
string line = userDataSources[t][i]; //Iterate over CSV data..
var userObj = Activator.CreateInstance(t);
UserData castObj = (UserData)userObj;
castObj.Constuctor(line);
algo.OnData(castObj);
}
}
}
interface IAlgorithm
{
void OnData(object data);
}
abstract class BaseAlgorithm<TData> : IAlgorithm where TData : class
{
public void OnData(object data)
{
//perform type checks here, if necessary
OnData(data as TData);
}
protected abstract void OnData(TData data);
}
//User's algorithm.
class Algorithm : BaseAlgorithm<Weather>
{
//Handle Custom User Data
protected override void OnData(Weather data)
{
Console.WriteLine(data.date.ToString());
Console.ReadKey();
}
}
public abstract class UserData {
public DateTime date;
public UserData() { }
public abstract void Constuctor(string line);
}
public class Weather : UserData
{
public DateTime date = new DateTime();
public double temperature = 0;
public Weather() { }
public override void Constuctor(string line) {
Console.WriteLine("Initializing weather object with: " + line);
date = DateTime.Now;
temperature = -1;
}
}
}