Преобразование выражения > к выражению >> - PullRequest
2 голосов
/ 07 мая 2020

У меня есть ситуация, когда я хотел бы преобразовать Expression<Func<BaseType,object>> в Expression<Func<DerievedType,object>>. Я также открыт для других решений для этого конкретного сценария.

Чтобы продемонстрировать проблему, у меня есть базовый класс:

public class PersonBase
{
    public string Name{get;set;}

    public virtual void Save()
    {
        Dummy.Method1(this,x=>x.Name);
    }
}

Производный класс определяется как

public class Student:PersonBase
{
    public string School{get;set;}
}

Класс-пустышка и связанные методы определены как

public class Dummy
{

public static void Method1<TDestination>(TDestination value,params Expression<Func<TDestination,object>>[] selector)
{
    var destinationType = value.GetType();
    var selectorType = selector.GetType();

    Console.WriteLine("Destination Type : " + destinationType.ToString());
    Console.WriteLine("Selector Type : " +selectorType.ToString());


    var FinalMethodToCallInfo = typeof(Dummy).GetMethod("FinalMethodToCall", BindingFlags.Public | BindingFlags.Static);
    var FinalMethodToCallMethod = FinalMethodToCallInfo.MakeGenericMethod(destinationType);
    FinalMethodToCallMethod.Invoke(null, new object[] { selector });
}

public static void FinalMethodToCall<TDestination>(params Expression<Func<TDestination,object>>[] selector)
{
    Console.WriteLine("Finally here");
}
}

Демонстрируется весь пример в Fiddle здесь .

Поскольку destinationType в Method1 имеет тип Student, а selectorType имеет тип Expression>, я получаю исключение, когда пытаюсь вызвать FinalMethodToCall с помощью отражения.

Object of type 'System.Linq.Expressions.Expression`1[System.Func`2[PersonBase,System.Object]][]' cannot be converted to type 'System.Linq.Expressions.Expression`1[System.Func`2[Student,System.Object]][]'.

Я здесь немного потерялся. Одно из решений, которое я мог придумать, заключалось в использовании ExpressionVisitor для замены типа параметра выражения с BaseClass на DerievedType.

Но мне было любопытно узнать, почему при вызове метода из Base (и передаче выражение), я указывал на два разных типа (производный и базовый). Может ли кто-нибудь помочь мне понять это поведение, а также есть ли лучшее решение, чем использование ExpressionVisitor для замены типа параметра?

PS: Я не могу изменить подпись моего метода сохранения.

Ответы [ 2 ]

0 голосов
/ 12 мая 2020

Я изменил его, чтобы он работал с "this" вместо нового объекта Student. Вот исправленный и исправленный код

public class PersonBase
{
    public string Name { get; set; }
    public virtual void Save()
    {
        // Change 1
        Dummy.Method1(this, x => x.Name);
    }
}
public class Student : PersonBase
{
    public string School { get; set; }
}

public class Dummy
{
    public static void FinalMethodToCall<TDestination>(Expression<Func<TDestination, object>> selector)
    {
        Console.WriteLine("Finally here");
    }

    public static void Method1<TDestination>(TDestination value, params Expression<Func<TDestination, object>>[] selector)
    {
        var destinationType = value.GetType();  
        var selectorType = selector.GetType();

        var FinalMethodToCallInfo = typeof(Dummy).GetMethod("FinalMethodToCall", BindingFlags.Public | BindingFlags.Static);
        var FinalMethodToCallMethod = FinalMethodToCallInfo.MakeGenericMethod(destinationType);
        //FinalMethodToCallMethod.Invoke(null, new object[] { selector });

        // Change 2
        ParameterExpression pExpr = Expression.Parameter(destinationType, "g");
        PropertyInfo columnProperty = destinationType.GetProperty("Name");
        MemberExpression mExpr = Expression.Property(pExpr, columnProperty);

        //var lExpr = Expression.Lambda<Func<TDestination, object>>(mExpr, pExpr);
        //FinalMethodToCallMethod.Invoke(null, new object[] { lExpr });

        var delegateType = typeof(Func<,>).MakeGenericType(destinationType, typeof(object));
        dynamic l1 = Expression.Lambda(delegateType, mExpr, pExpr);
        FinalMethodToCallMethod.Invoke(null, new object[] { l1 });
    }
}
0 голосов
/ 07 мая 2020

Я внес несколько изменений в общие c методы, как показано ниже.

Обновить PersonBase и сделать метод Save для явного объявления T.

public class PersonBase
{
    public string Name{get;set;}

    public virtual void Save<T>() where T : PersonBase
    {
        Dummy.Method1<T>(this,x=>x.Name);
    }
}

Обновить Первым параметром Method1 будет Object, как показано ниже.

public static void Method1<TDestination>(Object value,params Expression<Func<TDestination,object>>[] selector)

И вызовите Save с явной передачей значения generi c, как показано ниже.

(new Student{Name="anu"}).Save<Student>();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...