Как я могу вернуться: где TEnumerable: IEnumerable <T> - PullRequest
0 голосов
/ 04 декабря 2018

Цель: универсальный перечислимый тип должен быть того же типа при возврате.

Примечание: это работает, когда типы введены, но я не понимаю, почему они могут 't не будет выведено* Текущий метод (работает, только если введены все типы)

public static TEnumerable WithEach<TEnumerable, T>(this TEnumerable items, Action<T> action)
where TEnumerable : IEnumerable<T>
{
    foreach (var item in items) action.Invoke(item);
    return items;
}

Пример только

var list = new List<int>(); //TODO: Mock random values
list.WithEach(x => Console.WriteLine(x)) //Here WithEach ideally returns List<int> following orignal type List<int>
    .OrderBy(x => x) 
    .WithEach(x => Console.WriteLine(x)); //Here WithEach ideally returns IOrderedEnumerable<int> following OrderBy

Заставить его работать

var list = new List<int>(); //TODO: Mock random values
list.WithEach<List<int>, int>(x => Console.WriteLine(x))
    .OrderBy(x => x) 
    .WithEach<IOrderedEnumerable<int>, int>(x => Console.WriteLine(x));

Чего мне не хватает, так это того, почему C # не может определить типы, хотя фильтр where делает типы точными.Я понимаю, почему вы предоставляете все или не универсальные типы для методов, поэтому, пожалуйста, не указывайте мне эти ответы.

Редактировать: Если я не могу вывести типы;тогда как я могу сделать это более элегантным?

Ответы [ 2 ]

0 голосов
/ 04 декабря 2018

Вывод типа в C # является очень сложным - на этот раз я не собираюсь выдвигать спецификацию, чтобы попытаться пройти через нее, потому что я осознаю, насколько ужасной она может стать.

Я считаю проблема в том, что ни одна из комбинаций параметров / аргументов не дает компилятору достаточно информации для вывода T:

  • TEnumerable itemsпараметр не упоминает T, поэтому он не используется для вывода T, несмотря на ограничение типа
  • Параметр Action<T> будет в порядке, но компилятор не может сделать вывод на основев лямбда-выражении, которое вы предоставляете

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

var list = new List<int>();
list.WithEach((int x) => Console.WriteLine(x++))
    .OrderBy(x => x) 
    .WithEach((int x) => Console.WriteLine(x));

Недостатком этого является то, что он не будет работать с анонимнымтипы, конечно.

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

public static TEnumerable WithEach<TEnumerable, T>(
    this TEnumerable items,
    Action<T> action,
    T ignored = default(T))

Если вы хотите вызвать метод со списком какого-то анонимного типа, вы можете написать:

list.WithEach(x => Console.WriteLine(x.Name), new { Name = "", Value = 10 });

... где финалАргумент будет соответствовать анонимному типу.Это позволит выводить тип T по последнему параметру вместо второго.Вы можете использовать это для других типов, конечно, но я бы, вероятно, предпочел использовать его для анонимных типов.

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

0 голосов
/ 04 декабря 2018

Объявите ваше расширение, используя T, например, так:

public static IEnumerable<T> WithEach<T>(this IEnumerable<T> items,Action<T> action)
{
    foreach (var item in items) action.Invoke(item);
    return items;
}

Это имеет обратную сторону потери конкретного подкласса IEnumerable, который вы реализуете.

Это легкореализовать перегрузки для определенных подклассов, которые вас интересуют:

public static IOrderedEnumerable<T> WithEach<T>(this IOrderedEnumerable<T> items, Action<T> action)
{
    ((IEnumerable<T>)items).WithEach(action);
    return items;
} 

Однако возвращать IEnumerable после итерации немного страшно.IEnumerables не могут быть перезапущены.

...