【问题标题】:Declare a List of class references声明类引用列表
【发布时间】:2018-11-06 12:45:36
【问题描述】:

我需要声明一个类引用列表。具体来说,一个实现接口的类列表,在这里我将其称为IInterface

类似于 List 如何成为类型列表,如下所示:

List<Type> types = new List<Type> {string, bool, int, float};

我需要完成同样的事情,其中​​每个都是我自己的类并实现接口 IInterface 所以:

List<(idk)> references = new List<(idk)> {myClass, myClass2, myClass3};

它们都是MyClass : IInterfaceMyClass2 : IInterfaceMyClass3 : IInterface

我需要这个,这样当我创建类型的实例时,编译器就会知道该类型实现了IInterface

【问题讨论】:

  • 您是否尝试将类型添加到此列表或这些类型的实例?
  • 是的,这还不清楚,如果你想添加实例,List&lt;IInterface&gt; 很好,或者你想创建一个Type 的列表,通过某种编译时间将其限制为你自己的类型检查?
  • @maccettura 这是我的第一个想法,但他们似乎想要一个List&lt;Type&gt;
  • @CamiloTerevinto 哦,我看错了。

标签: c# reflection collections


【解决方案1】:

我需要这个,以便当我创建类型的实例时,编译器会知道该类型实现了 IInterface。

下面我将向您展示两种可能的方法来获取实现IInterface 的那些类的type 列表。所以在创建新对象时,你可以使用这个列表来决定这个类是否实现了IInterfce

  • 编译时解决方案

如果你想要一个编译时解决方案,你应该有一个 List&lt;IInterface&gt; ,那么这个列表中只允许那些实现 IInterface 的类的对象。有了这个列表(只有那些实现IInterface 的类的对象后,使用这个列表来准备类型的列表。

例如。

Demo 类实现了 IInterfaceDemo2 没有。

    List<IInterface> listOfIInterface = new List<IInterface>();
    listOfIInterface.Add(new Demo());
    listOfIInterface.Add(new Demo2()); //this line will have compile time error

现在使用这个列表来准备类型的列表

    List<Type> listOfIInterfaceType = new List<Type>();
    foreach(object obj in listOfIInterface)
    {
        listOfIInterfaceType.Add(obj.GetType());
    }
  • 运行时解决方案

如果您想为您的问题提供更多动态和运行时的解决方案,请试试这个。

如果有多个类并且您想知道哪个类实现了IInterface 并将这些类的类型选择到一个列表中。你可以试试下面的代码。

假设有两个类DemoDemo2Demo 确实实现了 IInterfaceDemo2 没有。

当你拥有两个类的对象时,你将它们放入Object 的列表中并在该列表上循环并执行以下逻辑。

    List<object> listOfObject = new List<object>();
    listOfObject.Add(new Demo()); //Demo Implements IInterface
    listOfObject.Add(new Demo2());//Demo2 doesn't Implement IInterface

    //this will have all possible types
    List<Type> listOfAllType = new List<Type>();
    //this will have type of those class, which implement interface
    List<Type> listOfInterfaceType = new List<Type>();
    //this will have objet of those class, which implement interface.
    List<object> listOfInterfaceObject = new List<object>();

    foreach (object obj in listOfObject)
    {
        Type type = obj.GetType();
        if (!listOfAllType.Contains(type))
            listOfAllType.Add(obj.GetType());

        IInterface testInstance = obj as IInterface;
        if (testInstance != null)
        {
            if (!listOfInterfaceType.Contains(type))
                listOfInterfaceType.Add(type);
            if (!listOfInterfaceObject.Contains(obj))
                listOfInterfaceObject.Add(obj);
        }
    }

请注意,如果任何类没有实现接口,则它的对象不能转换为接口。因此,如果testInstance 在尝试转换后仍然为空,则它的类没有实现接口。

【讨论】:

  • 如果你使用 obj as IInterface 并检查 null ,则不需要 try-catch
  • @CamiloTerevinto 谢谢.. 我已经相应地更新了代码
【解决方案2】:

如果您基本上想要一个List&lt;Type&gt;,其中需要Types 来实现一个接口,并且您希望在编译时强制执行,这实际上可以通过包装List&lt;Type&gt; 并使add 方法具有受约束的泛型类型参数并使用它来添加到列表中,但使用起来可能有点笨拙(您将无法使用您在问题中提到的漂亮的集合初始值设定项语法):

public class TypeList<T> : IEnumerable<Type>
{
    private List<Type> _list = new List<Type>();

    public void Add<TAdd>() where TAdd : T
    {
        _list.Add(typeof(TAdd));
    }

    public IEnumerator<Type> GetEnumerator() => _list.GetEnumerator();

    IEnumerator IEnumerable.GetEnumerator() => _list.GetEnumerator();
}

此类的泛型类型参数是您希望列表约束的类型,因此在您的示例中,使用列表如下所示:

var list = new TypeList<IInterface>();
list.Add<MyClass>();
list.Add<MyClass2>();
list.Add<MyClass3>();

这些将无法编译:

list.Add<string>();
list.Add<bool>();
list.Add<int>();
list.Add<float>();

【讨论】:

  • 我在想我最终不得不创建自己的班级来做到这一点,但是,是的,这行得通
【解决方案3】:

您只是在List&lt;Type&gt; 之后,以TypeOf(myClass), TypeOf(myClass2)... 作为值。如果您想实际验证这些类型是否实现了IInterface,则必须进行额外检查。您不能在编译时指定类型应该只是实现您的接口的类型。

除了这听起来像是依赖注入的先决条件外,如果是这种情况,您可能希望采用 Microsoft 的 Unity 依赖注入框架。

【讨论】:

    猜你喜欢
    • 2010-12-09
    • 1970-01-01
    • 2018-10-16
    • 2017-01-10
    • 2014-12-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多