Как создать общий метод расширения?
Я хочу разработать универсальный метод расширения, который должен упорядочить строку в алфавитном порядке, а затем по длине в порядке возрастания.
Я имею в виду
string[] names = { "Jon", "Marc", "Joel",
"Thomas", "Copsey","Konrad","Andrew","Brian","Bill"};
var query = names.OrderBy(a => a.Length).ThenBy(a => a);
Каков способ разработки универсального метода расширения?
Я пробовал:
public static class ExtensionOperation
{
public static T[] AlphaLengthWise<T>(this T[] names)
{
var query = names.OrderBy(a => a.Length).ThenBy(a => a);
return query;
}
}
Я получил:
Ошибка 1: T не содержит определения длины
Ошибка 2: невозможно преобразовать System.Linq.IOrderedEnumerable
в T[]
.
Ответы
Ответ 1
Первая ошибка заключается в том, что Length
является свойством класса String
, а в вашей общей версии тип параметра T неизвестен. Это может быть любой тип.
Вторая ошибка заключается в том, что вы возвращаете объект запроса, а не фактический результат. Возможно, вам придется вызвать ToArray()
перед возвратом.
С небольшими изменениями вы можете придумать следующее:
public static class ExtensionOperation
{
public static IEnumerable<T> AlphaLengthWise<T, L>(
this IEnumerable<T> names, Func<T, L> lengthProvider)
{
return names
.OrderBy(a => lengthProvider(a))
.ThenBy(a => a);
}
}
Что вы можете использовать следующим образом:
string[] names = { "Jon", "Marc", "Joel", "Thomas", "Copsey", "Konrad", "Andrew", "Brian", "Bill" };
var result = names. AlphaLengthWise(a => a.Length);
Ответ 2
Почему вы хотите сделать это в общем? Просто используйте
public static class ExtensionOperations
{
public static IEnumerable<string> AlphaLengthWise(this string[] names)
{
var query = names.OrderBy(a => a.Length).ThenBy(a => a);
return query;
}
}
Ответ 3
Я думаю, вы можете немного смутить цель дженериков.
Generics - это способ адаптировать класс или метод к определенному типу. Общий метод или класс предназначены для работы для любого типа. Это наиболее легко проиллюстрировано в классе List<T>
, где его можно настроить как список любого типа. Это дает вам тип безопасности, зная, что список содержит только этот тип.
Ваша задача предназначена для работы с определенным типом типа string
. Дженерики не собираются решать проблему, которая связана с определенным типом.
Что вы хотите - это простой (не общий) метод расширения:
public static class ExtensionOperations
{
public static IEnumerable<string> AlphaLengthWise(
this IEnumerable<string> names)
{
if(names == null)
throw new ArgumentNullException("names");
return names.OrderBy(a => a.Length).ThenBy(a => a);
}
}
Создание аргумента и возвращаемого типа IEnumerable<string>
делает этот метод универсальным расширением, который может применяться к любому типу, реализующему IEnumerable<string>
. Это будет включать string[]
, List<string>
, ICollection<string>
, IQueryable<string>
и многие другие.
Ответ 4
Почему вы хотите, чтобы он был общим?
Это будет работать только тогда, когда T
имеет свойство Length, и для этого вам понадобится интерфейс.
Кроме того, T должен быть IComparable.
Ответ 5
Я хочу разработать универсальный метод расширения, который должен расположить строки в алфавитном порядке, тогда...
public static class ExtensionOperation
{
public static IEnumerable<String> AplhaLengthWise(
this IEnumerable<String> names)
{
return names.OrderBy(a => a.Length).ThenBy(a => a);
}
}
Ответ 6
Скопируйте, как это делает Microsoft:
public static class ExtensionOperation {
// Handles anything queryable.
public static IOrderedQueryable<string> AlphaLengthWise(this IQueryable<string> names) {
return names.OrderBy(a => a.Length).ThenBy(a => a);
}
// Fallback method for non-queryable collections.
public static IOrderedEnumerable<string> AlphaLengthWise(this IEnumerable<string> names) {
return names.OrderBy(a => a.Length).ThenBy(a => a);
}
}
Ответ 7
Вы хотите использовать IEnumerable<T>
вместо T[]
. Кроме того, вы не сможете использовать Length
для T
, так как не все типы имеют свойство Length
. Вы можете изменить свой метод расширения на .OrderBy(a => a.ToString().Length)
Если вы знаете, что всегда будете иметь дело со строками, используйте IEnumerable<String>
, а не IEnumerable<T>
, и вы сразу получите доступ к свойству Length
.