Метод расширения для универсального типа с дополнительными параметрами универсального типа - PullRequest
4 голосов
/ 16 декабря 2010

Я хотел бы написать метод расширения для универсального типа с дополнительными параметрами универсального типа.У меня уже есть рабочий код, но результат мне не нравится, потому что пользователь должен повторно ввести параметры универсального типа существующего типа.

У меня есть конкретный пример, но имейте в виду, что этоэто общая проблема.Я ценю отзывы о конкретной проблеме, но я ищу общие решения.

Для класса типа Action<T> добавьте метод расширения с сигнатурой, подобной этой:

Func<T, TResult> ToFunc<TResult>();

Вот мой рабочий код:

public static class DelegateExtensions
{
  public static Func<T, TResult> ToFunc<T, TResult>(this Action<T> action)
  {
    return arg => { action(arg); return default(TResult); };
  }
}

Но использование воняет:

public void TakesAFunc(Func<int, float> someFunc) { /* ... */ }
// ...
Action<int> someIntAction = /* ... */;
TakesAFunc(someIntAction.ToFunc<int, float>());

В этом примере универсальный параметр int является единственным допустимым значением, поэтомуэто вызывает ненужное дублирование кода.

Вывод типа здесь не работает.Я думаю, это потому, что вы не можете вывести общий параметр через тип возвращаемого значения.

Этот код решит проблему, но, к сожалению, не работает:

public static class DelegateExtensions<T>
{
  public static Func<T, TResult> ToFunc<TResult>(this Action<T> action)
  {
    return arg => { action(arg); return default(TResult); };
  }
}

Использование будетТочно так же, как и следовало ожидать:

public void TakesAFunc(Func<int, float> someFunc) { /* ... */ }
// ...
Action<int> someIntAction = /* ... */;
TakesAFunc(someIntAction.ToFunc<float>());

Я заметил, что System.Linq.Queryable работает так же, как мой первый кусок кода, хотя обычно для него не нужны дополнительные параметры типа, поэтому вывод типа работает.

Есть ли какой-нибудь известный способ обойти эти дубликаты параметров универсального типа?Одна мысль, которая приходит на ум, - это генераторы кода или какие-то макросы, но я не могу придумать, как бы это сделать чисто.

Ответы [ 2 ]

3 голосов
/ 16 декабря 2010

Одна из распространенных уловок для такого рода вещей заключается в передаче фиктивного значения нужного типа только для вывода типа, что требуется в определенных сценариях с анонимными типами.

public static class DelegateExtensions
{
  public static Func<T, TResult> 
  ToFunc<T, TResult>(this Action<T> action, TResult ignored)
  {
    return arg => { action(arg); return default(TResult); };
  }
}

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

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

2 голосов
/ 11 января 2011

Я опоздал на вечеринку - извините.

Как уже упоминалось - в настоящее время это невозможно без переключения Func на выходной параметр.

Я выброшу другой способ сделать что-то подобное - он выглядит немного изменчивым синтаксисом, но он работает.

 public class ActionWrap<T>
{
    private readonly Action<T> _action;

    internal ActionWrap(Action<T> action)
    {
        _action = action;
    }

    public Func<T, TResult> OfType<TResult>()
    {
        return arg => { _action(arg); return default(TResult); };
    }
}

public static class DelegateExtensions
{
    public static ActionWrap<T> ToFunc<T>(this Action<T> action)
    {
        return new ActionWrap<T>(action);
    }
}

Затем вызывается так:

Action<int> x = z=> Console.WriteLine(z);
Func<int, float> asFunc = x.ToFunc().OfType<float>();

Это не совсем то, что вы хотели, но оно достигает цели не повторять int int generic снова и может быть распространено на другие случаигде вы хотите сделать что-то подобное.

...