首页 > 解决方案 > 铸造泛型类型 C#

问题描述

我想有一个接口,它允许我保留泛型类的对象。下面的一些代码和更多解释:

    public interface IItem { }
public interface IClass1<T> : IEnumerable<T> { }
public class Item1 : IItem { }
public class Item2 : IItem { }
public class Class1<T> : IClass1<T> where T : class, IItem { }
public class Class2<T> : IClass1<T> where T : class, IItem { }
public class Class : UserControl
{
    IClass1<IItem> _item;
    public virtual IClass1<IItem> item
    {
    get
        {
            return _item;
        }
    set
        {
            _item = value;
            //then do something...
        }
    }
    public Class2()
    {
        //few examples what I would like to do
        item = new Class1<Item1>();
        item = new Class1<Item2>();
        item = new Class2<Item1>();
        item = new Class2<Item2>();
    }
}

问题是 Class2 将作为继承类的基础,我只知道,字段 _item 将保留实现一些通用接口的类的对象(接口继承自 IEnumerable,因此它必须是通用的),我不知道我如何强制字段项接受实现此接口的类的对象,(虽然它们的通用类型可以是 Item1、Item2 等,但它们都实现了 IItem 接口)

标签: c#generics

解决方案


以下是将您的类重新定义为更易于理解的内容:

public interface IFruit { }
public interface ICollectionOfFruit<T> : IEnumerable<T> { }
public class Apple : IFruit { }
public class Banana : IFruit { }
public class BoxOfFruit<T> : ICollectionOfFruit<T> where T : class, IFruit { public IEnumerator<T> GetEnumerator() { throw new NotImplementedException(); } IEnumerator IEnumerable.GetEnumerator() { throw new NotImplementedException(); } }
public class BagOfFruit<T> : ICollectionOfFruit<T> where T : class, IFruit { public IEnumerator<T> GetEnumerator() { throw new NotImplementedException(); } IEnumerator IEnumerable.GetEnumerator() { throw new NotImplementedException(); } }
public class Class
{
    ICollectionOfFruit<IFruit> _item;

    public Class()
    {
        //few examples what I would like to do
        _item = new BoxOfFruit<Apple>();
        _item = new BoxOfFruit<Banana>();
        _item = new BagOfFruit<Apple>();
        _item = new BagOfFruit<Banana>();
    }
}

您需要了解的是,即使Apple继承(实现)也不会继承自IFruitICollectionOfFruit<Apple>ICollectionOfFruit<IFruit>

如果ICollectionOfFruit<T>继承IList<T>,则转换BoxOfFruit<Apple>ICollectionOfFruit<IFruit>将允许您将 a 添加Banana到集合中。这会在运行时爆炸。

但是,在您的情况下,ICollectionOfFruit<T>继承自IEnumerable<T>因此您可以进行一项简单的更改以使您的代码正常工作:

public interface ICollectionOfFruit<out T> : IEnumerable<T> { }

因为out这意味着您永远不会尝试将其放入in您的收藏中IFruit,因此允许演员表是安全的。

但是,如果您的实际用例允许ICollectionOfFruit<T>将 aT作为方法的输入,那么您就不能使用out.


推荐阅读