views:

697

answers:

5

I have code:

public delegate int SomeDelegate(int p);

public static int Inc(int p) {
    return p + 1;
}

I can cast Inc to SomeDelegate or Func<int, int>:

SomeDelegate a = Inc;
Func<int, int> b = Inc;

but I can't cast Inc to SomeDelegate and after that cast to Func<int, int> with usual way like this:

Func<int, int> c = (Func<int, int>)a; // Сompilation error

How I can do it?

+6  A: 

Try this:

Func<int, int> c = (Func<int, int>)Delegate.CreateDelegate(typeof(Func<int, int>), 
                                                           b.Target,
                                                           b.Method);
Diego Mijelshon
Have a look at my answer for an easier way to achieve this.
Winston Smith
+6  A: 

The problem is that:

SomeDelegate a = Inc;

Isn't actually a cast. It's the short-form of:

SomeDelegate a = new SomeDelegate(Inc);

Therefore there's no cast. A simple solution to your problem can be this (in C# 3.0)

Func<int,int> f = i=>a(i);
Gamlor
The problem with that is that you're actually wrapping the delegate with a new one that uses an anonymous method, which has a cost.
Diego Mijelshon
Yeah, you're right. Elegant Code vs. Performance. Depends on you're need what you pick.
Gamlor
+11  A: 
SomeDelegate a = Inc;
Func<int, int> b = Inc;

is short for

SomeDelegate a = new SomeDelegate(Inc); // no cast here
Func<int, int> b = new Func<int, int>(Inc);

You can't cast an instance of SomeDelegate to a Func<int, int> for the same reason you can't cast a string to a Dictionary<int, int> -- they're different types.

This works:

Func<int, int> c = x => a(x);

which is syntactic sugar for

class MyLambda
{
   SomeDelegate a;
   public Foo(SomeDelegate a) { this.a = a; }
   public int Invoke(int x) { return this.a(x); }
}

Func<int, int> c = new Func<int, int>(new MyLambda(a).Invoke);
dtb
Maybe emphasize the fact the custom stuff you wrote is normally done by compiler magic.
Dykam
+1 for the nice explanation. There is a simpler way than *Func<int, int> c = x => a(x);* though - see my answer.
Winston Smith
+2  A: 

It is the same kind of problem as this:

public delegate int SomeDelegate1(int p);
public delegate int SomeDelegate2(int p);
...
  SomeDelegate1 a = new SomeDelegate1(Inc);
  SomeDelegate2 b = (SomeDelegate2)a;  // CS0030

which is the same kind of problem as:

public class A { int prop { get; set; } }
public class B { int prop { get; set; } }
...
  A obja = new A();
  B objb = (A)obja;  // CS0029

Objects cannot be casted from one type to an unrelated other type, even though the types are otherwise completely compatible. For lack of a better term: an object has type identity that it carries along at runtime. That identity cannot be changed after the object is created. The visible manifestation of this identity is Object.GetType().

Hans Passant
+8  A: 

There's a much simpler way to do it, which all the other answers have missed:

Func<int, int> c = a.Invoke;

See this blog post for more info.

Winston Smith
Nice. It's similar to Gamlor's solution, but without the anonymous method.Still, it's wrapping the original delegate, unlike my proposed solution.
Diego Mijelshon