0

我试图允许用户提供自定义数据并使用自定义类型管理数据。用户的算法会将时间同步的事件推送到他们定义的事件处理程序中。

我不确定这是否可能,但这是我想构建的“概念证明”代码。它没有在 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 识别为泛型类型?

4

3 回答 3

1

typeof(x)将返回Type由类型 name 表示的实例x

就您而言,您已经有一个Type实例;你的变量T是类型Type。因此,您不需要使用typeof

string line = userDataSources[T][i];

作为关于样式的建议,没有理由使用大写T作为局部变量的名称;它是一个普通的局部变量i,所以只需调用它tT看起来像一个通用参数,但它不是。


不过,接下来的两行不会那么容易:

var userObj = new T(line);
algo.OnData < typeof(T) > (userObj);

正如T在编译时所不知道的那样,您不能进行任何这样的调用。您将不得不使用反射来执行这些调用 - 首先,使用Activator该类创建T当前引用的任何类型的实例(在编译时userObj键入)。System.Object

随后,检索您的方法的MethodInfo实例并调用以获取插入的通用版本。然后,您可以调用其中一个重载来实际执行该方法。algoOnDataMakeGenericMethodTInvokeOnData<T>

于 2013-10-23T22:03:11.360 回答
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);
    
  2. 您不能像使用通用参数那样使用关键信息。通用参数是编译时,类型实例 - 运行时。有一些方法,通过反思,但它们是丑陋和低效的。所以,没有新的 T(line)。此外,即使您在这里有正确的通用参数,您也只能使用默认构造函数创建它,并且只有在您对参数有new()约束的情况下才能创建它。

  3. 也没有algo.OnData<t>(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();
        }
    }
于 2013-10-23T22:20:53.303 回答
0

感谢@OR Mapper 和@galenus :: 结合使用您的两个答案,这可以优雅地工作,无需太多反思。通过添加的假设,有一个包含 datetime 的基本数据类——一个跨所有时间序列数据的公共索引。

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;
        }
    }
}
于 2013-10-23T22:46:29.143 回答