Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/311.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# 如何使此字典TryGetValue代码更具可读性?_C#_.net_Dictionary_Trygetvalue - Fatal编程技术网

C# 如何使此字典TryGetValue代码更具可读性?

C# 如何使此字典TryGetValue代码更具可读性?,c#,.net,dictionary,trygetvalue,C#,.net,Dictionary,Trygetvalue,我想测试一个id是否未知,或者,如果已知,关联的值是否已更改。我目前正在使用类似的代码,但对于那些不熟悉该模式的人来说,这很难理解。你能想出一种方法,使它更可读,同时保持简短的LOC string id; string actual; string stored; if (!someDictionary.TryGetValue (id, out stored) || stored != actual) { // id not known yet or associated value

我想测试一个id是否未知,或者,如果已知,关联的值是否已更改。我目前正在使用类似的代码,但对于那些不熟悉该模式的人来说,这很难理解。你能想出一种方法,使它更可读,同时保持简短的LOC

string id;
string actual;
string stored;

if (!someDictionary.TryGetValue (id, out stored) || stored != actual) {
    // id not known yet or associated value changed.
}

所以我很可能会把它拆开,给它起个有意义的名字。这是更多的阅读,但你不需要在评论中说太多:

bool isKnown = someDictionary.TryGetValue (id, out stored);
// can only change when it is known
bool valueChanged = isKnown && stored != actual;

// quite self-explanatory, isn't it?
if (!isKnown || valueChanged) 
{

}
二元性

if (!(someDictionary.TryGetValue (id, out stored) && stored == actual)) ...

但不确定它是否更具可读性。。。但知道这一点很好。

将| |的每个部分都封装到它自己的方法或属性中,这样就可以这样编写了

if ( IdIsNew() || IdChanged())

我更喜欢一种新方法:

public bool ShouldSetValue(Dictionary someDictionary, object id,object actualValue)
{
    string stored;

    if (someDictionary.TryGetValue (id, out stored)) 
    {
        if (stored != actualValue)
            return true;
    }
    else
    {
        return true;
    }
}
在现有方法中,我只需:

if (ShouldSetValue(someDictionary,id,actual))
{
     someDictionary[id]=actual;
}

您可以编写具有良好名称的扩展方法:

public static class Utility
{
    public static bool ValueChangedOrUnknown(this Dictionary<string, string> dictionary, string id, string actual)
    {
        string stored = null;
        return (!dictionary.TryGetValue(id, out actual) || stored != actual);
    }
}

一种扩展方法应该是灵活的:

public static class DictionaryExtensions
{
    public static bool ShouldAddValue<TKey, TValue>(this Dictionary<TKey, TValue> someDictionary, TKey id, TValue actual)
    {
        TValue stored;
        return (!someDictionary.TryGetValue(id, out stored) || !stored.Equals(actual)); 
    }
}

如果您的意思是必须重复执行此操作,而且它又长又难看,请将逻辑抽象到另一个类并使用扩展方法

public static class DictionaryExtensions
{
    public static DictionaryChecker<TKey,TValue> contains<TKey,TValue>(this IDictionary<TKey,TValue> dictionary, TValue value)
    {
        return new DictionaryChecker<TKey,TValue>(value, dictionary);
    }
}

public class DictionaryChecker<TKey,TValue>
{
    TValue value;
    IDictionary<TKey,TValue> dictionary;

    internal DictionaryChecker(TValue value, IDictionary<TKey, TValue> dictionary)
    {
        this.value = value;
        this.dictionary = dictionary;
    }

    public bool For(TKey key)
    {
        TValue result;
        return dictionary.TryGetValue(key, out result) && result.Equals(value);
    }
}

它看起来很好…读起来和任何其他2条件if语句一样简单。关于我唯一可能改变的事情是翻转否定,以便尽早退出:

if (someDictionary.TryGetValue(id, out stored) && stored == actual) {
    return;
}
// store new value
我一点也不觉得它有什么混乱,也从来没有想过它是一个特别麻烦的习语,我谦恭地建议那些被它弄糊涂的C#dev习惯它。它是通用的、简洁的,并且为问题提供了尽可能多的解决方法。把它转换成10行代码就太重要了


