在类中存储不同泛型类型的列表

时间:2022-04-04 13:17:13

在类中存储不同泛型类型的列表

I've attached a picture of what I'm trying to do. Let's say I have a list of T in a class

我附上了我正在尝试做的事情。假设我在课堂上有一个T列表

public class MyClass<T> 
    where T : IMyInterface
{
    public List<T> list = new List<T>;
}

Now, another class has a list of MyClass.

现在,另一个类有一个MyClass列表。

public class AnotherClass
{
    public List<MyClass<IMyInterface>> list = new List<MyClass<IMyInterface>>;
}

What is the T that I should put for MyClass? If I put T, then it assumes all types in that class are the same, but it isn't. If I put IMyInterface, I couldn't cast IMyInterface to T when accessing these classes.

我应该为MyClass提供什么?如果我把T,那么它假定该类中的所有类型都相同,但事实并非如此。如果我放入IMyInterface,我在访问这些类时无法将IMyInterface强制转换为T.

new AnotherClass().list.Add(new MyClass<T>()); 

What is the type here right now? The list in AnotherClass generic type is IMyInterface but the thing I want to add in is T, which T I want to be dynamic but they are still under IMyInterface.

现在这里的类型是什么? AnotherClass泛型类型中的列表是IMyInterface,但我要添加的内容是T,我希望T是动态的,但它们仍然在IMyInterface下。

4 个解决方案

#1


6  

The T in a generic must be the same through out its lifetime.

通用中的T在其生命周期内必须相同。

for an example

举个例子

var a = new MyClass<int>();
a.list.Add(1); //since a's generic T is declared as int the list is now also int

var b = new MyClass<string>()
b.list.Add("string"); //in b its now declared as a string and avccepts only string

So when you are doing this.

所以当你这样做的时候。

var c = new MyClass<IMyInterface>();
c.list.Add(ObjectImplementingIMyInterface); //You must add something that implements IMyInterface

The only thing you know about the content is that it implements IMyInterface now if you want to split the execution of the object then you must check the type of the object via reflection.

您对内容的唯一了解是它现在实现IMyInterface如果您想要拆分对象的执行,那么您必须通过反射检查对象的类型。

