在私有类型上动态抛出 Microsoft.CSharp.RuntimeBinder.RuntimeBinderException
Dynamic throwing Microsoft.CSharp.RuntimeBinder.RuntimeBinderException on private types
我需要编写一些代码来克隆任何类型的 HashSet,但事先不知道该类型。由于缺少非通用接口(与字典不同,没有 ISet 接口只有 ISet<>),我必须使用反射。我决定让 dynamic 为我处理反射工作,但现在我 运行 遇到了一个看似非常奇怪的问题,当我 运行 以下代码(从现实世界的代码中大大简化)时:
class Program
{
static void Main(string[] args)
{
HashSet<ReferenceType> source = new HashSet<ReferenceType>();
ExtMethodsCloning.DeepClone(source);
}
private class ReferenceType { }
}
public static class ExtMethodsCloning
{
public static void SomeCloningMethodThatHappensToCallClear(dynamic baseObj)
{
baseObj.Clear();
}
}
如果您将 DeepClone 移至程序 class 或将 ReferenceType 设置为 public 它会起作用。它需要以某种方式查看 ReferenceType 才能工作。即使我们只对调用 Clear 方法感兴趣,它甚至没有在 ReferenceType 上定义,而是在 HashSet<> 上定义。
如何在不必诉诸手动进行反射工作的情况下解决这个问题?请记住,类型在编译时是未知的,因此没有泛型。
编辑:我知道在某些时候我必须创建新实例,因此必须调用私有构造函数。如果甚至可以使用动态调用构造函数,我希望在这种情况下会出现错误(并通过使用反射来解决它),但现在仅在 HashSet 上调用 Clear 时不会出现错误。
我不明白这里需要动态。我很确定你可以用泛型做你需要的事情。
编辑:如何通过反射调用泛型方法:
static void Main(string[] args)
{
var hs1 = new HashSet<SomePrivateClass>();
CallClear(hs1);
}
public static void CallClear(object objectThatIsAHashSet)
{
var method = typeof(Program).GetMethod("Clear", BindingFlags.Public | BindingFlags.Static);
var hsGenericType = objectThatIsAHashSet.GetType().GetGenericArguments()[0];
var genericMethod = method.MakeGenericMethod(hsGenericType);
genericMethod.Invoke(null, new[] {objectThatIsAHashSet});
}
private class SomePrivateClass { }
public static void Clear<T>(HashSet<T> hs)
{
hs.Clear();
}
编辑 2:为什么它不适用于动态。
基本上,动态只允许访问类型的 public 成员。因此,它不能用于调用私有成员或私有类型。基本规则是,如果你不能在一段代码中使用它的类型引用一个方法,你就不能使用动态访问它(即你不能使用动态来破坏封装)。
我需要编写一些代码来克隆任何类型的 HashSet,但事先不知道该类型。由于缺少非通用接口(与字典不同,没有 ISet 接口只有 ISet<>),我必须使用反射。我决定让 dynamic 为我处理反射工作,但现在我 运行 遇到了一个看似非常奇怪的问题,当我 运行 以下代码(从现实世界的代码中大大简化)时:
class Program
{
static void Main(string[] args)
{
HashSet<ReferenceType> source = new HashSet<ReferenceType>();
ExtMethodsCloning.DeepClone(source);
}
private class ReferenceType { }
}
public static class ExtMethodsCloning
{
public static void SomeCloningMethodThatHappensToCallClear(dynamic baseObj)
{
baseObj.Clear();
}
}
如果您将 DeepClone 移至程序 class 或将 ReferenceType 设置为 public 它会起作用。它需要以某种方式查看 ReferenceType 才能工作。即使我们只对调用 Clear 方法感兴趣,它甚至没有在 ReferenceType 上定义,而是在 HashSet<> 上定义。
如何在不必诉诸手动进行反射工作的情况下解决这个问题?请记住,类型在编译时是未知的,因此没有泛型。
编辑:我知道在某些时候我必须创建新实例,因此必须调用私有构造函数。如果甚至可以使用动态调用构造函数,我希望在这种情况下会出现错误(并通过使用反射来解决它),但现在仅在 HashSet 上调用 Clear 时不会出现错误。
我不明白这里需要动态。我很确定你可以用泛型做你需要的事情。
编辑:如何通过反射调用泛型方法:
static void Main(string[] args)
{
var hs1 = new HashSet<SomePrivateClass>();
CallClear(hs1);
}
public static void CallClear(object objectThatIsAHashSet)
{
var method = typeof(Program).GetMethod("Clear", BindingFlags.Public | BindingFlags.Static);
var hsGenericType = objectThatIsAHashSet.GetType().GetGenericArguments()[0];
var genericMethod = method.MakeGenericMethod(hsGenericType);
genericMethod.Invoke(null, new[] {objectThatIsAHashSet});
}
private class SomePrivateClass { }
public static void Clear<T>(HashSet<T> hs)
{
hs.Clear();
}
编辑 2:为什么它不适用于动态。
基本上,动态只允许访问类型的 public 成员。因此,它不能用于调用私有成员或私有类型。基本规则是,如果你不能在一段代码中使用它的类型引用一个方法,你就不能使用动态访问它(即你不能使用动态来破坏封装)。