如何创建通用扩展方法?


75

我想开发一种通用扩展方法,该方法应按字母顺序排列字符串,然后按纵向升序排列。

我的意思是

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


3
拥有只对字符串起作用的通用方法实际上并没有多大意义……
Jason Punyon

4
如果只想排列字符串,为什么要通用?
bniwredyc

6
@bniwredyc因为generic听起来很酷!:)
Arnis Lapsa

你可能也想正确的ExtensionOperstionExtensionOperation
亚历Bagnolini

Answers:


107

第一个错误是因为LengthString类的属性,而在通用版本中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);

1
我发现自己lengthProvider在通用代码中经常使用这种技术。这就是我这么爱lambda的另一个原因。:D
格雷格D

14

为什么要一般地这样做?只需使用

public static class ExtensionOperations
{
    public static IEnumerable<string> AlphaLengthWise(this string[] names)
    {
        var query = names.OrderBy(a => a.Length).ThenBy(a => a);
        return query;
    }
}

4
为什么string[]IEnumerable<String>呢?您可以删除.ToArray()并将其推迟(如果我没有记错的话)。
Alex Bagnolini

1
这忽略了问题,并提出了一个完全不同的问题的解决方案
John Smith,

7

我认为您可能对泛型的目的有些困惑。

泛型是一种将类或方法定制为特定类型的方法。通用方法或类旨在用于任何类型。这在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>等等。


2

我想开发一种通用扩展方法,该方法应按字母顺序排列字符串,然后...

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

1

复制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);
    }
}

0

您要使用IEnumerable<T>而不是T[]。除此之外,你将无法使用LengthT,因为不是所有的类型有一个Length属性。您可以将扩展方法修改为.OrderBy(a => a.ToString().Length)

如果您知道您将一直在处理字符串,请使用IEnumerable<String>而不是IEnumerable<T>,您将能够Length立即访问该属性。


将T []更改为IEnumerable <T>不需要元素的Length属性。
阿尼斯·拉普萨(09年

它肯定不会。答案的一部分与第二个错误有关。IOrderedEnumerable<T>实现IEnumerable<T>,这样就可以解决那部分问题。至于Length属性,我的建议是ToString()用来确保字符串,或者,如果他是新来的,他总是会处理字符串,则改为T使用string
David Hedlund
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.