Подтвердить что ты не робот

Сохранение списка разных типов в классе

Структура класса

Я прикрепил фотографию того, что я пытаюсь сделать. Скажем, у меня есть список T в классе

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

Теперь у другого класса есть список MyClass.

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

Что такое T, который я должен поставить для MyClass? Если я положил T, то он предполагает, что все типы в этом классе одинаковы, но это не так. Если я поместил IMyInterface, я не смог бы передать IMyInterface в T при доступе к этим классам.

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

Каков тип здесь прямо сейчас? Список в родовом типе AnotherClass - IMyInterface, но вещь, которую я хочу добавить, - это T, и я хочу быть динамичной, но они все еще находятся под IMyInterface.

4b9b3361

Ответ 1

T в общем случае должен быть одним и тем же за всю свою жизнь.

для примера

var a = new MyClass<int>();
a.list.Add(1); //since a 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

Итак, когда вы это делаете.

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

Единственное, что вы знаете о содержимом, это то, что теперь он реализует 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
}

Вот пример, который я сделал в 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 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 methods and not only the Interfaces
            Console.WriteLine("Bar");
        }
    }
}

Ответ 2

Я думаю, ваша проблема в том, что вам не нужно использовать для этого дженерики. Если вы укажете свой класс как:

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

Затем вы можете добавить к этому любой экземпляр любого класса, реализующего интерфейс.

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);
    }
}

Затем вы можете получить доступ ко всем элементам из списка как 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;
}

Или вы можете просто попробовать кастинг и проверить, не null:

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

Ответ 3

Я думаю, вы имеете в виду, что хотите иметь несколько общих типов в одном списке, например:

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

Простой способ сделать это - определить ваш список как список объектов:

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

Проблема здесь в том, что вы можете использовать все, что вам нравится в этом списке, а не только ваш общий класс. Возможно также следующее:

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

Единственный способ ограничить то, что вы можете добавить, - использовать абстрактный базовый класс.

public class MyClassBase 
{

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

И затем список:

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

Вам все равно придется выполнять некоторые проверки типов при обращении к этим объектам, но по крайней мере вы узнаете, что объекты ограничены теми, кто наследует MyClassBase

Ответ 4

Использование ковариант?

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>());
    }
}