私はコードを持っています:
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
どうすればできますか?
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);
文字列をDictionary <int、int>にキャストできないのと同じ理由で、SomeDelegateのインスタンスをFunc <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);
これを試して:
Func<int, int> c = (Func<int, int>)Delegate.CreateDelegate(typeof(Func<int, int>),
b.Target,
b.Method);
問題はそれです:
SomeDelegate a = Inc;
実際にはキャストではありません。これは以下の短縮形です。
SomeDelegate a = new SomeDelegate(Inc);
したがって、キャストはありません。あなたの問題の簡単な解決策はこれです(C#3.0の場合)
Func<int,int> f = i=>a(i);
これは機能します(少なくともC#4.0では-以前のバージョンでは試されていません):
SomeDelegate a = Inc;
Func<int, int> c = new Func<int, int>(a);
ILを見ると、これはWinstonの回答とまったく同じコードにコンパイルされます。これが、私が書いたばかりの2行目の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
に割り当てた場合にも正確に表示されます。
ちなみに、Diegoのソリューションはより効率的ですが、結果のデリゲートは他のデリゲートを経由するのではなく、基になるメソッドを直接参照するため、マルチキャストデリゲートは正しく処理されません。ウィンストンのソリューションは、他のデリゲートに完全に委ねるだけなので、そうします。複数のターゲットを持つデリゲートも処理する直接的なソリューションが必要な場合は、もう少し複雑なものが必要です。
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;
}
これは、単一のターゲットを持つデリゲートにとって正しいことです。つまり、入力デリゲートが参照したメソッド(および該当する場合はオブジェクト)を直接参照するターゲットタイプの単一のデリゲートを生成することになります。
キャストをハックするには、c ++の共用体に相当するc#を使用するトリックを使用します。トリッキーな部分は、[FieldOffset(0)]を持つ2つのメンバーを持つ構造体です。
[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);
}
}
これは同じ種類の問題です:
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
型が完全に互換性がある場合でも、オブジェクトをある型から無関係な他の型にキャストすることはできません。より適切な用語がないため、オブジェクトには実行時に保持される型IDがあります。オブジェクトの作成後は、そのIDを変更できません。このアイデンティティの目に見える形はObject.GetType()です。
私は例が好きです。これが私のコード例です:
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();
}
}
出力は次のとおりです。