C# 将 Dictionary 强制转换为 Dictionary
本文关键字:string Dictionary 转换 Obje AnyType | 更新日期: 2023-09-27 18:31:33
是否可以将Dictionary<string, Anything>
转换为一致的中间泛型类型? 所以我可以将<string, string>
、<string, bool>
、<string, int>
、<string, anything>
全部投射到同一类型的字典中?
我正在从事一个使用大量反射的项目,我需要能够处理 DIctionary 类型,如下所示:
FieldInfo field = this.GetType().GetField(fieldName);
Dictionary<string, Object> dict = (Dictionary<string, Object>)field.GetValue(this);
上面的代码是我目前拥有的代码,程序总是在 cast from 字段失败。获取值到泛型Dictionary<string, Object>
.
有没有办法做到这一点? 还是我应该找出一种不同的方法来处理这些词典?
任何帮助将不胜感激。
按照AakashM的回答,演员似乎不会打球。不过,您可以使用一些辅助方法绕过它:
IDictionary dictionary = (IDictionary)field.GetValue(this);
Dictionary<string, object> newDictionary = CastDict(dictionary)
.ToDictionary(entry => (string)entry.Key,
entry => entry.Value);
private IEnumerable<DictionaryEntry> CastDict(IDictionary dictionary)
{
foreach (DictionaryEntry entry in dictionary)
{
yield return entry;
}
}
在这种情况下,鸭子输入foreach很方便。
这对你有帮助吗?
Dictionary<a, b> output =
input.ToDictionary(item => item.Key, item => (SomeType)item.Value);
即使你能找到某种方式来表达这一点,那也是错误的做法——Dictionary<string, bool>
不是真的 Dictionary<string, object>
,所以我们绝对不想投。考虑一下,如果我们可以转换,我们可以尝试将string
作为值放入,这显然不适合!
但是,我们可以做的是强制转换为非泛型IDictionary
(所有Dictionary<,>
都实现),然后使用它来构造具有相同值的新Dictionary<string, object>
:
FieldInfo field = this.GetType().GetField(fieldName);
IDictionary dictionary = (IDictionary)field.GetValue(this);
Dictionary<string, object> newDictionary =
dictionary
.Cast<dynamic>()
.ToDictionary(entry => (string)entry.Key,
entry => entry.Value);
(请注意,由于此处讨论的原因,您不能在此处使用.Cast<DictionaryEntry>
。如果你是C#4之前,所以没有dynamic
,你必须手动进行枚举,就像Gibsnag的答案一样)
当我偶然发现同样的情况时,我创建了以下帮助程序:
/// <summary>
/// Casts a dictionary object to the desired Dictionary type.
/// </summary>
/// <typeparam name="TKey">The target Key type.</typeparam>
/// <typeparam name="TValue">The target value type.</typeparam>
/// <param name="dictionary">The dictionary to cast.</param>
/// <returns>A copy of the input dictionary, casted to the provided types.</returns>
private Dictionary<TKey, TValue> CastDictionary<TKey, TValue>(IDictionary dictionary)
{
// Get the dictionary's type.
var dictionaryType = typeof(Dictionary<TKey, TValue>);
// If the input is not a dictionary.
if (dictionaryType.IsAssignableFrom(typeof(Dictionary<,>)))
{
// Throw an exception.
throw new Exception("The cast to a dictionary failed: The input object is not a dictionary.");
}
// Get the generic arguments of the dictionary.
var arguments = dictionaryType.GetGenericArguments();
// If the first type of the dictionary is not a descendant of TKey.
if (!(arguments[0] is TKey || arguments[0].IsAssignableFrom(typeof(TKey)))
// Or its second type is not a descendant of TValue.
|| !(arguments[1] is TValue || arguments[1].IsAssignableFrom(typeof(TValue))))
{
// Throw an exception.
throw new Exception("The cast to a dictionary failed: The input dictionary's signature does not match <" + typeof(TKey).Name + ", " + typeof(TValue).Name + ">");
}
// Get the dictionary's default constructor.
var constructor = dictionaryType.GetConstructor(Type.EmptyTypes);
// Create a new dictionary.
var output = (Dictionary<TKey, TValue>)constructor.Invoke(null);
// Loop through the dictionary's entries.
foreach (DictionaryEntry entry in dictionary)
{
// Insert the entries.
output.Add((TKey)entry.Key, (TValue)entry.Value);
}
// Return the result.
return output;
}
可以在您的情况下按如下方式使用:
FieldInfo field = (IDictionary)this.GetType().GetField(fieldName);
Dictionary<string, Object> dict = CastDictionary<string, Object>(field.GetValue(this));
解释什么是错误的:方差
如本回答所述:
Dictionary<string, bool>
不是真的Dictionary<string,object>
让我解释一下原因。这一切都与 C# 中的协方差和逆变有关。总之,Dictionary<K, V>
中的键类型K
和值类型V
既不是纯粹的输入参数,也不是整个字典中的输出参数。因此,这两种泛型类型都不能强制转换为较弱或较强的类型。
如果强制转换为较弱的类型,则会中断输入。例如,期望类型为 K, V
或更强的 Add
函数不能接受K, V
中的任何一个的超类型。如果强制转换为更强的类型,则会中断输出。例如,索引器属性返回类型 V
。我们如何才能安全地将其转换为V
的子类型,只知道原始类型是V
?我们不能。
使用变体泛型的类型安全部分解决方案
有一种方法允许强类型转换,但仅限于原始字典接口的部分片段,这些片段在泛型参数的协方差/逆变方面是一致的。此解决方案使用实现一堆部分接口的包装器类型。每个分部接口都有键/值类型的协方差/逆方差的特定类型组合。然后我们将所有这些部分接口组合到一个主接口中,并通过一个支持对象(一个常规字典)来实现它。来了。首先,接口:
public interface IDictionaryBase
{
int Count { get; }
bool IsReadOnly { get; }
void Clear();
}
public interface IInKeyInValueSemiDictionary<in K, in V> : IDictionaryBase, IInKeySemiDictionary<K>
{
V this[K key] { set; }
void Add(K key, V value);
}
public interface IInKeyOutValueSemiDictionary<in K, out V> : IDictionaryBase, IInKeySemiDictionary<K>, IOutValueSemiDictionary<V>
{
V this[K key] { get; }
ISuccessTuple<V> TryGetValue(K key);
}
public interface ISuccessTuple<out V>
{
bool WasSuccessful { get; }
V Value { get; }
}
public class SuccessTupleImpl<V> : ISuccessTuple<V>
{
public bool WasSuccessful { get; }
public V Value {get;}
public SuccessTupleImpl(bool wasSuccessful, V value)
{
WasSuccessful = wasSuccessful;
Value = value;
}
}
public interface IInKeySemiDictionary<in K> : IDictionaryBase
{
bool ContainsKey(K key);
bool Remove(K key);
}
public interface IOutKeySemiDictionary<out K> : IDictionaryBase
{
IEnumerable<K> Keys { get; }
}
public interface IOutValueSemiDictionary<out V> : IDictionaryBase
{
IEnumerable<V> Values { get; }
}
注意:对于泛型参数,我们不必在这里涵盖所有 in/out 组合,并且还注意到某些接口只需要一个泛型参数。原因是协方差/逆变的某些组合没有任何关联的方法,因此不需要相应的类型。请注意,我省略了KeyValuePair<K, V>
类型-如果您想包含它,则需要对此执行类似的技巧,而现阶段似乎不值得。
因此,接下来,所有这些接口的联合:
public interface IVariantDictionary<K, V> : IInKeyInValueSemiDictionary<K, V>, IInKeyOutValueSemiDictionary<K, V>,
IOutKeySemiDictionary<K>, IDictionary<K, V>
{ }
然后,包装类:
class VariantDictionaryImpl<K, V> : IVariantDictionary<K, V>
{
private readonly IDictionary<K, V> _backingDictionary;
public VariantDictionaryImpl(IDictionary<K, V> backingDictionary)
{
_backingDictionary = backingDictionary ?? throw new ArgumentNullException(nameof(backingDictionary));
}
public V this[K key] { set => _backingDictionary[key] = value; }
V IInKeyOutValueSemiDictionary<K, V>.this[K key] => _backingDictionary[key];
V IDictionary<K, V>.this[K key] { get => _backingDictionary[key]; set => _backingDictionary[key] = value; }
public int Count => _backingDictionary.Count;
public bool IsReadOnly => _backingDictionary.IsReadOnly;
public IEnumerable<K> Keys => _backingDictionary.Keys;
public ICollection<V> Values => _backingDictionary.Values;
ICollection<K> IDictionary<K, V>.Keys => _backingDictionary.Keys;
IEnumerable<V> IOutValueSemiDictionary<V>.Values => Values;
public void Add(K key, V value)
{
_backingDictionary.Add(key, value);
}
public void Add(KeyValuePair<K, V> item)
{
_backingDictionary.Add(item);
}
public void Clear()
{
_backingDictionary.Clear();
}
public bool Contains(KeyValuePair<K, V> item)
{
return _backingDictionary.Contains(item);
}
public bool ContainsKey(K key)
{
return _backingDictionary.ContainsKey(key);
}
public void CopyTo(KeyValuePair<K, V>[] array, int arrayIndex)
{
_backingDictionary.CopyTo(array, arrayIndex);
}
public IEnumerator<KeyValuePair<K, V>> GetEnumerator()
{
return _backingDictionary.GetEnumerator();
}
public bool Remove(K key)
{
return _backingDictionary.Remove(key);
}
public bool Remove(KeyValuePair<K, V> item)
{
return _backingDictionary.Remove(item);
}
public ISuccessTuple<V> TryGetValue(K key)
{
bool wasSuccessful = _backingDictionary.TryGetValue(key, out V v);
return new SuccessTupleImpl<V>(wasSuccessful, v);
}
public bool TryGetValue(K key, out V value)
{
return _backingDictionary.TryGetValue(key, out value);
}
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable)_backingDictionary).GetEnumerator();
}
}
将字典包装在此类中后,可以将其用作常规字典,也可以用作定义的任何协变/逆变片段接口类型。
考虑是否真的有必要在object
之间进行转换。我开始走这条路,偶然发现了这篇文章,然后意识到我可以通过泛型而不是转换来实现我需要的东西。例如;
class DictionaryUtils<T>
{
public static T ValueOrDefault(IDictionary<string, T> dictionary, string key)
{
return dictionary.ContainsKey(key) ? dictionary[key] : default(T);
}
}
这段代码要干净得多,并且比其他答案中显示的等效转换代码更快。
是 可以将FieldInfo
转换为Dictionary
,如下所示
这是我在代码中使用的一个例子
Dictionary<string, string>
GetTheDict = FilesAndPaths.GetType()
.GetFields()
.Where(f => f.Name.Equals(pLoadFile))
.Select(f => (Dictionary<string, string>)f.GetValue(FilesAndPaths))
.Single();
我遇到了同样的情况,并创建了一个WrapperDictionary类和一个强制转换扩展方法。如果您还想对其进行操作(例如删除项目),发现它很有帮助。
例:
const string TestKey1 = "Key";
const string TestValue1 = "Value";
var dict = new Dictionary<string, string>();
dict.Add(TestKey1, TestValue1);
var wrapper = dict.CastDictionary<string, string, string, object>();
wrapper.Remove(TestKey1);
法典:
public class DictionaryWrapper<TKeyTarget, TValueTarget, TKeySource, TValueSource> : IDictionary<TKeyTarget, TValueTarget>
{
#region types
private class EnumeratorWrapper : IEnumerator<KeyValuePair<TKeyTarget, TValueTarget>>
{
private readonly IEnumerator<KeyValuePair<TKeySource, TValueSource>> _enumerator;
private readonly DictionaryWrapper<TKeyTarget, TValueTarget, TKeySource, TValueSource> _dictionaryWrapper;
public EnumeratorWrapper(IEnumerator<KeyValuePair<TKeySource, TValueSource>> enumerator, DictionaryWrapper<TKeyTarget, TValueTarget, TKeySource, TValueSource> dictionaryWrapper)
{
_enumerator = enumerator;
_dictionaryWrapper = dictionaryWrapper;
}
public void Dispose()
{
_enumerator.Dispose();
}
public bool MoveNext()
{
return _enumerator.MoveNext();
}
public void Reset()
{
_enumerator.Reset();
}
public KeyValuePair<TKeyTarget, TValueTarget> Current => _dictionaryWrapper._kvpSourceToTargetFunc(_enumerator.Current);
object IEnumerator.Current => Current;
}
#endregion
#region fields
private readonly IDictionary<TKeySource, TValueSource> _dictionary;
private readonly Func<TKeySource, TKeyTarget> _keySourceToTargetFunc;
private readonly Func<TKeyTarget, TKeySource> _keyTargetToSourceFunc;
private readonly Func<TValueSource, TValueTarget> _valueSourceToTargetFunc;
private readonly Func<TValueTarget, TValueSource> _valueTargetToSourceFunc;
private readonly Func<KeyValuePair<TKeySource, TValueSource>, KeyValuePair<TKeyTarget, TValueTarget>> _kvpSourceToTargetFunc;
private readonly Func<KeyValuePair<TKeyTarget, TValueTarget>, KeyValuePair<TKeySource, TValueSource>> _kvpTargetToSourceFunc;
#endregion
#region Construction
public DictionaryWrapper(
IDictionary<TKeySource, TValueSource> dict,
Func<TKeySource, TKeyTarget> keySourceToTargetFunc = null,
Func<TKeyTarget, TKeySource> keyTargetToSourceFunc = null,
Func<TValueSource, TValueTarget> valueSourceToTargetFunc = null,
Func<TValueTarget, TValueSource> valueTargetToSourceFunc = null)
{
_dictionary = dict;
_keySourceToTargetFunc = keySourceToTargetFunc ?? (i => (TKeyTarget) (object) i);
_keyTargetToSourceFunc = keyTargetToSourceFunc ?? (i => (TKeySource) (object) i);
_valueSourceToTargetFunc = valueSourceToTargetFunc ?? (i => (TValueTarget) (object) i);
_valueTargetToSourceFunc = valueTargetToSourceFunc ?? (i => (TValueSource) (object) i);
_kvpSourceToTargetFunc =
kvp => new KeyValuePair<TKeyTarget, TValueTarget>(_keySourceToTargetFunc(kvp.Key), _valueSourceToTargetFunc(kvp.Value));
_kvpTargetToSourceFunc =
kvp => new KeyValuePair<TKeySource, TValueSource>(_keyTargetToSourceFunc(kvp.Key), _valueTargetToSourceFunc(kvp.Value));
}
#endregion
#region Interface Members
public IEnumerator<KeyValuePair<TKeyTarget, TValueTarget>> GetEnumerator()
{
return new EnumeratorWrapper(_dictionary.GetEnumerator(), this);
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public void Add(KeyValuePair<TKeyTarget, TValueTarget> item)
{
_dictionary.Add(_kvpTargetToSourceFunc(item));
}
public void Clear()
{
_dictionary.Clear();
}
public bool Contains(KeyValuePair<TKeyTarget, TValueTarget> item)
{
return _dictionary.Contains(_kvpTargetToSourceFunc(item));
}
public void CopyTo(KeyValuePair<TKeyTarget, TValueTarget>[] array, int arrayIndex)
{
throw new NotImplementedException();
}
public bool Remove(KeyValuePair<TKeyTarget, TValueTarget> item)
{
return _dictionary.Remove(_kvpTargetToSourceFunc(item));
}
public int Count => _dictionary.Count;
public bool IsReadOnly => _dictionary.IsReadOnly;
public bool ContainsKey(TKeyTarget key)
{
return _dictionary.ContainsKey(_keyTargetToSourceFunc(key));
}
public void Add(TKeyTarget key, TValueTarget value)
{
_dictionary.Add(_keyTargetToSourceFunc(key), _valueTargetToSourceFunc(value));
}
public bool Remove(TKeyTarget key)
{
return _dictionary.Remove(_keyTargetToSourceFunc(key));
}
public bool TryGetValue(TKeyTarget key, out TValueTarget value)
{
var success = _dictionary.TryGetValue(_keyTargetToSourceFunc(key), out TValueSource result);
value = success ? _valueSourceToTargetFunc(result) : default;
return success;
}
public TValueTarget this[TKeyTarget key]
{
get => _valueSourceToTargetFunc(_dictionary[_keyTargetToSourceFunc(key)]);
set => _dictionary[_keyTargetToSourceFunc(key)] = _valueTargetToSourceFunc(value);
}
public ICollection<TKeyTarget> Keys => _dictionary.Keys.Select(k => _keySourceToTargetFunc(k)).ToList();
public ICollection<TValueTarget> Values => _dictionary.Values.Select(v => _valueSourceToTargetFunc(v)).ToList();
#endregion
}
public static class DictionaryWrapperExtensions
{
public static IDictionary<TKeyCasted, TValueCasted> CastDictionary<TKey, TValue, TKeyCasted, TValueCasted>(this IDictionary<TKey, TValue> dictionary)
{
return new DictionaryWrapper<TKeyCasted,TValueCasted,TKey,TValue>(dictionary);
}
}
本文关键字:string Dictionary 转换 Obje AnyType | 更新日期: 2023-09-27 18:31:33
是否可以将Dictionary<string, Anything>
转换为一致的中间泛型类型? 所以我可以将<string, string>
、<string, bool>
、<string, int>
、<string, anything>
全部投射到同一类型的字典中?
我正在从事一个使用大量反射的项目,我需要能够处理 DIctionary 类型,如下所示:
FieldInfo field = this.GetType().GetField(fieldName);
Dictionary<string, Object> dict = (Dictionary<string, Object>)field.GetValue(this);
上面的代码是我目前拥有的代码,程序总是在 cast from 字段失败。获取值到泛型Dictionary<string, Object>
.
有没有办法做到这一点? 还是我应该找出一种不同的方法来处理这些词典?
任何帮助将不胜感激。
按照AakashM的回答,演员似乎不会打球。不过,您可以使用一些辅助方法绕过它:
IDictionary dictionary = (IDictionary)field.GetValue(this);
Dictionary<string, object> newDictionary = CastDict(dictionary)
.ToDictionary(entry => (string)entry.Key,
entry => entry.Value);
private IEnumerable<DictionaryEntry> CastDict(IDictionary dictionary)
{
foreach (DictionaryEntry entry in dictionary)
{
yield return entry;
}
}
在这种情况下,鸭子输入foreach很方便。
你有帮助吗?
Dictionary<a, b> output =
input.ToDictionary(item => item.Key, item => (SomeType)item.Value);
即使你能找到某种方式来表达这一点,那也是错误的做法——Dictionary<string, bool>
不是真的 Dictionary<string, object>
,所以我们绝对不想投。考虑一下,如果我们可以转换,我们可以尝试将string
作为值放入,这显然不适合!
但是,我们可以做的是强制转换为非泛型IDictionary
(所有Dictionary<,>
都实现),然后使用它来构造具有相同值的新Dictionary<string, object>
:
FieldInfo field = this.GetType().GetField(fieldName);
IDictionary dictionary = (IDictionary)field.GetValue(this);
Dictionary<string, object> newDictionary =
dictionary
.Cast<dynamic>()
.ToDictionary(entry => (string)entry.Key,
entry => entry.Value);
(请注意,由于此处讨论的原因,您不能在此处使用.Cast<DictionaryEntry>
。如果你是C#4之前,所以没有dynamic
,你必须手动进行枚举,就像Gibsnag的答案一样)
当我偶然发现同样的情况时,我创建了以下帮助程序:
/// <summary>
/// Casts a dictionary object to the desired Dictionary type.
/// </summary>
/// <typeparam name="TKey">The target Key type.</typeparam>
/// <typeparam name="TValue">The target value type.</typeparam>
/// <param name="dictionary">The dictionary to cast.</param>
/// <returns>A copy of the input dictionary, casted to the provided types.</returns>
private Dictionary<TKey, TValue> CastDictionary<TKey, TValue>(IDictionary dictionary)
{
// Get the dictionary's type.
var dictionaryType = typeof(Dictionary<TKey, TValue>);
// If the input is not a dictionary.
if (dictionaryType.IsAssignableFrom(typeof(Dictionary<,>)))
{
// Throw an exception.
throw new Exception("The cast to a dictionary failed: The input object is not a dictionary.");
}
// Get the generic arguments of the dictionary.
var arguments = dictionaryType.GetGenericArguments();
// If the first type of the dictionary is not a descendant of TKey.
if (!(arguments[0] is TKey || arguments[0].IsAssignableFrom(typeof(TKey)))
// Or its second type is not a descendant of TValue.
|| !(arguments[1] is TValue || arguments[1].IsAssignableFrom(typeof(TValue))))
{
// Throw an exception.
throw new Exception("The cast to a dictionary failed: The input dictionary's signature does not match <" + typeof(TKey).Name + ", " + typeof(TValue).Name + ">");
}
// Get the dictionary's default constructor.
var constructor = dictionaryType.GetConstructor(Type.EmptyTypes);
// Create a new dictionary.
var output = (Dictionary<TKey, TValue>)constructor.Invoke(null);
// Loop through the dictionary's entries.
foreach (DictionaryEntry entry in dictionary)
{
// Insert the entries.
output.Add((TKey)entry.Key, (TValue)entry.Value);
}
// Return the result.
return output;
}
可以在您的情况下按如下方式使用:
FieldInfo field = (IDictionary)this.GetType().GetField(fieldName);
Dictionary<string, Object> dict = CastDictionary<string, Object>(field.GetValue(this));
解释什么是错误的:方差
如本回答所述:
Dictionary<string, bool>
不是真的Dictionary<string,object>
让我解释一下原因。这一切都与 C# 中的协方差和逆变有关。总之,Dictionary<K, V>
中的键类型K
和值类型V
既不是纯粹的输入参数,也不是整个字典中的输出参数。因此,这两种泛型类型都不能强制转换为较弱或较强的类型。
如果强制转换为较弱的类型,则会中断输入。例如,期望类型为 K, V
或更强的 Add
函数不能接受K, V
中的任何一个的超类型。如果强制转换为更强的类型,则会中断输出。例如,索引器属性返回类型 V
。我们如何才能安全地将其转换为V
的子类型,只知道原始类型是V
?我们不能。
使用变体泛型的类型安全部分解决方案
有一种方法允许强类型转换,但仅限于原始字典接口的部分片段,这些片段在泛型参数的协方差/逆变方面是一致的。此解决方案使用实现一堆部分接口的包装器类型。每个分部接口都有键/值类型的协方差/逆方差的特定类型组合。然后我们将所有这些部分接口组合到一个主接口中,并通过一个支持对象(一个常规字典)来实现它。来了。首先,接口:
public interface IDictionaryBase
{
int Count { get; }
bool IsReadOnly { get; }
void Clear();
}
public interface IInKeyInValueSemiDictionary<in K, in V> : IDictionaryBase, IInKeySemiDictionary<K>
{
V this[K key] { set; }
void Add(K key, V value);
}
public interface IInKeyOutValueSemiDictionary<in K, out V> : IDictionaryBase, IInKeySemiDictionary<K>, IOutValueSemiDictionary<V>
{
V this[K key] { get; }
ISuccessTuple<V> TryGetValue(K key);
}
public interface ISuccessTuple<out V>
{
bool WasSuccessful { get; }
V Value { get; }
}
public class SuccessTupleImpl<V> : ISuccessTuple<V>
{
public bool WasSuccessful { get; }
public V Value {get;}
public SuccessTupleImpl(bool wasSuccessful, V value)
{
WasSuccessful = wasSuccessful;
Value = value;
}
}
public interface IInKeySemiDictionary<in K> : IDictionaryBase
{
bool ContainsKey(K key);
bool Remove(K key);
}
public interface IOutKeySemiDictionary<out K> : IDictionaryBase
{
IEnumerable<K> Keys { get; }
}
public interface IOutValueSemiDictionary<out V> : IDictionaryBase
{
IEnumerable<V> Values { get; }
}
注意:对于泛型参数,我们不必在这里涵盖所有 in/out 组合,并且还注意到某些接口只需要一个泛型参数。原因是协方差/逆变的某些组合没有任何关联的方法,因此不需要相应的类型。请注意,我省略了KeyValuePair<K, V>
类型-如果您想包含它,则需要对此执行类似的技巧,而现阶段似乎不值得。
因此,接下来,所有这些接口的联合:
public interface IVariantDictionary<K, V> : IInKeyInValueSemiDictionary<K, V>, IInKeyOutValueSemiDictionary<K, V>,
IOutKeySemiDictionary<K>, IDictionary<K, V>
{ }
然后,包装类:
class VariantDictionaryImpl<K, V> : IVariantDictionary<K, V>
{
private readonly IDictionary<K, V> _backingDictionary;
public VariantDictionaryImpl(IDictionary<K, V> backingDictionary)
{
_backingDictionary = backingDictionary ?? throw new ArgumentNullException(nameof(backingDictionary));
}
public V this[K key] { set => _backingDictionary[key] = value; }
V IInKeyOutValueSemiDictionary<K, V>.this[K key] => _backingDictionary[key];
V IDictionary<K, V>.this[K key] { get => _backingDictionary[key]; set => _backingDictionary[key] = value; }
public int Count => _backingDictionary.Count;
public bool IsReadOnly => _backingDictionary.IsReadOnly;
public IEnumerable<K> Keys => _backingDictionary.Keys;
public ICollection<V> Values => _backingDictionary.Values;
ICollection<K> IDictionary<K, V>.Keys => _backingDictionary.Keys;
IEnumerable<V> IOutValueSemiDictionary<V>.Values => Values;
public void Add(K key, V value)
{
_backingDictionary.Add(key, value);
}
public void Add(KeyValuePair<K, V> item)
{
_backingDictionary.Add(item);
}
public void Clear()
{
_backingDictionary.Clear();
}
public bool Contains(KeyValuePair<K, V> item)
{
return _backingDictionary.Contains(item);
}
public bool ContainsKey(K key)
{
return _backingDictionary.ContainsKey(key);
}
public void CopyTo(KeyValuePair<K, V>[] array, int arrayIndex)
{
_backingDictionary.CopyTo(array, arrayIndex);
}
public IEnumerator<KeyValuePair<K, V>> GetEnumerator()
{
return _backingDictionary.GetEnumerator();
}
public bool Remove(K key)
{
return _backingDictionary.Remove(key);
}
public bool Remove(KeyValuePair<K, V> item)
{
return _backingDictionary.Remove(item);
}
public ISuccessTuple<V> TryGetValue(K key)
{
bool wasSuccessful = _backingDictionary.TryGetValue(key, out V v);
return new SuccessTupleImpl<V>(wasSuccessful, v);
}
public bool TryGetValue(K key, out V value)
{
return _backingDictionary.TryGetValue(key, out value);
}
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable)_backingDictionary).GetEnumerator();
}
}
将字典包装在此类中后,可以将其用作常规字典,也可以用作定义的任何协变/逆变片段接口类型。
真的有必要在object
之间进行转换。我开始走这条路,偶然发现了这篇文章,然后意识到我可以通过泛型而不是转换来实现我需要的东西。例如;
class DictionaryUtils<T>
{
public static T ValueOrDefault(IDictionary<string, T> dictionary, string key)
{
return dictionary.ContainsKey(key) ? dictionary[key] : default(T);
}
}
这段代码要干净得多,并且比其他答案中显示的等效转换代码更快。
FieldInfo
转换为Dictionary
,如下所示
这是我在代码中使用的一个例子
Dictionary<string, string>
GetTheDict = FilesAndPaths.GetType()
.GetFields()
.Where(f => f.Name.Equals(pLoadFile))
.Select(f => (Dictionary<string, string>)f.GetValue(FilesAndPaths))
.Single();
我遇到了同样的情况,并创建了一个WrapperDictionary类和一个强制转换扩展方法。如果您还想对其进行操作(例如删除项目),发现它很有帮助。
例:
const string TestKey1 = "Key";
const string TestValue1 = "Value";
var dict = new Dictionary<string, string>();
dict.Add(TestKey1, TestValue1);
var wrapper = dict.CastDictionary<string, string, string, object>();
wrapper.Remove(TestKey1);
法典:
public class DictionaryWrapper<TKeyTarget, TValueTarget, TKeySource, TValueSource> : IDictionary<TKeyTarget, TValueTarget>
{
#region types
private class EnumeratorWrapper : IEnumerator<KeyValuePair<TKeyTarget, TValueTarget>>
{
private readonly IEnumerator<KeyValuePair<TKeySource, TValueSource>> _enumerator;
private readonly DictionaryWrapper<TKeyTarget, TValueTarget, TKeySource, TValueSource> _dictionaryWrapper;
public EnumeratorWrapper(IEnumerator<KeyValuePair<TKeySource, TValueSource>> enumerator, DictionaryWrapper<TKeyTarget, TValueTarget, TKeySource, TValueSource> dictionaryWrapper)
{
_enumerator = enumerator;
_dictionaryWrapper = dictionaryWrapper;
}
public void Dispose()
{
_enumerator.Dispose();
}
public bool MoveNext()
{
return _enumerator.MoveNext();
}
public void Reset()
{
_enumerator.Reset();
}
public KeyValuePair<TKeyTarget, TValueTarget> Current => _dictionaryWrapper._kvpSourceToTargetFunc(_enumerator.Current);
object IEnumerator.Current => Current;
}
#endregion
#region fields
private readonly IDictionary<TKeySource, TValueSource> _dictionary;
private readonly Func<TKeySource, TKeyTarget> _keySourceToTargetFunc;
private readonly Func<TKeyTarget, TKeySource> _keyTargetToSourceFunc;
private readonly Func<TValueSource, TValueTarget> _valueSourceToTargetFunc;
private readonly Func<TValueTarget, TValueSource> _valueTargetToSourceFunc;
private readonly Func<KeyValuePair<TKeySource, TValueSource>, KeyValuePair<TKeyTarget, TValueTarget>> _kvpSourceToTargetFunc;
private readonly Func<KeyValuePair<TKeyTarget, TValueTarget>, KeyValuePair<TKeySource, TValueSource>> _kvpTargetToSourceFunc;
#endregion
#region Construction
public DictionaryWrapper(
IDictionary<TKeySource, TValueSource> dict,
Func<TKeySource, TKeyTarget> keySourceToTargetFunc = null,
Func<TKeyTarget, TKeySource> keyTargetToSourceFunc = null,
Func<TValueSource, TValueTarget> valueSourceToTargetFunc = null,
Func<TValueTarget, TValueSource> valueTargetToSourceFunc = null)
{
_dictionary = dict;
_keySourceToTargetFunc = keySourceToTargetFunc ?? (i => (TKeyTarget) (object) i);
_keyTargetToSourceFunc = keyTargetToSourceFunc ?? (i => (TKeySource) (object) i);
_valueSourceToTargetFunc = valueSourceToTargetFunc ?? (i => (TValueTarget) (object) i);
_valueTargetToSourceFunc = valueTargetToSourceFunc ?? (i => (TValueSource) (object) i);
_kvpSourceToTargetFunc =
kvp => new KeyValuePair<TKeyTarget, TValueTarget>(_keySourceToTargetFunc(kvp.Key), _valueSourceToTargetFunc(kvp.Value));
_kvpTargetToSourceFunc =
kvp => new KeyValuePair<TKeySource, TValueSource>(_keyTargetToSourceFunc(kvp.Key), _valueTargetToSourceFunc(kvp.Value));
}
#endregion
#region Interface Members
public IEnumerator<KeyValuePair<TKeyTarget, TValueTarget>> GetEnumerator()
{
return new EnumeratorWrapper(_dictionary.GetEnumerator(), this);
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public void Add(KeyValuePair<TKeyTarget, TValueTarget> item)
{
_dictionary.Add(_kvpTargetToSourceFunc(item));
}
public void Clear()
{
_dictionary.Clear();
}
public bool Contains(KeyValuePair<TKeyTarget, TValueTarget> item)
{
return _dictionary.Contains(_kvpTargetToSourceFunc(item));
}
public void CopyTo(KeyValuePair<TKeyTarget, TValueTarget>[] array, int arrayIndex)
{
throw new NotImplementedException();
}
public bool Remove(KeyValuePair<TKeyTarget, TValueTarget> item)
{
return _dictionary.Remove(_kvpTargetToSourceFunc(item));
}
public int Count => _dictionary.Count;
public bool IsReadOnly => _dictionary.IsReadOnly;
public bool ContainsKey(TKeyTarget key)
{
return _dictionary.ContainsKey(_keyTargetToSourceFunc(key));
}
public void Add(TKeyTarget key, TValueTarget value)
{
_dictionary.Add(_keyTargetToSourceFunc(key), _valueTargetToSourceFunc(value));
}
public bool Remove(TKeyTarget key)
{
return _dictionary.Remove(_keyTargetToSourceFunc(key));
}
public bool TryGetValue(TKeyTarget key, out TValueTarget value)
{
var success = _dictionary.TryGetValue(_keyTargetToSourceFunc(key), out TValueSource result);
value = success ? _valueSourceToTargetFunc(result) : default;
return success;
}
public TValueTarget this[TKeyTarget key]
{
get => _valueSourceToTargetFunc(_dictionary[_keyTargetToSourceFunc(key)]);
set => _dictionary[_keyTargetToSourceFunc(key)] = _valueTargetToSourceFunc(value);
}
public ICollection<TKeyTarget> Keys => _dictionary.Keys.Select(k => _keySourceToTargetFunc(k)).ToList();
public ICollection<TValueTarget> Values => _dictionary.Values.Select(v => _valueSourceToTargetFunc(v)).ToList();
#endregion
}
public static class DictionaryWrapperExtensions
{
public static IDictionary<TKeyCasted, TValueCasted> CastDictionary<TKey, TValue, TKeyCasted, TValueCasted>(this IDictionary<TKey, TValue> dictionary)
{
return new DictionaryWrapper<TKeyCasted,TValueCasted,TKey,TValue>(dictionary);
}
}