Передача делегата Func в С#
У меня есть код:
public delegate int SomeDelegate(int p);
public static int Inc(int p) {
return p + 1;
}
Я могу использовать Inc
для SomeDelegate
или Func<int, int>
:
SomeDelegate a = Inc;
Func<int, int> b = Inc;
но я не могу отбрасывать Inc
в SomeDelegate
и после этого применять к Func<int, int>
обычным способом:
Func<int, int> c = (Func<int, int>)a; // Сompilation error
Как я могу это сделать?
Ответы
Ответ 1
SomeDelegate a = Inc;
Func<int, int> b = Inc;
не подходит для
SomeDelegate a = new SomeDelegate(Inc); // no cast here
Func<int, int> b = new Func<int, int>(Inc);
Вы не можете передать экземпляр SomeDelegate в Func < int, int > по той же причине вы не можете передать строку в словарь < int, int > - они разные.
Это работает:
Func<int, int> c = x => a(x);
который является синтаксическим сахаром для
class MyLambda
{
SomeDelegate a;
public MyLambda(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);
Ответ 2
Там гораздо более простой способ сделать это, о чем пропустили все остальные ответы:
Func<int, int> c = a.Invoke;
Смотрите этот пост в блоге для получения дополнительной информации.
Ответ 3
Попробуйте следующее:
Func<int, int> c = (Func<int, int>)Delegate.CreateDelegate(typeof(Func<int, int>),
b.Target,
b.Method);
Ответ 4
Проблема в том, что:
SomeDelegate a = Inc;
На самом деле это не актерский состав. Это короткая форма:
SomeDelegate a = new SomeDelegate(Inc);
Поэтому нет броска. Простым решением вашей проблемы может быть это (в С# 3.0)
Func<int,int> f = i=>a(i);
Ответ 5
Это работает (по крайней мере, в С# 4.0 - не используется в более ранних версиях):
SomeDelegate a = Inc;
Func<int, int> c = new Func<int, int>(a);
Если вы посмотрите на IL, это скомпилируется в тот же код, что и Winston. Здесь IL для второй строки того, что я только что написал:
ldloc.0
ldftn instance int32 ConsoleApplication1.Program/SomeDelegate::Invoke(int32)
newobj instance void class [mscorlib]System.Func`2<int32,int32>::.ctor(object, native int)
И это также то, что вы видите, если вы присвойте a.Invoke
в c
.
Кстати, хотя решение Диего более эффективно, поскольку полученный делегат ссылается непосредственно на базовый метод, а не на другой делегат, он не обрабатывает делегатов многоадресной рассылки правильно. Решение Winston делает это, потому что оно просто полностью подчиняется другому делегату. Если вам нужно прямое решение, которое также обрабатывает делегатов с несколькими целями, вам нужно что-то более сложное:
public static TResult DuplicateDelegateAs<TResult>(MulticastDelegate source)
{
Delegate result = null;
foreach (Delegate sourceItem in source.GetInvocationList())
{
var copy = Delegate.CreateDelegate(
typeof(TResult), sourceItem.Target, sourceItem.Method);
result = Delegate.Combine(result, copy);
}
return (TResult) (object) result;
}
Это правильно для делегатов с одной целью, кстати, приведет к созданию только одного делегата целевого типа, который ссылается непосредственно на любой метод (и, где применимо, объект), на который ссылается входной делегат.
Ответ 6
Это та же проблема:
public delegate int SomeDelegate1(int p);
public delegate int SomeDelegate2(int p);
...
SomeDelegate1 a = new SomeDelegate1(Inc);
SomeDelegate2 b = (SomeDelegate2)a; // CS0030
что является такой же проблемой, как:
public class A { int prop { get; set; } }
public class B { int prop { get; set; } }
...
A obja = new A();
B objb = (B)obja; // CS0029
Объекты не могут быть отлиты от одного типа к несвязанному другому типу, хотя типы в противном случае полностью совместимы. Из-за отсутствия лучшего термина: объект имеет идентификатор типа, который он переносит во время выполнения. Эта идентичность не может быть изменена после создания объекта. Видимым проявлением этого тождества является Object.GetType().
Ответ 7
Вы можете взломать бросок, используя трюк, в котором вы используете эквивалент С# для объединения С++. Трудная часть - это структура с двумя членами, которые имеют [FieldOffset (0)]:
[TestFixture]
public class Demo
{
public void print(int i)
{
Console.WriteLine("Int: "+i);
}
private delegate void mydelegate(int i);
[StructLayout(LayoutKind.Explicit)]
struct funky
{
[FieldOffset(0)]
public mydelegate a;
[FieldOffset(0)]
public System.Action<int> b;
}
[Test]
public void delegatetest()
{
System.Action<int> f = print;
funky myfunky;
myfunky.a = null;
myfunky.b = f;
mydelegate a = myfunky.a;
a(5);
}
}