12

ジェネリック クラスを使用して動的ディスパッチを実装dynamicし、ジェネリック型パラメーターが別のクラスのプライベート 内部クラスである場合、ランタイム バインダーは例外をスローします。

例えば:

using System;

public abstract class Dispatcher<T> {
    public T Call(object foo) { return CallDispatch((dynamic)foo); }

    protected abstract T CallDispatch(int foo);
    protected abstract T CallDispatch(string foo);
}

public class Program {
    public static void Main() {
        TypeFinder d = new TypeFinder();

        Console.WriteLine(d.Call(0));
        Console.WriteLine(d.Call(""));
    }

    private class TypeFinder : Dispatcher<CallType> {
        protected override CallType CallDispatch(int foo) {
            return CallType.Int;
        }

        protected override CallType CallDispatch(string foo) {
            return CallType.String;
        }
    }

    private enum CallType { Int, String }
}

ここではRuntimeBinderException、メッセージとともに a がスローされます

「Dispatcher.CallDispatch(int)」は、保護レベルが原因でアクセスできません

アクセスできない理由は、型パラメーターTがアクセスできないプライベートCallTypeであるDispatcher<T>ためです。したがって、CallDispatchアクセスできない必要がありますが、 としてアクセスできるため、そうではありませんT

これは のバグdynamicですか、それともサポート対象外ですか?

4

2 に答える 2

4

バグです。静的に電話をかけることができれば(そしてそうすることができれば)、動的に電話をかけることができるはずです。

具体的には、次のコードが機能します。

using System;

public abstract class Dispatcher<T> {
    public T Call(object foo)
    {
        return CallDispatch(((object)(dynamic)foo).ToString());
    }

    protected abstract T CallDispatch(int foo);
    protected abstract T CallDispatch(string foo);
}

public class Program {
    public static void Main() {
        TypeFinder d = new TypeFinder();

        Console.WriteLine(d.Call(0));
        Console.WriteLine(d.Call(""));
    }

    private class TypeFinder : Dispatcher<CallType> {
        protected override CallType CallDispatch(int foo) {
            return CallType.Int;
        }

        protected override CallType CallDispatch(string foo) {
            return CallType.String;
        }
    }

    private enum CallType { Int, String }
}

静的型を知らせるために使用したことに注意してくださいToString()。C#コンパイラとCLRは、このコンテキストがプライベート型にアクセスするCallTypeことを許可するため、DLRもそれを許可する必要があります。

于 2011-05-31T12:51:43.580 に答える
1

次の静的型付けの変更は同等である必要があるため、これはバグです。

using System;

public abstract class Dispatcher<T>
{
    public T Call(int foo) { return CallDispatch(foo); }
    public T Call(string foo) { return CallDispatch(foo); }

    protected abstract T CallDispatch(int foo);
    protected abstract T CallDispatch(string foo);
}

そして、それは機能します。

この問題は、コンパイラとそれが行う dlr 呼び出し、およびコンパイラが呼び出しに含める静的情報に問題があるようです。これは、dlr 呼び出しを手動でセットアップするオープン ソース フレームワークImpromptuInterfaceで回避できます。Impromptu では、コンテキストをに設定するthisことで、TypeFinder になるランタイム タイプからアクセス許可を取得します。

using System;
using ImpromptuInterface.Dynamic;
public abstract class Dispatcher<T>
{
    protected CacheableInvocation _cachedDynamicInvoke;

    protected Dispatcher()
    {
        _cachedDynamicInvoke= new CacheableInvocation(InvocationKind.InvokeMember, "CallDispatch", argCount: 1, context: this);
    }

    public T Call(object foo)
    {
        return (T) _cachedDynamicInvoke.Invoke(this, foo);
    }

    protected abstract T CallDispatch(int foo);
    protected abstract T CallDispatch(string foo);
}
于 2011-06-02T15:16:19.283 に答える