Как конвертировать или разыграть Funcк функции - PullRequest
0 голосов
/ 25 октября 2018

У меня есть

Expression<Func<T1, T2>> source

, поэтому я могу без проблем скомпилировать его в Func<T1, T2>:

Func<T1, T2> result = source.Compile();

Но теперь у меня есть особый случай, где (учитывая, что T2 является int) я должен вернуть Func<T1, int>.Конечно, я не могу просто привести его, но я также не могу найти другой способ его преобразования.

public Func<T1, int> GetFuncToReturnId()
{
    if (source.ReturnType != typeof(int))
    {
        throw new InvalidOperationException("source must be of return type must be of type int");
    }

    return // ??? please help !!!
}

Я пытался преобразовать части Expression или скомпилированный Func в конструктор Func<T1, int> но это не помогло.Что я могу сделать, чтобы

  • преобразовать Expression<Func<T1, T2>> в Expression<Func<T1, int>>
  • или Func<T1, T2> в Func<T1, int>?

Ответы [ 2 ]

0 голосов
/ 25 октября 2018

Из вашего вопроса неясно, в чем именно заключается ваша проблема, но я могу предположить, что приведение Func<T1, T2> к Func<T1, int> дает недопустимую ошибку приведения.

Причина, по которой это неверно, заключается в том, что C # консервативен в отношении любого преобразования параметра типа в любой другой тип.Предположим, у вас есть пользовательское преобразование из Foo в Bar.Если у вас есть метод

Bar M<T>(T t) { return (Bar)t; }

, вы можете разумно ожидать, что M<Foo>(new Foo()) вызовет пользовательское преобразование в Bar.Но дженерики C # не являются шаблонами и не воссоздают код для каждого родового экземпляра.Этот вид преобразования действителен только в том случае, если имеется удостоверение или ссылка преобразование, и C # не позволяет вам совершить эту распространенную ошибку.

Более того, в любое времявы делаете типовой тест для универсального, он больше не «универсальный» .Предполагается, что общий код должен работать одинаково независимо от аргументов типа , поэтому он называется «универсальный код».Похоже, то, что вы делаете, работает против с целью генериков.

Тем не менее, если вы одержимы этим, есть несколько способов сделать эталонное преобразование междуобщие типы, подобные этому:

class C<T1, T2>
{
  void M(Func<T1, int> f) {}

  // This way is wrong.
  void N1(Func<T1, T2> f) 
  {
    if (f is Func<T1, int>)
      M((Func<T1, int>)f); // Error, cannot convert
  }

  // This works.
  void N2(Func<T1, T2> f) 
  {
    var fi = f as Func<T1, int>;
    if (fi != null)
      M(fi);
  }

  // This also works.
  void N3(Func<T1, T2> f) 
  {
    if (f is Func<T1, int>)
      M((Func<T1, int>)(object)f);
  }

  // This works in C# 7; it's a more concise way to combine the previous two
  void N4(Func<T1, T2> f) 
  {
    if (f is Func<T1, int> fi)
      M(fi);
  }

}
0 голосов
/ 25 октября 2018

Этого можно добиться, используя Convert.ChangeType

var compiled = source.Compile();

return (T1 x) => (int) Convert.ChangeType(compiled(x), typeof(int));

или просто дважды применив

var compiled = source.Compile();
return (T1 x) => (int) (object) compiled(x);
...