Как преобразовать Func‹T1, bool› в Func‹T2, bool› в C#

Я попытался закодировать функцию, используя refelecion, для преобразования функции Func‹ TSource, bool> в Func‹ TTarget, bool>, но безуспешно.

Это то, что я сделал:

static Func<TTarget, bool> Convert<TSource, TTarget>(Func<TSource, bool> func)
    {
        var result = func;
        result.GetType().GenericTypeArguments[1] = typeof(TTarget);
        return (Func<TTarget, bool>)result;
    } 

Редактировать:

В моем случае у меня есть объект User как DTO, и я не хочу делиться этим DTO с другими слоями, он будет виден только моему сервисному агенту. Затем есть еще один уровень, который имеет доступ к моему сервисному агенту, в на этом уровне у меня есть еще один объект, представляющий пользователя, скажем, «CustomUser». Допустим, разница между «Пользователь» и «CutomUser» в том, что первый имеет свойство «Пароль», а второй — без него.

В моем сервисном агенте у меня есть функция GetUser( Func‹ User, bool> func ), но на моем стороннем уровне я не вижу объект User, однако объект CustomUser виден Итак, на моем сервисном агентском уровне я хочу создать еще одну функцию GetUser ( Func‹ CustomUser, bool >), которая будет видна другим слоям, и эта функция напрямую вызывает первую скрытую функцию GetUser(Func‹ User, bool>) с помощью преобразователя

public CustomUser GetUser(Func<CustomUser, bool> func) {
    // var myUser = this.GetUser(ConvertFunc( func) ) ;
    // The rest of code before returning my customUser
}

person SomeCode.NET    schedule 28.09.2014    source источник
comment
Что бы это вообще значило? Если func принимает TSource, то он принимает TSource. Притворяться, что это требует TTarget, вероятно, плохо кончится.   -  person Oliver Charlesworth    schedule 29.09.2014
comment
Это не имеет смысла, если для этого нет большего контекста.   -  person Theodoros Chatzigiannakis    schedule 29.09.2014
comment
@OliverCharlesworth, почему это невозможно? если у меня есть функция с одним аргументом Func‹User, bool›, то я вызываю ее следующим образом: MyFunction(u=› u.Id == 1) затем, если я преобразую свой Func‹User, bool› в Func‹MyCustomUser , bool› метод вызова остается прежним, потому что у меня одинаковые свойства как в User, так и в CustomUser.   -  person SomeCode.NET    schedule 29.09.2014
comment
Если CustomUser расширяется из User, то преобразование не требуется.   -  person Oliver Charlesworth    schedule 29.09.2014
comment
@OliverCharlesworth Я знаю это, но CustomUser не знает, если можно преобразовать выражение, почему бы не Func? взгляните на этот более быстрый способ приведения Func‹ T, T2› в Func‹T, объект›   -  person SomeCode.NET    schedule 29.09.2014
comment
Без предложения where, гарантирующего, что TSource и TTarget реализуют что-то похожее, вы не сможете делать то, что хотите, потому что вы не можете гарантировать, что Func<TTarget,bool> совместимо с Func<TSource,bool>. Возможно, если вы объясните, почему, по вашему считаете, вам нужно это сделать, кто-нибудь сможет помочь с этим.   -  person Peter Ritchie    schedule 29.09.2014
comment
@cYounes Потому что весь смысл деревьев выражений в том, что код может точно исследовать, как выглядит выражение. Если бы вы могли сделать это с помощью произвольных методов, нам бы вообще не понадобились деревья выражений.   -  person    schedule 29.09.2014
comment
Если CustomerUser не является User, и вы все еще хотите обращаться с ним как с User (и вы уверены, что это сработает), лучше попробуйте обойти проблему, набрав dynamic. Нет смысла пытаться обойти статическую систему типов с помощью хитрых уловок, потому что (а) это не так просто, как кажется, и (б) вы можете легко отказаться от этого в более новых версиях языка.   -  person Theodoros Chatzigiannakis    schedule 29.09.2014
comment
@PeterRitchie Просто объяснил ситуацию в отредактированном посте   -  person SomeCode.NET    schedule 29.09.2014
comment
@cYounes Вы не можете делать то, что хотите, не делясь чем-то между слоями. Похоже, вам действительно нужно что-то динамическое. (en.wikipedia.org/wiki/Dynamic_dispatch) Вероятно, множество хороших вопросов по SO об этом stackoverflow.com/search?q=dynamic+dispatch+%5Bc%23%5D   -  person Peter Ritchie    schedule 29.09.2014
comment
@cYounes вам нужно что-то вроде Func<User,bool> userFunc = u=>func(UserToCustomUser(u)) и после использования this.GetUser(userfunc ), но у вас должна быть функция UserToCustomUser, которая может сопоставлять объект пользователя с объектом пользователя-клиента.   -  person Grundy    schedule 29.09.2014
comment
@Grundy Я уже определил функцию UserToCustomUser. Не могли бы вы просто уточнить, пожалуйста? :)   -  person SomeCode.NET    schedule 29.09.2014
comment
@cYounes, что вам нужно уточнить? я уже показываю образец Func<User,bool> userFunc = u=>func(UserToCustomUser(u))   -  person Grundy    schedule 29.09.2014
comment
@Grundy Большое спасибо, ваше решение работает правильно, вы можете написать ответ, который будет отмечен как решение :)   -  person SomeCode.NET    schedule 29.09.2014


Ответы (2)


Вы пытаетесь преобразовать Func<TSource, bool> в Func<TTarget, bool> без каких-либо других деталей или ограничений.

Рассмотрим случай, когда TSource — это string, а TTarget — это XmlDocument. Метод, который соответствует первому делегату, — string.StartsWith(string), а метод, который подходит второму делегату, — List<XmlDocument>.Contains(XmlDocument).

Итак, когда вы делаете следующее (действительный вызов, если мы предполагаем, что ваш код действителен):

var converted = Convert<string, XmlDocument>("String".StartsWith);

И тогда вы звоните:

var result = converted.Invoke(new XmlDocument());

Как ты думаешь, что произойдет? Что вы хотите сделать?

person Theodoros Chatzigiannakis    schedule 28.09.2014
comment
как я уже сказал в комментарии выше, если можно преобразовать выражение, почему бы не использовать функцию? Более быстрый способ приведения Func‹T, T2› к Функция‹T, объект› - person SomeCode.NET; 29.09.2014
comment
@cYounes Навскидку, я бы сказал, что это потому, что последний параметр типа является ковариантным (а остальные - нет). Взгляните на его определение (обратите внимание на ключевое слово out): msdn.microsoft.com/en-us/library/bb549151(v=vs.110).aspx - person Theodoros Chatzigiannakis; 29.09.2014
comment
@cYounes, потому что Func уже скомпилирован, но выражение представляет собой просто синтаксическое дерево, которое вы можете изменить по своему усмотрению. - person Grundy; 29.09.2014

Наконец, решение @Grundy работает для меня правильно, мне просто нужно создать функцию, которая преобразует объект User в CustomUser, затем я делаю следующее:

Func<User,bool> userFunc = u=>func(UserToCustomUser(u))
this.GetUser(userfunc) 
person SomeCode.NET    schedule 02.10.2014