如果我经常使用它,一个名为
ContainsEqualValue
的扩展方法将是合适的-但是我会在扩展方法中使用与您完全相同的代码

虽然我认识到“try”模式是必要的,但我不喜欢需要“out”参数的实现。如果具有与TryGetValue类似的功能,则似乎更有用:

public T GetValue(int id, object actual)
{
  object stored;
 if (someDictionary.TryGetValue (id, out stored) || stored == actual) 
    return stored;
  return new object();
}
  • 如果键不在字典中,TryGetDictValue(字典,键)返回null
  • TryGetDictValue(dictionary、key、defaultValue)如果key不在dictionary中,则返回defaultValue
  • TryGetDictValue(dictionary、key、valueReturningDelegate)在键不在dictionary中时调用提供的委托并返回其结果
在任何情况下,结果的返回类型都是字典数据的返回类型


很遗憾,没有办法潜入时间机器,把这些东西变成字典里的方法。另一方面,可以将它们实现为静态函数,并将字典作为第一个参数。

它已初始化,
out
关键字与运算符优先级规则相结合可确保。必须在函数内部设置out参数,以便TryGetValue初始化它。
存储的
始终在调用
TryGetValue
后初始化。这是
out
参数的规则。显然,它不是一个有效的值。很好,这是编写代码的方式。我不必了解细节就可以立即了解发生了什么。@mafurtct:不,性能并不差,当isKnown为false时,不会比较值,这由&&运算符确保,-1表示不可读。我很难理解和修正这些陈述。特别是,因为
存储的
输出的
,所以在同一语句中使用它。你强迫我读每一个元素来理解发生了什么。@AMissico:如果你不读一段代码中的每一个元素,那么你怎么能确定你理解发生了什么?@LukeH:这正是为什么我讨厌人们写大量代码,但却做得很少的原因。@LukeH:你读每一个字吗?不,我们略读,了解基本情况。当这个方法失败时,我们会读到。
AddValue
是一个可怕的名称,它实际上并没有做任何事情/改变任何事情
CanadValue
可能是个更好的名字。好主意。也许是字典的一种扩展方法?而且这个名字很奇怪。大家都同意这个名字很奇怪。换了。是的,你可以把它作为字典上的一个扩展方法来实现,这可能会使它变得更好…为什么不
HasValue
KeyHasValue
?@AMissico,因为它不仅检查它是否有值,而且如果它有值,它会将该值与另一个值进行比较,看看值是否不同。所以这是一个函数,看看我们是否应该设置值,所以也许应该设置值会更好……我不会创建新方法,除非它们能够消除任何潜在的错误。如果增加可读性和维护性,我会创建新方法。我讨厌“out”参数,我通常用扩展方法包装对TryGetValue的任何访问(例如,tryGetValuerDefault直接返回条目,如果找不到条目,则返回null或0)。它与任何2条件语句都不太一样,因为它需要预先声明
out
参数。“…习惯了吗?”从本质上讲,开发人员并不是“困惑”的。即使是一个从左到右阅读的资深程序员,也必须反复阅读这篇文章,并在这样做的同时在头脑中处理好几个元素。这不是一项艰巨的任务,但也不是自然的。这在某种程度上是程序性代码,并引入了重复和错误的机会。可读性是一个合理的问题,带有
bool
结果的
TryGetValue
在语义上很弱。@Jay:为什么要检查out变量的声明?很明显,它就在那里(或者编译器会抱怨),并且您不应该关心该值在前面是什么(因为它是out参数,函数不使用该值)。这真的是关于
out
而不是条件的吗?关于这句话,我唯一要承认的一点是:1.)副作用在条件句中,2.)条件句是顺序相关的
booltry*(out)
是BCL中的一个很好的习惯用法,我希望开发人员能够理解,所以我原谅第一个。@Jay:你的评论是“spot”
if(!someDictionary.contains(actual).For(id)){
    // id not known yet or associated value changed.
}
if (someDictionary.TryGetValue(id, out stored) && stored == actual) {
    return;
}
// store new value
public T GetValue(int id, object actual)
{
  object stored;
 if (someDictionary.TryGetValue (id, out stored) || stored == actual) 
    return stored;
  return new object();
}