使用object和list <object>参数</object>重载两个函数

时间:2013-08-21 12:15:25

标签: c#

考虑以下代码:

static void Main(string[] args)
    {
        Log("Test");//Call Log(object obj)
        Log(new List<string>{"Test","Test2"});;//Also Call Log(object obj)
    }

    public static void Log(object obj)
    {
        Console.WriteLine(obj);
    }

    public static void Log(List<object> objects)
    {
        foreach (var obj in objects)
        {
            Console.WriteLine(obj);
        }
    }  

在第一行中,我使用字符串值调用log并调用Log(object obj),但在第二行中,我使用字符串Log的列表调用new List<string>{"Test","Test2"},但编译器调用Log(object obj)而不是Log(List<object> objects)

为什么编译器有这种行为?

如何使用字符串列表调用第二个日志?

4 个答案:

答案 0 :(得分:29)

List<string> 不是 a List<object>;但是,List<string> object - 因此选择超载非常有意义。请尝试改为:

public static void Log<T>(IList<T> objects)
{
    foreach (var obj in objects)
    {
        Console.WriteLine(obj);
    }
}  

甚至:

public static void Log<T>(IEnumerable<T> objects)
{
    foreach (var obj in objects)
    {
        Console.WriteLine(obj);
    }
}  

您可能也喜欢:

public static void Log(params object[] objects)
{
    foreach (var obj in objects)
    {
        Console.WriteLine(obj);
    }
}

可以用作:

Log("Test","Test2");

答案 1 :(得分:7)

Marc Gravell答案的变体:

public static void Log(IReadOnlyList<object> objects)
{
    foreach (var obj in objects)
    {
        Console.WriteLine(obj);
    }
}

这不会向此特定示例添加任何内容,但如果您希望使用对List<T>的索引访问权限,则可以IEnumerable<object>的方式执行此操作没有。 (是的,有一个LINQ运算符用于对可枚举的索引访问,但它很笨拙,也可能非常慢。IReadOnlyList<object>非常有用,如果你想明确你的方法需要有效的索引访问。)

与使用IEnumerable<object&gt;的Marc版本一样作为参数类型,这会利用协方差 - 与List<T>不同,TIEnumerable<T>IReadOnlyList<T>中是协变的。这意味着,因为stringobjectIEnumerable<string>IEnumerable<object>,同样,IReadOnlyList<string>IReadOnlyList<object>

两个接口的只读性质很重要。原始示例失败的全部原因是List<T>支持阅读和写作 - 如果您传递给我List<object>我可以添加任何内容 - stringGiraffe或者我喜欢什么。这就是为什么List<string>不能替代List<object>的原因 - 我无法向Giraffe添加List<string>,即使我可以将List<object>添加到IEnumerable<T> 1}}。但是因为IReadOnlyList<T>string不允许将对象添加到它们代表的集合中,所以重要的是你可以得到的东西,而不是你可以放入的东西。任何来自集合的东西仅包含object个对象的内容为object,因为所有内容都为IReadOnlyList<object>

是的,我知道您的原始代码并未尝试向列表中添加任何内容,但这并不重要 - 在这种情况下,所有C#都关心函数签名的外观。通过指定List<string>,您明确表示您永远不会尝试修改列表,此时C#知道可以通过{{1}}。

答案 2 :(得分:3)

List<string>无法投放到List<Object>。 如果您有List<Object>,则可以向其添加任何类型的对象。 如果您有List<String>,则只能为其添加字符串。 因此,List<String>无法转换为List<Object>,因为它不能以相同的方式使用。

答案 3 :(得分:1)

我想这是Liskov Substitution Principal的一个很好的例子。 LSP在其简单的解释中声称,如果动物可以咬人,那么一只狗(它是一种动物)也应该能够咬人。

这就像逻辑中的三段论,其中指出:

  1. 所有动物都吃
  2. 牛是一种动物
  3. 因此,牛吃
  4. 我想在这里,编译器遵循这个原则,因为:

    1. 可以记录所有对象(public void Log (object obj) {}
    2. List<string>是一个对象
    3. 因此List<string>可以用作该方法的参数,并进行记录。