Можно ли применить общий метод к списку элементов?
Предположим, что я написал свой собственный метод для изменения списка на месте.
public static void MyReverse<T>(List<T> source)
{
var length = source.Count;
var hLength = length / 2;
for (var i = 0; i < hLength; i++)
{
T temp = source[i];
source[i] = source[length - 1 - i];
source[length - 1 - i] = temp;
}
}
Я называю это так, и он работает.
var fooList = new List<Foo>();
MyReverse(fooList);
Если я хочу отменить несколько списков, я называю это так.
var fooList = new List<Foo>();
var barList = new List<Bar>();
var bazList = new List<Baz>();
MyReverse(fooList);
MyReverse(barList);
MyReverse(bazList);
Если я хочу изменить произвольное количество списков, попробую:
public static void Main(string[] args)
{
var lists = new List<object>
{
new List<Foo>(),
new List<Bar>(),
new List<Bar>()
};
ReverseLists(lists);
}
public static void ReverseLists(List<object> sourceLists)
{
foreach (var sourceList in sourceLists)
{
MyReverse(sourceList); // Error: Type arguments cannot be inferred from usage
}
}
Но это порождает ошибку времени компиляции. Это то, что я пытаюсь сделать возможным - может ли быть реализован метод ReverseLists
?
Ответы
Ответ 1
Предполагая, что у вас есть статический метод, подобный этому
public static class ReverseHelper
{
public static void MyReverse<T>(IList<T> source)
{
var length = source.Count;
var hLength = length / 2;
for (var i = 0; i < hLength; i++)
{
T temp = source[i];
source[i] = source[length - 1 - i];
source[length - 1 - i] = temp;
}
}
}
С помощью не общего интерфейса и общего класса вы можете это сделать.
public interface IReverser
{
void Reverse();
}
public class ListReverser<T> : IReverser
{
private readonly IList<T> source;
public ListReverser(IList<T> source)
{
this.source = source;
}
public void Reverse()
{
ReverseHelper.MyReverse<T>(source);
}
}
static void Main(string[] args)
{
var lists = new List<IReverser>
{
new ListReverser<Foo>(new List<Foo>()),
new ListReverser<Bar>(new List<Bar>()),
new ListReverser<Bar>(new List<Bar>())
};
foreach (var reverser in lists)
{
reverser.Reverse();
}
}
Я использовал IList<T>
вместо List<T>
для поддержки более широкого числа типов; Если вы хотите List<T>
, вы можете вернуть его.
Ответ 2
Согласно моему комментарию выше...
Компилятор не может скрывать вывод типа T при передаче object
(что фактически происходит)
Однако существует гораздо более простой вариант - просто отказаться от использования дженериков и изменить подпись вашего метода MyReverse на public static void MyReverse(IList source)
(и в другом месте заменить List<object>
на IList
)
т
public static void Main(string args[])
{
var lists = new List<IList>
{
new List<Foo>(),
new List<Bar>(),
new List<Bar>()
};
ReverseLists(lists);
}
public static void MyReverse(IList source)
{
var length = source.Count;
var hLength = length / 2;
for (var i = 0; i < hLength; i++)
{
var temp = source[i];
source[i] = source[length - 1 - i];
source[length - 1 - i] = temp;
}
}
public static void ReverseLists(List<IList> sourceLists)
{
foreach (var sourceList in sourceLists)
{
MyReverse(sourceList); // Error: Type arguments cannot be inferred from usage
}
}
public class Foo
{
}
public class Bar
{
}
Ответ 3
Если вы измените свою сигнатуру метода ReverseLists на
public static void ReverseLists<T>(IEnumerable<object> sourceLists)
{
foreach (var sourceList in sourceLists.OfType<List<T>>())
{
MyReverse(sourceList);
}
}
Затем вы можете вызвать это для каждого типа списка:
ReverseLists<Foo>(lists);
ReverseLists<Bar>(lists);
Может быть, не обязательно иметь его один раз для типа списка, но сравнительно небольшое изменение в вашем существующем коде.
Ответ 4
Чтобы комплимент ответа от Шрирама Сактивеля - ключ к вашей проблеме состоит в том, что Тип не может быть выведен из того, что вы проходите. Стоит отметить, что List<T>
реализует IList
, поэтому ваш вопрос выше можно перерисовать с помощью массив параметров списка как:
void Main()
{
var fooList = new List<string>();
var barList = new List<string>();
var bazList = new List<string>();
ReverseLists(fooList, barList, bazList);
}
public static void ReverseLists(params IList [] sourceLists)
{
foreach (var sourceList in sourceLists)
{
MyReverse(sourceList);
}
}
public static void MyReverse(IList source)
{
var length = source.Count;
var hLength = length / 2;
for (var i = 0; i < hLength; i++)
{
var temp = source[i];
source[i] = source[length - 1 - i];
source[length - 1 - i] = temp;
}
}
Ответ 5
измените эту строку в исходном сообщении:
MyReverse(sourceList); // Error: Type arguments cannot be inferred from usage
:
MyReverse(((System.Collections.IList)sourceList).Cast<object>().ToList());