这是动态中的错误吗
本文关键字:错误 动态 | 更新日期: 2023-09-27 17:58:02
当在泛型类上使用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
"Dispatcher.CallDispatch(int)"由于其保护级别而无法访问
无法访问的原因是类型参数T
是Dispatcher<T>
无法访问的私有CallType
。因此,CallDispatch
必须是不可访问的,但事实并非如此,因为它可以作为T
访问。
这是dynamic
的一个错误,还是不应该支持它?
这是一个错误。如果您可以静态地进行调用(并且可以),那么您应该能够动态地进行调用。
具体来说,以下代码有效:
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也应该允许它。
这是一个错误,因为下面的静态类型更改应该是等效的
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一起使用。通过将上下文设置为this
,Impromptu可以从运行时类型(即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);
}