6

Consider the code:

public interface IGeneral {}
public interface ISpecific : IGeneral {}
public Func<IGeneral, String> Cast(Object specificFuncAsObject) {
      var generalFunc = specificFuncAsObject as Func<IGeneral, String>;
      Assert.IsNotNull(generalFunc); // <--- casting didn't work
      return generalFunc;
}

Func<ISpecific, String> specificFunc = specific => "Hey!";
var generalFunc = Cast(specificFunc);

Is there a way to make such casting work? I know that IGeneral cannot be casted to ISpecific in general case. But in my particular situation I wish I could do something like this:

 Func<IGeneral, String> generalFunc = new Func<IGeneral, String>(general => specificFunc(general as ISpecific));

But having the specificFunc as Object and having ISpecific type only via specificFuncAsObject.GetType()

Trident D'Gao
  • 18,973
  • 19
  • 95
  • 159
  • You can create a wrapping lambda method, but if I'm reading this right at first glance I think you'll have to cast: `generalFunc = general => specificFunc((ISpecific)general);` Otherwise as a `Func` you could pass in some `IOtherSpecific` and things will fall apart because `specificFunc` wanted an `ISpecific`, _not_ an `IGeneral` or `IOtherSpecific`. – Chris Sinclair Sep 18 '13 at 19:09

2 Answers2

9

T (the input type) in Func<T, TResult> is contravariant, not covariant, so such a thing is not directly possible. You can, however, do the following:

Func<ISpecific, String> specificFunc = specific => "Hey!";
Func<IGeneral, String> generalFunc = general => specificFunc((ISpecific)general);

Or the reverse:

Func<IGeneral, String> generalFunc = general => "Hey!";
Func<ISpecific, String> specificFunc = generalFunc;
Tim S.
  • 55,448
  • 7
  • 96
  • 122
4

I believe this is impossible, think of the following case:

class Base
{
}

class DerivedA : Base
{
}

class DerivedB : Base
{
}

With the some methods:

string DoSomething(DerivedA myDerived)
{
}

Then, somewhere you have code:

Func<DerivedA, string> functionA = DoSomething;
// Let's assume this cast is possible...
Func<Base, string> functionBase = (Func<BaseB, string>) functionA;

// At this point, the signature of the function that functionBase is assigned to
// is actually `string DoSomething(DerivedA myDerived)`
functionB(new DerivedB());
// If the cast is allowed, then passing a DerivedB should be allowed, but this makes
// absolutely no sense because the function is expecting a DerivedA.

What you can do is use a utility function to convert with a cast (or as operator if you wish):

Func<Base, string> Convert<T>(Func<T, string> function) where T : Base
{
return x => function(x as T);
}

And then do something like:

Func<DerivedA, string> functionA = DoSomething;
Func<Base, string> functionBase = Convert(functionA);
Anthony
  • 9,451
  • 9
  • 45
  • 72