Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/22.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#_.net - Fatal编程技术网

字典值c#

字典值c#,c#,.net,C#,.net,如果我们在.Net中对字典进行循环,它是无法更改的。但是为什么字典中的值是只读的呢。有人有什么想法吗?。为什么.Net团队决定在遍历字典时不更改值。我可以理解,如果密钥不能更改,为什么要更改值?。 另外,如果您使用LINQ并以Ienumerable的形式获取密钥,那么该值可以更改吗?。延迟加载有作用吗?KeyValuePair是一个结构,而可变结构是邪恶的,因此它被设置为只读 要更改某些值,可以迭代KeyValuePairs并存储所有要进行的更新。完成迭代后,您可以循环更新列表并应用它们。下面是

如果我们在.Net中对字典进行循环,它是无法更改的。但是为什么字典中的值是只读的呢。有人有什么想法吗?。为什么.Net团队决定在遍历字典时不更改值。我可以理解,如果密钥不能更改,为什么要更改值?。
另外,如果您使用LINQ并以Ienumerable的形式获取密钥,那么该值可以更改吗?。延迟加载有作用吗?

KeyValuePair是一个结构,而可变结构是邪恶的,因此它被设置为只读

要更改某些值,可以迭代KeyValuePairs并存储所有要进行的更新。完成迭代后,您可以循环更新列表并应用它们。下面是一个示例,说明了如何做到这一点(不使用LINQ):

Dictionary dict=new Dictionary();
dict[“foo”]=“bar”;
dict[“baz”]=“qux”;
列表更新=新列表();
foreach(dict中的KeyValuePair kvp)
{
if(kvp.Key.Contains(“o”))
添加(新的KeyValuePair(kvp.Key,kvp.Value+“!”));
}
foreach(更新中的KeyValuePair kvp)
{
dict[kvp.Key]=kvp.Value;
}

我不知道为什么,但您可以通过间接引用值来绕过此限制。例如,您可以创建一个简单引用另一个类的类,如下所示:

class StrongRef<ObjectType>
{
    public StrongRef(ObjectType actualObject)
    {
        this.actualObject = actualObject;
    }

    public ObjectType ActualObject
    {
        get { return this.actualObject; }
        set { this.actualObject = value; }
    }

    private ObjectType actualObject;
}
类StrongRef
{
公共StrongRef(对象类型actualObject)
{
this.actualObject=actualObject;
}
公共对象类型ActualObject
{
获取{返回this.actualObject;}
设置{this.actualObject=value;}
}
私有对象类型actualObject;
}
然后,您可以改变间接引用,而不是改变DICITORY中的值。(我听说Blue Peter使用以下程序将死去的狗替换为长相相同的活动物,这是有根据的。)

public void replace deaddogs()
{
foreach(dogsByName中的KeyValuePair名称DDOG)
{
字符串名称=namedDog.Key;
StrongRef dogRef=namedDog.值;
//更新间接引用
dogRef.ActualObject=PurchaseNewDog();
}
}
其他替代方法是在迭代时将必要的更改记录在第二个字典中,然后应用这些更改(通过迭代第二个字典),或者在循环完成后,在迭代并使用该字典而不是原始字典的同时构建一个完整的替换字典。

(基于哈希表,但同样适用)

这里的关键是枚举数是 旨在提供 整个系列,但为了性能 为什么他们不复制整个 集合到另一个临时数组 或者诸如此类的事情。相反,他们 使用live collection并抛出 如果他们发现有人,就会有例外 更改了收藏。是的,它使 这种类型的代码更难编写

为什么BCL团队决定在循环字典时不允许更改值。我知道密钥不能更改,但为什么不允许更改值

我不能肯定地为编纂词典的团队说话,但我可以做出一些有根据的猜测

首先,人们常说,好的程序严格要求其输出的正确性,但对其接受的内容宽容。我不认为这是一个好的设计原则。这是一个糟糕的设计原则,因为它允许有缺陷的调用程序依赖于未定义和不受支持的行为。因此,它创建了一个向后兼容的设计原则可扩展性负担。(我们在web浏览器世界中当然看到了这一点,每个浏览器供应商都被迫与其他浏览器接受错误HTML的情况兼容。)

组件定义合同——它们表示接受哪些信息作为输入,支持哪些操作,以及产生哪些结果。当您接受合同中没有的输入,或者支持合同中没有的操作时,您所做的基本上是制定一个新合同,一个没有记录的合同,而不是支持你基本上是在制造一个定时炸弹,当它爆炸时,要么是客户(他们可能甚至不知道他们正在做不受支持的事情)被破坏,要么是组件提供商最终不得不永远支持他们实际上没有签署的合同

因此,严格执行契约是一个好的设计原则。集合上IEnumerable的契约是“在迭代时修改集合是非法的”。该契约的实现者可以选择说“好吧,我碰巧知道某些修改是安全的,所以我允许这些”,嘿,突然之间,你不再执行合同了。你执行的是一个不同的,没有文件的合同,人们会依赖它

最好是简单地强制执行合同,即使这是不必要的。这样,在未来,你可以自由地依赖你的书面合同,而不必担心有人违反合同并逃脱惩罚,并希望能够永远这样做

设计一个允许在迭代过程中改变值的字典是很容易的。这样做会阻止组件提供者关闭该功能,而且他们也不需要提供该功能,因此,当有人尝试时,最好给出一个错误,而不是允许调用方违反合同

第二种猜测:字典类型是未密封的,因此可以扩展。第三方可能会以这样的方式扩展字典,即如果在枚举过程中更改了某个值,则会违反其不变量。例如,假设有人以这样的方式扩展字典,即可以按值排序对其进行枚举

当你写一个用词的方法时
class StrongRef<ObjectType>
{
    public StrongRef(ObjectType actualObject)
    {
        this.actualObject = actualObject;
    }

    public ObjectType ActualObject
    {
        get { return this.actualObject; }
        set { this.actualObject = value; }
    }

    private ObjectType actualObject;
}
public void ReplaceDeadDogs()
{
    foreach (KeyValuePair<string, StrongRef<Dog>> namedDog in dogsByName)
    {
        string name = namedDog.Key;
        StrongRef dogRef = namedDog.Value;

        // update the indirect reference
        dogRef.ActualObject = PurchaseNewDog();
    }
}
var bobs = from item in items where item.Name == "Bob" select item;
foreach(var bob in bobs) ...