接口IList <t>上的Expression.PropertyOrField上的Expression.Call抛出InvalidOperationException </t>

时间:2012-02-24 00:49:39

标签: c# reflection

因此,如果我尝试在属于IList类的类的属性上调用“Clear”,则抛出它。如果我对IList类型的常量执行相同的操作,程序运行正常。

class Program
{
    static void Main(string[] args)
    {
        var parent = new Parent(new List<SomeClass>());
        parent.Data.Add(new SomeClass("Test"));
        Console.WriteLine(parent.Data.Count);

        var expr = Expression.Lambda(Expression.Call(Expression.Constant(parent.Data), "Clear", null, null), null);
        var x = expr.Compile();
        x.DynamicInvoke();

        Console.WriteLine(parent.Data.Count);

        var expr2 = Expression.Lambda(Expression.Call(Expression.PropertyOrField(Expression.Constant(parent), "Data"), "Clear", null, null), null);
        var x2 = expr.Compile();
        x2.DynamicInvoke();

        Console.WriteLine(parent.Data.Count);
        Console.ReadLine();

    }

    public class Parent
    {
        public Parent(IList<SomeClass> data)
        {
            this.Data = data;
        }
        public IList<SomeClass> Data { get; set; }
    }
    public class SomeClass
    {
        public SomeClass(string value) { }
    }
}

// output:
// 1
// 0
// Exception of type: InvalidOperationException was thrown

这只是一个错误,还是有一些合乎逻辑的原因呢?

2 个答案:

答案 0 :(得分:1)

它的行为与此类似,因为接口中的“继承”如何在.net中工作。想象一下,你有这样的接口:

public interface ITest 
{
    string Property{get;set;}
}


public interface ISubTest : ITest
{

}

然后打电话给:

typeof(ITest).GetProperty("Property"); // returns property
typeof(ISubTest).GetProperty("Property"); // returns null 

因此,在您的情况下,转换为ICollection会起作用,因为在ICollection接口中定义了Clear方法,而不是在IList接口上定义。

有关Why is the members of an inherited interface not available using reflection?

的答案中的接口类型派生的更多信息

答案 1 :(得分:0)

我会标记响应现有连接错误的人或对此行为有一些合理的解释作为答案,但......解决方案是在拨打电话之前转换为ICollection

        var expr2 = Expression.Lambda(Expression.Call(
            Expression.Convert(Expression.PropertyOrField(Expression.Constant(parent), "Data"), typeof(ICollection<>).MakeGenericType(parent.Data.GetType().GetGenericArguments()))
            , "Clear", null, null), null);