How am I able to create A List<T> containing an open generic Interface?

爷,独闯天下 提交于 2019-12-12 16:36:07

问题


I have a List which must contain IInteract Objects. But IInteract is a generic interface which requires 2 type arguments.

My main idea is iterate through a list of Objects and "Interact" one with another if they didn't interact yet. So i have this object

List<IObject> WorldObjects = new List<IObject>();

and this one:

private List<IInteract> = new List<IInteract>();

Except I can't compile the last line because IInteract requires 2 type arguments. But I don't know what the arguments are until I add them. I could add interactions between Objects of Type A and A... or Objects of Type B and C.

I want to create "Interaction" classes which do something with the "acting" object and the "target" object, but I want them to be independent from the objects... so I could add an Interaction between for instance... "SuperUltraClass" and... an "integer".

Am I using the wrong approach?


回答1:


Assuming IInteract is defined as something like

interface IInteract<T1, T2>

and you are using it for a field of a class Foo:

class Foo
{
  List<IInteract...> field;
}

Then if you want to defer the decision of what types to bind to the IInteract type arguements you need to parameterize the container class:

class Foo<T1, T2>
{
   List<IInteract<T1, T2>> field;
}

The type arguments to IInteract here will be bound when you define a concrete instantiation of the container class, like: var x = new Foo<int, double>(). This will cause the IInteract field to be of type IInteract<int, double> for that particular instantiation of the Foo generic type.




回答2:


I think an interface hierarchy might make things easier. The top-level could be a non-generic interface with just the methods that you need to invoke, absent any type information. The second level would be those that required some typing...of course, it may be enough to simply have the implementing class instead of the second level interface.

public interface IInteract
{
    void Interact();
}

public interface IInteract<TActor,TTarget> : IInteract
{
    TActor Actor { get; set; }
    TTarget Target { get; set; }
}

Then you can create your list of IInteract objects and it can contain any of the strongly typed IInteract<TActor,TTarget> objects, though only those methods on the non-generic interface will be available. The important thing will be the concrete implementations -- that is what will determine what code gets executed anyway.




回答3:


I think you should use an inversion of control container (I've used Castle Windsor in the past). Then you can do something like this:

void Interact<TA, TB>(TA objectA, TB objectB)
{
    var interact = Container.Resolve<IInteract<TA, TB>>();
    interact.Interact(objectA, objectB);
}



回答4:


you can do this:

private List<IInteract<SomeType, SomeOtherType>> = new List<IInteract<SomeType, SomeOtherType>>();

But like you said you don't know what types you're adding. So here are a couple of options:

1: Use object (or even dynamic) types:

private List<IInteract<object, object>> ...

2: Use generics in your class:

class Foo<T1, T2> {
    private List<IInteract<T1, T2>> ...
}

...

Foo<string, int> bar = new Foo<string, int>();

In the second example you are locked into adding only strings and ints (or whatever you create the Foo object to be) to your list. In the first example you can mix and match, but you would have to do runtime type checking to figure out what you're pulling out of the list.




回答5:


I'm not sure I completely understand what you're trying to accomplish. What you need to do is create a concrete class which implements your interface, and then use that in your List<>. Like so:

public interface IInteract
{
   Type A { get; set; }
   Type B { get; set; }
}


public class Interact : IInteract
{
    public Type A
    {
        get { return a; }
    }

    public Type B
    {
        get { return b; }
    }

}

And then use your concrete class in your list:

private List<Interact> = new List<Interact>();  



回答6:


You might be better off using a dictionary, where the key is a tuple of the two types that you are interacting, and the values are Interact, so each Interact implementation would have to do some casting

private Dictionary<Tuple<Type, Type>, IInteract<Object, Object>> interactions = new Dictionary<Tuple<Type, Type>, IInteract<Object, Object>>();

It's a bit messy but then you can add to it:

IInteract<Object, Object> superClassIntInteraction = someInteractionClass;
interactions.Add(new Tuple<Type, Type>(typeof(SuperClass),typeof(int)), superClassIntInteraction);

I'm assuming that you want to be able to search the list/dictionary to be able to find a specific interaction later on, which is where the dictionary comes in handy



来源:https://stackoverflow.com/questions/4521587/how-am-i-able-to-create-a-listt-containing-an-open-generic-interface

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!