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> WorldO开发者_StackOverflow社区bjects = 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?
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.
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.
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);
}
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.
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>();
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
精彩评论