代码之家  ›  专栏  ›  技术社区  ›  Barsonax

动态抛出Microsoft。C竖琴。RuntimeBinder。私有类型上的RuntimeBinderException

  •  0
  • Barsonax  · 技术社区  · 8 年前

    我需要编写一些代码来克隆任何类型的哈希集,但类型事先未知。由于缺少非泛型接口(与dictionary不同,没有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移动到program类或将ReferenceType设置为public,则会正常工作。它需要查看ReferenceType才能工作。尽管我们只对调用Clear方法感兴趣,它甚至没有在ReferenceType上定义,而是在HashSet上定义<>。

    如何在不必手动进行反射工作的情况下解决此问题?请记住,类型在编译时是未知的,因此没有泛型。

    编辑:我知道,在某个时候,我必须创建新实例,因此必须调用私有构造函数。如果可以使用dynamic调用构造函数,我预计在这种情况下会出现错误(并通过使用反射来解决),但现在不可能只在HashSet上调用Clear。

    1 回复  |  直到 8 年前
        1
  •  0
  •   Adam Brown    8 年前

    我不理解这里需要动态。我很确定你可以用泛型做你需要的事情。

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

     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。

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