【问题标题】:Make a Dictionary method argument default to an empty dictionary instead of null使 Dictionary 方法参数默认为空字典而不是 null
【发布时间】:2014-11-18 11:44:19
【问题描述】:

我有一个Dictionary<string, string> 作为方法参数,我想知道是否有办法让它默认为空字典而不是null。我更喜欢总是有一个空列表/字典/IEnumerable 而不是null。我尝试将参数设置为:

Dictionary<string, string> dictionary = default(Dictionary<string,string>);

但计算结果为null

有没有办法让默认字典为空?

【问题讨论】:

  • 不,你不能。如果您使用可选参数,默认参数的值应该是编译时间常量
  • 你的问题有点不清楚.. 为什么不直接使用if (dictionary == null){ dictionary = new Dictionary&lt;string, string&gt;(); } - 意图很明确,调用者不介意,没有扩展,没有覆盖行为.. 为什么要复杂化?跨度>
  • 我将“参数”更改为“参数”顺便说一句,我认为这就是你的意思。请参阅What's the difference between an argument and a parameter? 了解区别
  • 感谢大家的cmets。我想我会使用空检查或方法重载。我什至问这个问题的原因是我完全同意这篇文章 (blog.mariusschulz.com/2014/07/02/stop-cheating-the-type-system) 和其中的这句话(“如果你返回一个空的 IEnumerable 而不是一个空的,我会来你的房子然后用火箭筒射击你的脸。”)Null 是可能存在的最糟糕的默认值,叹息......
  • 任何引用类型的“默认”值为空。默认运算符不知道如何构造对象。您正在寻找的是 null 安全性,并且在 C# 中不存在。

标签: c# dictionary default


【解决方案1】:

有没有办法让默认字典为空?

是的,使用构造函数代替default

void Foo(Dictionary<string, string> parameter){
    if(parameter == null) parameter = new Dictionary<string,string>();
}

您也可以将参数设为可选:

void Foo(Dictionary<string, string> parameter = null)
{
    if(parameter == null) parameter = new Dictionary<string,string>();
}

optional parameter 必须是编译时常量,所以不能直接使用new Dictionary&lt;string,string&gt;()


根据问题是否可以更改 default 关键字的行为,不,您不能返回不同的值。对于引用类型,null 是默认值,将被返回。

C#language specs.§12.2:

变量的默认值取决于变量的类型,确定如下:

  • 对于 value-type 的变量,默认值与 value-type 计算的值相同 默认构造函数(§11.1.2)。
  • 对于引用类型的变量,默认值为 null

更新:不管怎样,你可以使用这个扩展(我不会使用它):

public static T EmptyIfNull<T>(this T coll) 
    where T :  ICollection, new() // <-- Constrain to types with a default constructor and collections
{
    if(coll == null)
        return new T();
    return coll;
}

现在你可以这样使用它了:

Dictionary<string, string> parameter = null;
Foo(parameter.EmptyIfNull());  // now an empty dictionary is passed

但另一个程序员最不想看到的是成千上万行代码,到处都是.EmptyIfNull(),因为第一个人懒得使用构造函数。

【讨论】:

  • 我会将它与空合并运算符结合起来。
  • @DanielA.White 我不会。你为什么要?这个答案中的内容很容易阅读。 parameter = parameter ?? new Dictionary&lt;string,string&gt;(); 冗余地将 parameter 的先前值重新分配给自己,让读者想知道为什么会发生这种情况。
  • 请注意,由于 OP 有兴趣使 Foo() 工作,除了函数体内的参数检查之外,这还需要一个 Foo(Dictionary&lt;string, string&gt; parameter = null) 默认值,而不是替换为内部的参数检查函数体。
  • @hvd:我提供了另一种方法让Foo“工作”,而无需更改方法体中的字典。
  • @TimSchmelter 像你一样,我不会使用它。 :) 不过,我认为这不是 OP 所追求的:OP 要求默认值,因此调用者不会指定任何参数值。您的 EmptyIfNull 将强制调用者编写 default(Dictionary&lt;string, string&gt;).EmptyIfNull() 或添加一个本地未使用的变量。但也许我误解了这个问题。我根据自己对问题的理解发布了不同的答案。
【解决方案2】:

考虑一下,使用任何参数的简单方法,如果你想给它一个不是编译时常量的默认值,这里就可以工作:不要给它一个默认值。请改用重载函数。

public void Foo() {
  Foo(new Dictionary<string, string>());
}

public void Foo(Dictionary<string, string> dictionary) {
  ...
}

对于调用者来说,如何实现并不重要:重要的是调用Foo() 编译并且在运行时具有与Foo(new Dictionary&lt;string, string&gt;()) 完全相同的效果,对吧?嗯,这正是通过添加重载实现的。

【讨论】:

    【解决方案3】:

    你可以这样做:

    经典实现

    public void Foo(Dictionary<string, string> dictionary)
    {
        if (dictionary == null)
        {
            dictionary = Enumerable.Empty<string>().ToDictionary(_ => string.Empty);
        }
    }
    

    如果您使用的是 C# 8.0 及更高版本

    public void Foo2(Dictionary<string, string> dictionary)
    {
        dictionary ??= Enumerable.Empty<string>().ToDictionary(_ => string.Empty);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-01-31
      • 1970-01-01
      • 2013-12-29
      • 2012-12-29
      • 2021-08-14
      • 1970-01-01
      • 2017-10-15
      • 1970-01-01
      相关资源
      最近更新 更多