if(c.list[i].GetType() == typeof(ClassA_IMyInterface)
{
    //Execute on ClassA_IMyInterface
    //If you are after the ClassA 
    //and want to run something speciffic for it the cast
    ClassA clA = = (ClassA)c.list[i];
    //Now you have access to the implementation of ClassA instead of just the interface 
}
else if (c.list[i].GetType() == typeof(ClassB_IMyInterface)
{
    //Execute on ClassB_IMyInterface
}

Here is an example i made in ConsoleApplication showing how it lays out.

这是我在ConsoleApplication中做的一个示例,展示了它的布局。

public class MyClass<T> where T : IMyInterface
{
    public List<T> list = new List<T>();
}
public interface IMyInterface
{
}
public class Foo : IMyInterface
{
}
public class Bar : IMyInterface
{
}
public class FooBar
{
    public void Test()
    {
        var content = new MyClass<IMyInterface>();
        content.list.Add(new Foo());
        if (content.list[0] is Foo)
        {
            //Execute on Foo 
            var g = (Foo)content.list[0];
            //Now you can access Foo's methods and not only the Interfaces
            Console.WriteLine("Foo");
        }
        else if (content.list[0] is Bar)
        {
            //Execute on Bar
            var g = (Bar)content.list[0];
            //Now you can access Bar's methods and not only the Interfaces
            Console.WriteLine("Bar");
        }
    }
}

#2


5  

I think your issue is that you do not need to use generics for this. If you specify your class as:

我认为您的问题是您不需要使用泛型。如果您将类指定为:

public class MyClass
{
    public IList<IMyInterface> list = new List<IMyImterface>();
}

Then you can add to this any instance of any class implementing the interface.

然后,您可以添加任何实现该接口的类的实例。

public class DummyClass : IMyInterface {}

public class AnotherClass {
{
    IList<MyClass> anotherList = new List<MyClass>();

    public void AMethod()
    {
        MyClass myList = new MyClass();
        myList.Add(new DummyClass());

        anotherList.Add(myList);
    }
}

Then you can access all items from the list as IMyInterface directly, or if you want items of a specific class, you can use LINQ:

然后你可以直接访问列表中的所有项目作为IMyInterface,或者如果你想要特定类的项目,你可以使用LINQ:

foreach (IMyImterface item in myList.Where(x => x is DummyClass))
{
    DummyClass dummy = (DummyClass)item;
}

// or
foreach (IMyImterface item in myList.OfType<DummyClass>())
{
    DummyClass dummy = (DummyClass)item;
}

Or you can just try casting and check if null:

或者您可以尝试转换并检查是否为null:

foreach (IMyIntetface item in myList)
{
    DummyClass dummy = item as DummyClass;
    if (dummy != null)
    {
        // do something
    }
}

#3


3  

I think you mean that you want to have multiple generic types in one list eg:

我想你的意思是你想在一个列表中有多个泛型类型,例如:

var ac = new AnotherClass();
ac.list.Add(new MyClass<int>()); 
ac.list.Add(new MyClass<bool>()); 
ac.list.Add(new MyClass<double>());

A simple way to do this is to define your list as a list of object:

一种简单的方法是将列表定义为对象列表:

public class AnotherClass
{
    public List<object> list = new List<object>();
}

The issue here is you could anything you like to that list, not just your generic class. The following would also be possible:

这里的问题是你可以对列表中的任何内容,而不仅仅是你的泛型类。以下也是可能的:

list.Add(1); 
list.Add("hello"); 

The only way you could restrict what you can add is to use an abstract base class.

限制可以添加的内容的唯一方法是使用抽象基类。

public class MyClassBase 
{

}
public class MyClass<T> : MyClassBase
    where T : IMyInterface
{
    public List<T> list = new List<T>();
}

And then have a list of those:

然后有一个列表:

public class AnotherClass
{
    public List<MyClassBase> list = new List<MyClassBase>();
}

You'll still have to do some type checking when accessing those objects but at least you'll know that the objects are restricted to those inheriting MyClassBase

在访问这些对象时,您仍然需要进行一些类型检查,但至少您会知道对象仅限于那些继承MyClassBase的对象

#4


2  

Using covariant?

使用协变?

public interface IMyInterface { }
public class A : IMyInterface { }
public class B : IMyInterface { }

// Covariant interface
public interface IMyClass<out T> { }

// Inherit IMyClass
public class MyClass<T> : IMyClass<T> where T : IMyInterface 
{ 
    public List<T> list = new List<T>(); 
}

public class AnotherClass
{
    // Note the list using IMyClass instead of the concrete MyClass type
    // The covariant interface type would allow any IMyInterface conversion
    public List<IMyClass<IMyInterface>> list = new List<IMyClass<IMyInterface>>();

    public AnotherClass()
    {
        this.list.Add(new MyClass<A>());
        this.list.Add(new MyClass<B>());
    }
}

#1


6  

The T in a generic must be the same through out its lifetime.

通用中的T在其生命周期内必须相同。

for an example

举个例子

var a = new MyClass<int>();
a.list.Add(1); //since a's generic T is declared as int the list is now also int

var b = new MyClass<string>()
b.list.Add("string"); //in b its now declared as a string and avccepts only string

So when you are doing this.

所以当你这样做的时候。

var c = new MyClass<IMyInterface>();
c.list.Add(ObjectImplementingIMyInterface); //You must add something that implements IMyInterface

The only thing you know about the content is that it implements IMyInterface now if you want to split the execution of the object then you must check the type of the object via reflection.

您对内容的唯一了解是它现在实现IMyInterface如果您想要拆分对象的执行,那么您必须通过反射检查对象的类型。

if(c.list[i].GetType() == typeof(ClassA_IMyInterface)
{
    //Execute on ClassA_IMyInterface
    //If you are after the ClassA 
    //and want to run something speciffic for it the cast
    ClassA clA = = (ClassA)c.list[i];
    //Now you have access to the implementation of ClassA instead of just the interface 
}
else if (c.list[i].GetType() == typeof(ClassB_IMyInterface)
{
    //Execute on ClassB_IMyInterface
}

Here is an example i made in ConsoleApplication showing how it lays out.

这是我在ConsoleApplication中做的一个示例,展示了它的布局。

public class MyClass<T> where T : IMyInterface
{
    public List<T> list = new List<T>();
}
public interface IMyInterface
{
}
public class Foo : IMyInterface
{
}
public class Bar : IMyInterface
{
}
public class FooBar
{
    public void Test()
    {
        var content = new MyClass<IMyInterface>();
        content.list.Add(new Foo());
        if (content.list[0] is Foo)
        {
            //Execute on Foo 
            var g = (Foo)content.list[0];
            //Now you can access Foo's methods and not only the Interfaces
            Console.WriteLine("Foo");
        }
        else if (content.list[0] is Bar)
        {
            //Execute on Bar
            var g = (Bar)content.list[0];
            //Now you can access Bar's methods and not only the Interfaces
            Console.WriteLine("Bar");
        }
    }
}

#2


5  

I think your issue is that you do not need to use generics for this. If you specify your class as:

我认为您的问题是您不需要使用泛型。如果您将类指定为:

public class MyClass
{
    public IList<IMyInterface> list = new List<IMyImterface>();
}

Then you can add to this any instance of any class implementing the interface.

然后,您可以添加任何实现该接口的类的实例。

public class DummyClass : IMyInterface {}

public class AnotherClass {
{
    IList<MyClass> anotherList = new List<MyClass>();

    public void AMethod()
    {
        MyClass myList = new MyClass();
        myList.Add(new DummyClass());

        anotherList.Add(myList);
    }
}

Then you can access all items from the list as IMyInterface directly, or if you want items of a specific class, you can use LINQ:

然后你可以直接访问列表中的所有项目作为IMyInterface,或者如果你想要特定类的项目,你可以使用LINQ:

foreach (IMyImterface item in myList.Where(x => x is DummyClass))
{
    DummyClass dummy = (DummyClass)item;
}

// or
foreach (IMyImterface item in myList.OfType<DummyClass>())
{
    DummyClass dummy = (DummyClass)item;
}

Or you can just try casting and check if null:

或者您可以尝试转换并检查是否为null:

foreach (IMyIntetface item in myList)
{
    DummyClass dummy = item as DummyClass;
    if (dummy != null)
    {
        // do something
    }
}

#3


3  

I think you mean that you want to have multiple generic types in one list eg:

我想你的意思是你想在一个列表中有多个泛型类型,例如:

var ac = new AnotherClass();
ac.list.Add(new MyClass<int>()); 
ac.list.Add(new MyClass<bool>()); 
ac.list.Add(new MyClass<double>());

A simple way to do this is to define your list as a list of object:

一种简单的方法是将列表定义为对象列表:

public class AnotherClass
{
    public List<object> list = new List<object>();
}

The issue here is you could anything you like to that list, not just your generic class. The following would also be possible:

这里的问题是你可以对列表中的任何内容,而不仅仅是你的泛型类。以下也是可能的:

list.Add(1); 
list.Add("hello"); 

The only way you could restrict what you can add is to use an abstract base class.

限制可以添加的内容的唯一方法是使用抽象基类。

public class MyClassBase 
{

}
public class MyClass<T> : MyClassBase
    where T : IMyInterface
{
    public List<T> list = new List<T>();
}

And then have a list of those:

然后有一个列表:

public class AnotherClass
{
    public List<MyClassBase> list = new List<MyClassBase>();
}

You'll still have to do some type checking when accessing those objects but at least you'll know that the objects are restricted to those inheriting MyClassBase

在访问这些对象时,您仍然需要进行一些类型检查,但至少您会知道对象仅限于那些继承MyClassBase的对象

#4


2  

Using covariant?

使用协变?

public interface IMyInterface { }
public class A : IMyInterface { }
public class B : IMyInterface { }

// Covariant interface
public interface IMyClass<out T> { }

// Inherit IMyClass
public class MyClass<T> : IMyClass<T> where T : IMyInterface 
{ 
    public List<T> list = new List<T>(); 
}

public class AnotherClass
{
    // Note the list using IMyClass instead of the concrete MyClass type
    // The covariant interface type would allow any IMyInterface conversion
    public List<IMyClass<IMyInterface>> list = new List<IMyClass<IMyInterface>>();

    public AnotherClass()
    {
        this.list.Add(new MyClass<A>());
        this.list.Add(new MyClass<B>());
    }
}