C# Expression.Call接口IList上的Expression.PropertyOrField<;T>;抛出无效操作异常
因此,如果我尝试对IList类型的类的属性调用“Clear”,它会抛出。如果我对IList类型的常量执行相同的操作,程序运行良好C# Expression.Call接口IList上的Expression.PropertyOrField<;T>;抛出无效操作异常,c#,reflection,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.W
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
类程序
{
静态void Main(字符串[]参数)
{
var parent=new parent(new List());
parent.Data.Add(新的SomeClass(“测试”));
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(父项),“Data”),“Clear”,null,null),null);
var x2=expr.Compile();
x2.DynamicInvoke();
Console.WriteLine(parent.Data.Count);
Console.ReadLine();
}
公共类父类
{
公共父级(IList数据)
{
这个。数据=数据;
}
公共IList数据{get;set;}
}
公共类
{
公共类(字符串值){}
}
}
//输出:
// 1
// 0
//引发了类型为InvalidOperationException的异常
这仅仅是一个bug,还是它这样做有某种逻辑原因?我将标记任何使用现有连接bug进行响应或对此行为有合理解释的人作为答案,但是。。。解决方案是在调用之前强制转换到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);
var expr2=Expression.Lambda(Expression.Call(
Expression.Convert(Expression.PropertyOrField(Expression.Constant(parent),“Data”)、typeof(ICollection).MakeGenericType(parent.Data.GetType().GetGenericArguments())
,“清除”,空,空),空);
我将标记任何使用现有连接错误进行响应或对此行为有合理解释的人作为答案,但。。。解决方案是在调用之前强制转换到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);
var expr2=Expression.Lambda(Expression.Call(
Expression.Convert(Expression.PropertyOrField(Expression.Constant(parent),“Data”)、typeof(ICollection).MakeGenericType(parent.Data.GetType().GetGenericArguments())
,“清除”,空,空),空);
由于.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将起作用,因为Clear方法是在ICollection接口中定义的,而不是在IList接口上定义的
关于接口类型派生的更多信息,请参见的答案,其行为类似于此,因为接口中的“继承”在.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将起作用,因为Clear方法是在ICollection接口中定义的,而不是在IList接口上定义的
有关接口类型派生的更多信息,请参见