在字典中使用带有未指定类型参数的泛型作为值

时间:2018-07-12 16:20:59

标签: c#

我正在编写一种方法,该方法根据传入的类型为加载过程返回类的不同实例。

我要写的方法将像这样使用:

Loader<MyType> loader = context.GetLoader<MyType>();
loader.Load(myTypeArray);

在内部,我打算将加载器作为值保留Dictionary<Type, T>。但是,我不确定T应该是哪种类型。

我可以制作T object,但我更喜欢将其保留为Loader<>。我知道我需要以任何一种方式进行转换,但是使用Loader<>会带来更多类型安全性。

有什么好的方法可以实现吗?

2 个答案:

答案 0 :(得分:3)

您有两种选择。两者都需要您添加接口。

  1. 添加一个普通的ILoader(无类型参数)接口,并在您的加载程序中将其实现为class Loader<T> : ILoader。通用界面可让您将所有加载程序存储在List<ILoader>中。

    interface ILoader {}
    
    class Loader<T> : ILoader {}
    
    void Example()
    {
        var loaders = new List<ILoader>();
        loaders.Add( new Loader<Foo>() );
        loaders.Add( new Loader<Bar>() );
    }
    
  2. 定义一个新的协变接口ILoader<out T>,并在您的Loader中将其实现为class Loader<T> : ILoader<T>。协方差将允许您将所有加载程序存储在List<ILoader<object>>中。此选项仅在T是引用类型时才有效,并且仅在您的接口方法都没有接受T作为参数时才可行。

    interface ILoader<out T> 
    {
        //void SetLoader(T input);         //Does not compile due to covariance
        T GetLoader();                     //Read is allowed
    }
    
    class Loader<T> : ILoader<T> 
    {
        public void SetLoader(T input) {}  //Works when not in interface
        public T GetLoader() { return default(T); }
    }
    
    void Example()
    {
        var loaders = new List<ILoader<object>>();
        loaders.Add( new Loader<Foo>() );
        loaders.Add( new Loader<Bar>() );
    }
    

Code sample on DotNetFiddle

答案 1 :(得分:2)

  

我可以制作T object,但我更喜欢将其保留为Loader<>。我知道我需要以任何一种方式进行转换,但是使用Loader<>会带来更多类型安全性。

不,它不会;这句话自相矛盾!您说“我知道我需要强制转换”,所以已经有编译时类型安全性,并且您可以获得更多类型安全性,但是零是不超过零!

请记住,保留表示形式的强制转换的功能恰恰是“我知道编译器在编译时不知道的在运行时将是正确的事实”。 那是演员的目的

在C#类型系统中无法表示“这是C<?>类型的事物”,因此不要尝试查找它。您已经接受了运行时类型检查,因此继续吧。您的变量dict[typeof(T)]产生的类型为Loader<T>不变。唯一可以保持不变的人是 you ,因此,甚至不要试图依靠编译器为您做到这一点。