Lambda - konwersja typu z Expresion<T> i Func<T, result>

0

Cześc.

Proszę o pomoc w sprawie konwersji między typami. Oto istota problemu:

  1. Mamy klasy:
internal class InternalClass
{
    public int FirstProperty { get; private set; }
    public int SecondProperty {get; private set; }

   public static implicit operator PublicClass(InternalClass internalClass)
   {
       PublicClass result = new PublicClass();
       result.First = internalClass.FirstProperty;
       result.Second = internalClass.SecondProperty;
       return result;
   }
}

public class PublicClass
{
    public int First {get; set; }
    public int Second {get; set; }
}

Jak widać prosta konwersja miedzy obiema typami. Klasa publiczna to po prostu klasa POCO (tutaj znacznie uproszona) widoczna w całej domenie aplikacji. Natomiast klasa InternalClass to obiekt encyjny pochodzący z ORM'u (LinQ To SQL). Zasadność takiego rozwiązania, jest taka, że Context i generalnie struktura źródła danych jest wymienna natomiast klasy encyjne chcę utrzymać niezmienne. Mniejsza o to. Do rzeczy:
Pobieranie wszystkich rekordów z tabeli InternalClass realizuję w prosty sposób:

return Context.InternalClass.Cast<PublicClass>();

pojawia się natomiast problem, gdybym chciał pobrać tylko wybrane rekordy:

public IEnumerable<PublicClass> GetByCondition(Expression<Func<PublicClass, bool>> condition)
{
return Context.InternalClass.Where(condition); // bad error
}

niestety pojawia się problem, gdyż where przyjmuję warunek

Expression<Func<InternalClass, bool>>

a ja mam taki jak podany w deklaracji, a naturalnie nie mogę na zewnątrz uwidocznić InternalClass. To nie wchodzi w grę.
Oczywiście mógłbym zrobić to nadmiarowo:

public IEnumerable<PublicClass> GetByCondition(Func<PublicClass, bool> condition)
{
return Context.InternalClass.Cast<PublicClass>().Where(condition);
}

Teraz mogłem pozbyć się ubierania tego w Expression, ale chyba nie o to chodzi, bo teraz zostaną przefiltrowane rekordy po pobraniu wszystkich z bazy.

Tak wiec zasadnicze pytanie brzmi - jak przekonwertować Expression<Func<PublicClass, bool>> na Expression<Func<InternalClass, bool>> znając sposób konwersji miedzy obiektami PublicClass i InternalClass.

Z góry dzięki za pomoc.

0

Problem już rozwiązałem. Dzięki.

1

Z ciekawości - jak rozwiązałeś? Bo myślałem wczoraj nad odpowiedzią i nic mądrego nie wymyśliłem :)

@down - no tak, Kowariancja i kontrawariancja, ale autor pisze że jakoś rozwiązał.

0

Tak wiec zasadnicze pytanie brzmi - jak przekonwertować
Expression<Func<PublicClass, bool>>
na
Expression<Func<InternalClass, bool>>
znając sposób konwersji miedzy obiektami PublicClass i InternalClass.
Takie cuda to w NET 4.0

0

Kowariancja i kontrawariancja to chyba się tyczą klas, gdzie jedna dziedziczy z drugiej raczej, nie? :)

0

Witam Was ponownie. Całość pisałem pod .NET 3.5, rozwiązania znalazłem dwa (jakoś po napisaniu pytania na forum, google zaczyna lepiej działać :) )

Rozwiązanie pierwsze jest tutaj:
http://stackoverflow.com/questions/654153/c-how-to-convert-an-expressionfuncsometype-to-an-expressionfuncothertype

Przyznam, że sam na pewno bym na to nie wpadł. Działa okej, co ważne jednak, należy zastosować przepisywanie bezpośrednio w tworzeniu wyrażenia nazwanego w przykładzie convert. Nie można użyc implicit operator, gdyż wtedy powstaje wyrażenie zawierające w sobie właśnie tę funkcję, która jest nieprzetłumaczalna.

Druga opcja to prostszy sposób o ile mamy dostęp do Func<PublicClass, result> zamiast Expression<Func<PublicClass, result>>
Tam więc jeśli typy PublicClass i InternalClass są możliwe do konwertowania jednego na drugi za pomocą jawnej/niejawnej konwersji to wystarczy... wywołać tego delegata :P

Func<PublicClass, bool> publicCond = //coś tam coś tam...
Func<InternalClass, bool> internalCond = p => publicCond(p);

1 użytkowników online, w tym zalogowanych: 0, gości: 1