Сохранение списка разных типов в классе
![Структура класса]()
Я прикрепил фотографию того, что я пытаюсь сделать. Скажем, у меня есть список 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.
Ответы
Ответ 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>());
}
}