C# “合并”;选中“添加或获取”;从字典
我厌倦了字典里的这个成语:C# “合并”;选中“添加或获取”;从字典,c#,collections,syntax,dictionary,extension-methods,C#,Collections,Syntax,Dictionary,Extension Methods,我厌倦了字典里的这个成语: Dictionary<Guid,Contact> Contacts; //... if (!Contacts.ContainsKey(id)) { contact = new Contact(); Contacts[id] = contact; } else { contac
Dictionary<Guid,Contact> Contacts;
//...
if (!Contacts.ContainsKey(id))
{
contact = new Contact();
Contacts[id] = contact;
}
else
{
contact = Contacts[id];
}
字典联系人;
//...
如果(!Contacts.ContainsKey(id))
{
触点=新触点();
联系人[id]=联系人;
}
其他的
{
联系人=联系人[id];
}
如果有一种语法允许在默认构造函数不存在的情况下从默认构造函数隐式创建新值(字典毕竟知道值的类型),那就太好了。有人见过这样做的助手(例如扩展方法)吗?实现:
public static TValue GetOrAdd<TKey, TValue>(this IDictionary<TKey, TValue> dictionary,
TKey key, Func<TValue> valueCreator)
{
TValue value;
if (!dictionary.TryGetValue(key, out value))
{
value = valueCreator();
dictionary.Add(key, value);
}
return value;
}
public static TValue GetOrAdd<TKey, TValue>(this IDictionary<TKey, TValue> dictionary,
TKey key) where TValue : new()
{
return dictionary.GetOrAdd(key, () => new TValue());
}
var contacts = new Dictionary<Guid, Contact>();
Guid id = ...
contacts.GetOrAdd(id).Name = "Abc"; // ok since Contact has public parameterless ctor
contacts.GetOrAdd(id, () => new Contact { Name = "John Doe" }).Age = 40;
publicstatictvalue GetOrAdd(这个IDictionary字典,
TKey键,Func valueCreator)
{
t价值;
if(!dictionary.TryGetValue(键,输出值))
{
value=valueCreator();
添加(键、值);
}
返回值;
}
公共静态TValue GetOrAdd(此IDictionary dictionary,
TKey键)其中TValue:new()
{
返回dictionary.GetOrAdd(key,()=>newtValue());
}
用法:
public static TValue GetOrAdd<TKey, TValue>(this IDictionary<TKey, TValue> dictionary,
TKey key, Func<TValue> valueCreator)
{
TValue value;
if (!dictionary.TryGetValue(key, out value))
{
value = valueCreator();
dictionary.Add(key, value);
}
return value;
}
public static TValue GetOrAdd<TKey, TValue>(this IDictionary<TKey, TValue> dictionary,
TKey key) where TValue : new()
{
return dictionary.GetOrAdd(key, () => new TValue());
}
var contacts = new Dictionary<Guid, Contact>();
Guid id = ...
contacts.GetOrAdd(id).Name = "Abc"; // ok since Contact has public parameterless ctor
contacts.GetOrAdd(id, () => new Contact { Name = "John Doe" }).Age = 40;
var contacts=newdictionary();
Guid id=。。。
contacts.GetOrAdd(id).Name=“Abc”//由于Contact具有公共无参数ctor,因此ok
contacts.GetOrAdd(id,()=>新联系人{Name=“John Doe”}).Age=40;
与Ani的答案相同,但用一句更难以理解的话:)
///昂贵的值创建者函数。
public static T GetOrAdd(此IDictionary dict,S key,Func valueCreator)
{
返回dict.TryGetValue(key,out var value)?value:dict[key]=valueCreator();
}
提供一个委托作为值创建者,而不是值本身,以防止不必要的对象创建
字典,不幸的是,.你总是可以滚动你自己的字典 解决方案1:继承并使用“新”重写方法,首先检查是否包含密钥。如果是,则通过键返回该值或通过
Func<K, T>
Func
代表。但是,当通过接口使用此字典时,此解决方案将中断
IDictionary<K,T>
IDictionary
因此,您需要通过解决方案2更彻底地了解这一点
解决方案2:使用内部字典的字典包装器-其余与解决方案1相同
解决方案3:ConcurrentDictionary提供了GetOrAdd,它也是线程安全的
解决方案4:与解决方案2类似的ConcurrentDictionary包装器
这是一个字典包装器:
public class WrappedDictionary<K, T> : IDictionary<K, T>
{
public IDictionary<K, T> WrappedInstance { get; set; }
public virtual T this[K key]
{
get
{
// CUSTOM RESOLUTION CODE GOES HERE
return this.WrappedInstance[key];
}
set
{
this.WrappedInstance[key] = value;
}
}
public int Count
{
get
{
return this.WrappedInstance.Count;
}
}
public bool IsReadOnly
{
get
{
return this.WrappedInstance.IsReadOnly;
}
}
public ICollection<K> Keys
{
get
{
return this.WrappedInstance.Keys;
}
}
public ICollection<T> Values
{
get
{
return this.WrappedInstance.Values;
}
}
public void Add(KeyValuePair<K, T> item)
{
this.WrappedInstance.Add(item);
}
public void Add(K key, T value)
{
this.WrappedInstance.Add(key, value);
}
public void Clear()
{
this.WrappedInstance.Clear();
}
public bool Contains(KeyValuePair<K, T> item)
{
return this.WrappedInstance.Contains(item);
}
public bool ContainsKey(K key)
{
return this.WrappedInstance.ContainsKey(key);
}
public void CopyTo(KeyValuePair<K, T>[] array, int arrayIndex)
{
this.WrappedInstance.CopyTo(array, arrayIndex);
}
public IEnumerator<KeyValuePair<K, T>> GetEnumerator()
{
return this.WrappedInstance.GetEnumerator();
}
public bool Remove(KeyValuePair<K, T> item)
{
return this.WrappedInstance.Remove(item);
}
public bool Remove(K key)
{
return this.WrappedInstance.Remove(key);
}
public bool TryGetValue(K key, out T value)
{
// CUSTOM RESOLUTION CODE GOES HERE
return this.WrappedInstance.TryGetValue(key, out value);
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.WrappedInstance.GetEnumerator();
}
}
公共类WrappedDictionary:IDictionary
{
公共IDictionary包装状态{get;set;}
公共虚拟T此[K密钥]
{
得到
{
//自定义解析代码在这里
返回此.WrappedInstance[键];
}
设置
{
this.WrappedInstance[key]=值;
}
}
公共整数计数
{
得到
{
返回this.WrappedInstance.Count;
}
}
公共图书馆是只读的
{
得到
{
返回此.WrappedInstance.IsReadOnly;
}
}
公共ICollection密钥
{
得到
{
返回此.WrappedInstance.Keys;
}
}
公共ICollection值
{
得到
{
返回this.WrappedInstance.Values;
}
}
公共作废添加(KeyValuePair项)
{
this.WrappedInstance.Add(项);
}
公共无效添加(K键,T值)
{
this.WrappedInstance.Add(key,value);
}
公共空间清除()
{
此.WrappedInstance.Clear();
}
public bool包含(KeyValuePair项)
{
返回此.WrappedInstance.Contains(项);
}
公共bool ContainsKey(K键)
{
返回此.WrappedInstance.ContainsKey(键);
}
public void CopyTo(KeyValuePair[]数组,int-arrayIndex)
{
this.WrappedInstance.CopyTo(数组,数组索引);
}
公共IEnumerator GetEnumerator()
{
返回此.WrappedInstance.GetEnumerator();
}
公共布尔删除(KeyValuePair项)
{
返回此.WrappedInstance.Remove(项目);
}
公共布尔删除(K键)
{
返回此.WrappedInstance.Remove(键);
}
公共bool TryGetValue(K键,out T值)
{
//自定义解析代码在这里
返回此.WrappedInstance.TryGetValue(键,输出值);
}
IEnumerator IEnumerable.GetEnumerator()
{
返回此.WrappedInstance.GetEnumerator();
}
}
请注意您提到的使用价值创建者。当创建价值的成本很高或者通常情况下不创建新实例时,这就更有意义了。如果您只是使用值类型,或者通过分析发现,常见的情况是创建新实例,那么开销可能比必要的要大,因此最好同时支持直接值分配和泛型委托。还有一些情况下,您希望分配一个已创建的值。这个答案是错误的-优先级是to!:before=,因此始终执行valueCreator。在作业周围加上括号。@WarwickAllison,我不确定新版本的C#是否发生了变化,但该代码在我测试的地方运行良好。valueCreator并不总是执行。证据:。但是,为了代码的可读性,可以使用括号。我在追一艘漂亮的单桅帆船:)