(Using .NET 4.0)
Ok, so I have
private Dictionary<int, Action<IMyInterface, IMyInterface>> handler {get; set;}
public void Foo<T, U>(Action<T, U> myAction)
where T : IMyInterface
where U : IMyInterface
{
// | This line Fails
// V
Action<IMyInterface, IMyInterface> anotherAction = myAction;
handler.Add(someInt, anotherAction);
}
I'm trying to store the delegate in a generic collection, so I can pull it back out later to invoke it.
How do I properly cast it?
The generic parameters to the Action delegate are type-contravariant; they are not type covariant. As a result, you can pass in a less specific type, but not a more specific type.
So this compiles:
protected void X()
{
Action<string> A = Foo;
}
void Foo(object s) { }
But this doesn't:
protected void X()
{
Action<object> A = Foo;
}
void Foo(string s) { }
Since T and U : IMyInterface
, your code is analogous to the first example.
The intellisense explains it rather clearly: (here's a bigger version)
Welp... looks like me and my friend found a bit of a work around.
public void Foo<T, U>(Action<T, U> myAction)
where T : IMyInterface
where U : IMyInterface
{
Action<IMyInterface, IMyInterface> anotherAction = (x, y) => eventHandler.Invoke((TSender)x, (TObject),y);
handler.Add(someInt, anotherAction);
}
With a simple lambda wrap, we accomplished what we needed.
I don't think there is a type safe way of doing what you're trying to accomplish. Using the example in your updated question:
private Dictionary<int, Action<IMyInterface, IMyInterface>> handler {get; set;}
public void Foo<T, U>(Action<T, U> myAction)
where T : IMyInterface
where U : IMyInterface
{
Action<IMyInterface, IMyInterface> anotherAction = (x, y) => myAction.Invoke((T)x, (U)y);
handler.Add(someInt, anotherAction);
}
Assuming IMyInterface and MyImplementation are defined as follows:
interface IMyInterface
{
void bar();
}
class MyImplementation : IMyInterface
{
void IMyInterface.bar()
{
//Snip: Do the things
}
void nope()
{
//Snip: Do other things
}
}
class MySimplerImplementation : IMyInterface
{
void IMyInterface.bar()
{
//Snip: Do things
}
}
We could find ourselves in the following situation:
void test()
{
//Create an action with a method that only MyImplementation implements
Action<MyImplementation, MyImplementation> forMyImplementationOnly =
(x, y) => x.nope();
//Use Foo (defined in the example code above) to 'cast' this
//action and add it to the handler dictionary
Foo<MyImplementation, Myimplementation>(forMyImplementationOnly);
//Retrieve the action from the handler dictionary
Action<IMyInterface, IMyInterface> castedAction = handler[someInt];
//Try running the action using MySimplerImplementation
castedAction(new MySimplerImplementation(), new MySimplerImplementation());
//This code will fail because MySimplerImplementation
//can not be cast to MyImplementation. It does not even
//define the nope() method that your initial Action required
}
It's for this reason that the Action generic is contravariant (you can use less specific types, but not more specific types).