是否可以将通用方法应用于项目列表?

时间:2015-01-27 12:20:13

标签: c# generics

让我们说我已经编写了自己的方法来反转列表。

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方法?

5 个答案:

答案 0 :(得分:10)

假设您有一个像这样的静态方法

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>,你可以把它放回去。

答案 1 :(得分:7)

根据我上面的评论......

编译器在传递object时无法隐蔽推断T的类型(这实际上是正在发生的事情)

但是有一个更简单的选项 - 只是放弃使用泛型,并将MyReverse方法的签名更改为public static void MyReverse(IList source)(以及其他地方用List<object>替换IList < / p>

即:

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
{
}

答案 2 :(得分:2)

如果您将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);

对于每个列表类型,可能不一定要调用一次,但对现有代码进行相对较小的更改。

答案 3 :(得分:2)

赞美Sriram Sakthivel的答案 - 问题的关键在于无法从传入的内容中推断出类型。值得注意的是List<T>实现了IList因此您的问题可以解决使用List的参数数组重新构建,如:

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;
    }
}

答案 4 :(得分:0)

在原帖中更改此行:

MyReverse(sourceList); // Error: Type arguments cannot be inferred from usage

到此:

MyReverse(((System.Collections.IList)sourceList).Cast<object>().ToList());