Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/flutter/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在字典和集合上自动添加索引器是一个好的设计决策吗?_C#_Collections_Dictionary_Indexing - Fatal编程技术网

C# 在字典和集合上自动添加索引器是一个好的设计决策吗?

C# 在字典和集合上自动添加索引器是一个好的设计决策吗?,c#,collections,dictionary,indexing,C#,Collections,Dictionary,Indexing,索引器何时可以自动将项目添加到集合/词典?这是合理的,还是与最佳实践相反 public class I { /* snip */ } public class D : Dictionary<string, I> { public I this[string name] { get { I item; if (!this.TryGetValue(name, out item))

索引器何时可以自动将项目添加到集合/词典?这是合理的,还是与最佳实践相反

public class I { /* snip */  }
public class D : Dictionary<string, I>
{
    public I this[string name]
    {
        get
        {
            I item;
            if (!this.TryGetValue(name, out item))
            {
                item = new I();
                this.Add(name, item);
            }
            return item;
        }
    }
}
公共类I{/*snip*/}
公共D类:字典
{
公共I此[字符串名称]
{
得到
{
I项目;
如果(!this.TryGetValue(名称,out项))
{
项目=新的I();
添加(名称、项目);
}
退货项目;
}
}
}
如何在集合中使用此选项的示例:

public class I
{
    public I(string name) {/* snip */}
    public string Name { get; private set; }
    /* snip */
}
public class C : Collection<I>
{
    private Dictionary<string, I> nameIndex = new Dictionary<string, I>();

    public I this[string name]
    {
        get
        {
            I item;
            if (!nameIndex.TryGetValue(name, out item))
            {
                item = new I(name);
                this.Add(item); // Will also add the item to nameIndex
            }
            return item;
        }
    }

    //// Snip: code that manages nameIndex 
    // protected override void ClearItems()
    // protected override void InsertItem(int index, I item)
    // protected override void RemoveItem(int index)
    // protected override void SetItem(int index, I item)
}
公共一级
{
公共I(字符串名){/*snip*/}
公共字符串名称{get;private set;}
/*剪断*/
}
公共C类:收藏
{
私有字典名称索引=新字典();
公共I此[字符串名称]
{
得到
{
I项目;
如果(!nameIndex.TryGetValue(名称,输出项))
{
项目=新I(名称);
this.Add(item);//还将该项添加到nameIndex
}
退货项目;
}
}
////Snip:管理名称索引的代码
//受保护的覆盖无效ClearItems()
//受保护的覆盖无效插入项(int索引,I项)
//受保护的覆盖void removietem(int索引)
//受保护的覆盖无效集合项(int索引,I项)
}

在没有其他关于你正在做什么的信息的情况下,我觉得这是一种令人惊讶的行为。我希望您能从上下文(即,将其命名为
autoinitializedictionary
或其他东西)中清楚地说明所期望的内容


我个人更愿意将其作为一种方法,而不是索引器;类似于
D.FindOrCreate
。(我觉得有一个惯用的名称来表示我暂时忘记了的方法。)

我认为只要这种行为被完全清楚地表达出来,它是完全好的。我有两个装饰师课程:

public class DefaultValueDictionary<K, V> : IDictionary<K, V>
{
  public DefaultValueDictionary(IDictionary<K, V> baseDictionary, Func<K, V> defaultValueFunc)
  {
    ...
  }
}

我认为这违反了两个原则。1) 最小意外原则。2)getter不应该改变任何事情

如果集合中不存在foo,我不希望在对{“foo”,null}中添加一个

x = collection["Foo"]

<>强>有两个问题你应该考虑——这两个问题都表明这是个坏主意。< /强>

首先,从.NET BCL集合类型继承通常不是一个好主意。这样做的主要原因是这些类型上的大多数方法(如
Add
Remove
)都不是虚拟的——如果您在派生类中提供自己的实现,那么如果您将集合作为基类型传递,它们将不会被调用。在您的例子中,通过隐藏
Dictionary
indexer属性,您正在创建一种情况,即使用基类引用的调用将执行与使用派生类引用的调用不同的操作。。。违反以下规定:

什么时候可以接受索引器 将项目自动添加到 收藏/字典

从来没有

这是合理的,还是与此相反 最佳实践

public class I { /* snip */  }
public class D : Dictionary<string, I>
{
    public I this[string name]
    {
        get
        {
            I item;
            if (!this.TryGetValue(name, out item))
            {
                item = new I();
                this.Add(name, item);
            }
            return item;
        }
    }
}
与最佳做法相反


也就是说,如果类的名称恰当,那么它是可以接受的。我个人会使用它。

我担心的主要原因是它不会是线程安全的。多个读者都试图一次写入字典,这需要仔细的锁管理,而这在一开始你可能不会想到(或得到正确的答案)。

我相信你正在寻找GetOrAdd(key,value)。这里是一个msdn示例,感谢所有反馈!我已经添加了一个示例,说明如何在集合中使用它。虽然到目前为止,实现集合的潜在问题较少,但我不确定它是否真的会更改任何参数。+1:有趣的是,注意到ASP.NET会话会执行类似的操作:如果你来自C++,你已经使用了STD::MAP,那么不增加密钥会违反最小的惊讶原则。这不是黑和白。@冰激凌我相信如果你从C++去C,你会很惊讶。
int count;
if(!dict.TryGetValue(key, out count))
  dict[count] = 1;
else dict[count] = count + 1;
x = collection["Foo"]
var derived = new D();
var firstItem = derived["puppy"]; // adds the puppy entry

var base = (Dictionary<string,I>)derived;
var secondItem = base["kitten"]; // kitten WAS NOT added .. BAD!
public static class DictionaryExtensions
{ 
    public static TValue FindOrAdd<TKey,TValue>( 
             this IDictionary<TKey,TValue> dictionary, TKey key, TValue value )
        where TValue : new()
    { 
        TValue value; 
        if (!this.TryGetValue(key, out value)) 
        { 
            value = new TValue(); 
            this.Add(key, value); 
        } 
        return value; 
    } 
}