我正在尝试允许用户提供自定义数据并使用自定义类型管理数据。用户的算法将时间同步的事件推送到他们定义的事件处理程序中。
我不确定这是否可行,但这里是我想要构建的“概念证明”代码。它在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作为泛型类型?
答案 0 :(得分:1)
typeof(x)
将返回类型名称x
表示的Type
个实例。
在您的情况下,您已经有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
的{{1}}方法的MethodInfo
实例,并调用MakeGenericMethod
以获取插入了OnData
的通用版本。然后,您可以调用one of the Invoke
overloads来实际执行T
方法。
答案 1 :(得分:1)
对于泛型,你做了很多事情:
算法接口及其实现看起来不像你已定义它们。指定类型的泛型参数后,您不必在方法中再次指定它。所以这将有效:
//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() constraint时才会创建。
否 algo.OnData&lt; t&gt;(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();
}
}
答案 2 :(得分:0)
感谢@ O.R Mapper和@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;
}
}
}