1
class MyClass
{
    public event Action<string> OnAction;
    public event Func<string, int> OnFunc;
}

class Program
{
    static void Main(string[] args)
    {
        MyClass mc = new MyClass();

        /// I need to handle arbitrary events.
        /// But I see no way to create anonymous delegates in runtime
        /// with arbitrary returns and parameters. So I choosed to
        /// create multiple “signatures” with different parameter
        /// number (up to 10) and different returns (either the Action or
        /// Func). While Actions<> work pretty well, the Funcs<> do not.
        Action<dynamic> someAction = delegate(dynamic p1) { };
        Func<dynamic, dynamic> someFunc = delegate(dynamic p1) { return 42;};

        // OK
        mc.OnAction += someAction;

        // Error: “Cannot implicitly convert type 'System.Func<dynamic,dynamic>'
        // to 'System.Func<string,int>'”
        mc.OnFunc += someFunc;

        // It doesn't work this way as well (the same error message):
        // dynamic someFunc = new Func<dynamic, dynamic>((dynamic n1) => { return 42; });

        // Let's try another way
        // 1:
        // Cannot convert anonymous method to delegate type 'System.Func<string,int>'
        // because the parameter types do not match the delegate parameter types.
        // 2 (even more funny):
        // Parameter 1 is declared as type 'dynamic' but should be 'string'.
        mc.OnFunc += delegate(dynamic p1) { return 42; };
    }
}

なぜそれはアクションに対しては機能し、関数に対しては機能しないのですか?言い換えれば、私はただ、なぜ大丈夫なのにAction<dynamic> → Action<string>大丈夫なのかを知りたいのFunc<dynamic,dynamic> → Func<string, int>です。ありがとう。

4

3 に答える 3

1

C# が の戻り値の型を持つデリゲートを期待している場合、返すようにint宣言されたデリゲートdynamicは互換性がありません。デリゲートは として宣言されFunc<dynamic, dynamic>、C# は厳密に型指定されています。関数が実際に int を返し、文字列を取るかどうかは気にしません。としてまだ宣言されていFunc<dynamic, dynamic>ます。

次の例を考えれば、コードがコンパイルされない理由は明らかです。

Func<string, int> myFunc = delegate(string foo) { return 42; };    
int result = myFunc("Foo");

// If this was allowed...
Func<dynamic, dynamic> otherFunc = delegate(string foo) { return 42; };
myFunc = otherFunc;
result = myFunc("Foo");

// Then this would also be allowed but would be a run-time error.
otherFunc = delegate(string foo) { return "Bar"; }; // Valid
myFunc = otherFunc;
result = myFunc("Foo"); // Oops... an int isn't returned.
于 2010-06-20T18:45:20.070 に答える
0

Action と Func の定義の唯一の違いは、Action には戻り値の型がないことです。コードを次のように変更した場合:

mc.OnFunc += new Func<dynamic, dynamic>(someFunc);// += someFunc;

mc.OnFunc += new Func<dynamic, int>(someFunc);// += someFunc;

できます。

于 2010-06-20T12:45:41.180 に答える
0

はい、分かりました。

アクションは次のように定義されます: delegate void Action <in T> (T arg);、func は次のように定義されます:delegate TResult Func <in T, out TResult> (T arg);問題はoutキーワードにあります。これは共分散を示しますが、inキーワードのように反分散を示しません。同時にtypeof(dynamic) == typeof(object)真実です。そのため、より一般的な型としてのdynamicは、私たちが取るものに対して共変ではありません。うーん、動的バインディングの方が柔軟だと思いました。」</p>

さらに読む: http://blogs.msdn.com/b/csharpfaq/archive/2010/02/16/covariance-and-contravariance-faq.aspx

ところで、後で見つけた引用:

メソッドの戻り値の型としてのみ使用され、正式なメソッド パラメーターの型としては使用されない場合は、ジェネリック型パラメーターを共変としてマークできます。逆に、型が正式なメソッド パラメーターの型としてのみ使用され、メソッドの戻り値の型として使用されない場合は、その型を反変としてマークできます。

于 2010-06-21T05:31:31.933 に答える