简体   繁体   中英

Add an object to a collection without knowing its generic type

class Program
{
    public static void Main(string[] args)
    {
        List<MyInterface> myList = new List<MyInterface>();

        myList.Add(new MyClass<int>());

        foreach (MyInterface item in myList)
        {
            (MyClass)item).Foo(); // <---- Critical Line
        }
    }
}

interface MyInterface { }

class MyClass<T> : MyInterface
{
    public MyClass() { }
    public void Foo() { DoSomething(); }
}

I want to use the Foo() method of MyClass without knowing the excact (generic) Type of the object. Is there a way to call it anyway? I will know T when the code is compiled, so could I perhaps store it in a property that is implemeted via InterfaceB ?

Thanks for your help!

Edit: Sorry for not being clear; There are other classes that implement MyInterface and I am checking wether the type of item is ClassB, so I can't put Foo() into MyInterface .

In order to statically refer to ClassB<T> you will need to specify the generic parameter in your code. You can't use the name ClassB because that will refer to a non-generic class named ClassB .

The other way to make this work is to add the information you need onto InterfaceB as it doesn't need a generic parameter

interface InterfaceB 
{
  InterfaceA FooUntyped();
}

...

foreach (InterfaceB item in bList) {
  aList.Add(item.FooUntyped());
}
interface MyInterface { }
interface MyFooInterface<T>
{
    List<T> Foo<T>();
}

class MyClass<T> : MyInterface, MyFooInterface<T>
{
    public MyClass() { }
    public List<T> Foo<T>() { DoSomething(); }
}

class MyClassB<T> : MyInfterface
{...}

...
        foreach (MyFooInterface item in myList.OfType<MyFooInterface>)
        {
            item.Foo();
        }
...

The key insight is that MyClass<int> and MyClass<SomethingElse> are 100% unrelated types so you cannot treat them the same. Not even partially. It is as if you wrote T1 and T2 to the compiler.

So you have to create a common base class/interface or use dynamic .

You're not iterating over items of ClassB, but instead interfaceB which doesn't actually specify a Foo method.

Without checking however:

var itemB = item as ClassB; if (itemB != null){ itemB.Foo() }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM