Expression.Call для Expression.PropertyOrField для интерфейса IList <T>создает исключение InvalidOperationException - PullRequest
1 голос
/ 24 февраля 2012

Так что, если я попытаюсь вызвать «Clear» для свойства класса, который имеет тип IList, он выдаст. Если я делаю то же самое с константой типа 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 ]

1 голос
/ 07 июня 2013

Это ведет себя так из-за того, как "наследование" в интерфейсах работает в .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, а не в IListinterface.

Подробнее о выводе типа интерфейса в ответе на Почему члены унаследованного интерфейса недоступны с помощью отражения?

0 голосов
/ 24 февраля 2012

Я отмечу любого, кто ответит существующей ошибкой соединения или у которого есть некоторое разумное объяснение этого поведения, как ответ, но ... решение состоит в том, чтобы привести 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);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...