动态抛出私有类型的Microsoft.CSharp.RuntimeBinder.RuntimeBinderException

时间:2018-01-16 18:41:51

标签: c# dynamic private

我需要编写一些代码来克隆任何类型的HashSet,但事先并不知道该类型。由于缺少非通用接口(与字典不同,没有ISet接口只是ISet<>),我必须使用反射。我决定让动态处理反射工作对我来说,但是当我运行以下代码(从现实代码中大大简化)时,我现在遇到了一个看似非常奇怪的问题:

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移动到程序类或将ReferenceType公开,则它可以正常工作。它以某种方式需要看到ReferenceType才能工作。尽管我们只对调用Clear方法感兴趣,而Clear方法甚至不是在ReferenceType上定义的,而是在HashSet&lt;&gt;上。

如何在不必手动进行反射工作的情况下解决这个问题?记住在编译时不知道类型,所以没有泛型。

编辑:我意识到在某些时候我必须创建新实例,因此必须调用私有构造函数。如果它甚至可以使用动态调用构造函数,那么在这种情况下会出现错误(并通过使用反射来解决它),但现在只在HashSet上调用Clear时不会。

1 个答案:

答案 0 :(得分:0)

我不明白这里需要动态。我非常确定你可以用泛型做你需要的东西。

编辑:如何通过反射调用泛型方法:

 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:为什么它不适用于动态。

基本上,dynamic只允许访问某个类型的公共成员。因此,它不能用于调用私有成员或私有类型。基本规则是,如果你不能使用它的类型引用一段代码中的方法,你就不能使用动态访问它(即你不能使用动态来破坏封装)。