Это работает (по крайней мере, в C # 4.0 - не пробовал в более ранних версиях):
SomeDelegate a = Inc;
Func<int, int> c = new Func<int, int>(a);
Если вы посмотрите на IL, это скомпилирует точно такой же код, что и ответ Уинстона. Вот 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
.
Между прочим, хотя решение Диего является более эффективным, в результате получающийся делегат ссылается непосредственно на базовый метод, а не проходит через другой делегат, он не обрабатывает многоадресные делегаты правильно. Решение Уинстона делает, потому что оно просто полностью подчиняется другому делегату. Если вам нужно прямое решение, которое также обрабатывает делегатов с несколькими целями, вам нужно нечто более сложное:
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;
}
Кстати, это правильно для делегатов с единственной целью - в итоге будет получен только один делегат целевого типа, который напрямую ссылается на любой метод (и, где это применимо, объект), на который ссылался входной делегат.