Как создать общий метод расширения?

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

я имею в виду

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[].


person user215675    schedule 01.12.2009    source источник
comment
Наличие общего метода, который работает только со строками, на самом деле не имеет большого смысла...   -  person Jason Punyon    schedule 01.12.2009
comment
Почему он должен быть общим, если вы хотите упорядочить только строки?   -  person bniwredyc    schedule 01.12.2009
comment
@bniwredyc Потому что generic звучит круто! :)   -  person Arnis Lapsa    schedule 01.12.2009
comment
Вы также можете исправить ExtensionOperstion на ExtensionOperation   -  person Alex Bagnolini    schedule 01.12.2009


Ответы (6)


Первая ошибка связана с тем, что 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);
person Darin Dimitrov    schedule 01.12.2009
comment
Я обнаружил, что часто использую подобные методы lengthProvider с общим кодом. Это еще одна причина, по которой я так люблю лямбды. :D - person Greg D; 01.12.2009

Почему вы хотите сделать это в общем? Просто используйте

public static class ExtensionOperations
{
    public static IEnumerable<string> AlphaLengthWise(this string[] names)
    {
        var query = names.OrderBy(a => a.Length).ThenBy(a => a);
        return query;
    }
}
person Maximilian Mayerl    schedule 01.12.2009
comment
Почему string[], а не IEnumerable<String>? Вы можете удалить .ToArray() и оставить его отложенным (если я не ошибаюсь). - person Alex Bagnolini; 01.12.2009
comment
Это игнорирует вопрос и представляет решение совершенно другой проблемы. - person John Smith; 16.08.2019

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

Обобщения — это способ адаптировать класс или метод к определенному типу. Универсальный метод или класс предназначен для работы с любым типом. Это легче всего проиллюстрировать в классе 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> и многие другие.

person Paul Turner    schedule 01.12.2009

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

public static class ExtensionOperation
{
    public static IEnumerable<String> AplhaLengthWise(
                                   this IEnumerable<String> names)
    {
        return names.OrderBy(a => a.Length).ThenBy(a => a);
    }
}
person Alex Bagnolini    schedule 01.12.2009

Скопируйте, как это делает 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);
    }
}
person Christian Hayter    schedule 01.12.2009

Вы хотите использовать IEnumerable<T> вместо T[]. Кроме этого, вы не сможете использовать Length из T, так как не все типы имеют свойство Length. Вы можете изменить метод расширения на .OrderBy(a => a.ToString().Length)

Если вы знаете, что всегда будете иметь дело со строками, используйте IEnumerable<String>, а не IEnumerable<T>, и вы сразу сможете получить доступ к свойству Length.

person David Hedlund    schedule 01.12.2009
comment
Изменение T[] на IEnumerable‹T› не потребует свойства Length для элементов. - person Arnis Lapsa; 01.12.2009
comment
это точно не будет. эта часть ответа касалась второй ошибки. IOrderedEnumerable<T> реализует IEnumerable<T>, так что это решит эту часть проблемы. Что касается свойства Length, я предложил использовать ToString() для обеспечения строки или, если он новичок, он всегда будет иметь дело со строками, чтобы изменить T на string. - person David Hedlund; 01.12.2009