J'ai le code:
public delegate int SomeDelegate(int p);
public static int Inc(int p) {
return p + 1;
}
Je peux transtyper Inc
en SomeDelegate
ou Func<int, int>
:
SomeDelegate a = Inc;
Func<int, int> b = Inc;
mais je ne peux pas transtyper Inc
en SomeDelegate
et après cette distribution en Func<int, int>
avec la méthode habituelle, comme ceci:
Func<int, int> c = (Func<int, int>)a; // Сompilation error
Comment je peux le faire?
SomeDelegate a = Inc;
Func<int, int> b = Inc;
est l'abréviation de
SomeDelegate a = new SomeDelegate(Inc); // no cast here
Func<int, int> b = new Func<int, int>(Inc);
Vous ne pouvez pas convertir une instance de SomeDelegate en Func <int, int> pour la même raison que vous ne pouvez pas convertir une chaîne en dictionnaire <int, int> - ils sont de types différents.
Cela marche:
Func<int, int> c = x => a(x);
qui est le sucre syntaxique pour
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);
Il existe un moyen beaucoup plus simple de le faire, ce que toutes les autres réponses ont manqué:
Func<int, int> c = a.Invoke;
Voir cet article de blog pour plus d'informations.
Essaye ça:
Func<int, int> c = (Func<int, int>)Delegate.CreateDelegate(typeof(Func<int, int>),
b.Target,
b.Method);
Le problème est que:
SomeDelegate a = Inc;
N'est pas réellement un casting. C'est la forme abrégée de:
SomeDelegate a = new SomeDelegate(Inc);
Par conséquent, il n'y a pas de casting. Voici une solution simple à votre problème (en C # 3.0)
Func<int,int> f = i=>a(i);
Cela fonctionne (en C # 4.0 au moins - non essayé dans les versions précédentes):
SomeDelegate a = Inc;
Func<int, int> c = new Func<int, int>(a);
Si vous regardez l'IL, cela compile exactement le même code que la réponse de Winston. Voici l'IL pour la deuxième ligne de ce que je viens d'écrire:
ldloc.0
ldftn instance int32 ConsoleApplication1.Program/SomeDelegate::Invoke(int32)
newobj instance void class [mscorlib]System.Func`2<int32,int32>::.ctor(object, native int)
Et c’est aussi précisément ce que vous voyez si vous affectez a.Invoke
à c
.
Incidemment, bien que la solution de Diego soit plus efficace, en ce sens que le délégué résultant fait directement référence à la méthode sous-jacente plutôt que de passer par l’autre délégué, elle ne gère pas correctement les délégués de multidiffusion. La solution de Winston le fait, car elle s’en remet complètement à l’autre délégué. Si vous souhaitez une solution directe prenant également en charge les délégués ayant plusieurs cibles, vous avez besoin de quelque chose d'un peu plus complexe:
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;
}
Soit dit en passant, cela convient parfaitement aux délégués ayant une cible unique: il ne finira par produire qu’un seul délégué du type cible qui fait directement référence à la méthode (et éventuellement à l’objet) du délégué en entrée auquel il est fait référence.
C'est le même genre de problème que celui-ci:
public delegate int SomeDelegate1(int p);
public delegate int SomeDelegate2(int p);
...
SomeDelegate1 a = new SomeDelegate1(Inc);
SomeDelegate2 b = (SomeDelegate2)a; // CS0030
qui est le même genre de problème que:
public class A { int prop { get; set; } }
public class B { int prop { get; set; } }
...
A obja = new A();
B objb = (B)obja; // CS0029
Les objets ne peuvent pas être convertis d'un type à un autre type sans lien, même si les types sont par ailleurs parfaitement compatibles. En l'absence d'un meilleur terme: un objet a une identité de type qu'il porte lors de l'exécution. Cette identité ne peut pas être modifiée après la création de l'objet. La manifestation visible de cette identité est Object.GetType ().
Vous pouvez pirater une distribution en utilisant une astuce dans laquelle vous utilisez l'équivalent c # d'une union c ++. La partie délicate est la structure avec deux membres qui ont un [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);
}
}
J'aime les exemples. Voici mon exemple de code:
class Program
{
class A
{
public A(D d) { d.Invoke("I'm A!"); }
public delegate string D(string s);
}
class B
{
public delegate string D(string s);
}
static void Main(string[] args)
{
//1. Func to delegates
string F(dynamic s) { Console.WriteLine(s); return s; }
Func<string, string> f = F;
//new A(f);//Error CS1503 Argument 1: cannot convert from 'System.Func<string, string>' to 'ConsoleApp3.Program.A.D'
new A(new A.D(f));//I'm A!
new A(x=>f(x));//I'm A!
Func<string, string> f2 = s => { Console.WriteLine(s); return s; };
//new A(f2);//Same as A(f)
new A(new A.D(f2));//I'm A!
new A(x => f2(x));//I'm A!
//You can even convert between delegate types
new A(new A.D(new B.D(f)));//I'm A!
//2. delegate to F
A.D d = s => { Console.WriteLine(s); return s; };
Func<string, string> f3 = d.Invoke;
f3("I'm f3!");//I'm f3!
Func<string, string> f4 = new Func<string, string>(d);
f4("I'm f4!");//I'm f4!
Console.ReadLine();
}
}
La sortie est: