我可以创建泛型类型字典吗?

我想创建一个 Dictionary 对象,其中包含字符串键,保存泛型类型的值。我想它看起来应该是这样的:

Dictionary<string, List<T>> d = new Dictionary<string, List<T>>();

让我补充以下内容:

d.Add("Numbers", new List<int>());
d.Add("Letters", new List<string>());

我知道我可以对一个字符串列表这样做,例如,使用下面的语法:

Dictionary<string, List<string>> d = new Dictionary<string, List<string>>();
d.Add("Key", new List<string>());

但如果可能的话,我想列一个通用的清单。

两个问题:

  1. 有可能吗?
  2. 语法是什么?
124036 次浏览

编辑: 现在我已经重读了问题... ..。

您不能这样做,但是定制集合可以在一定程度上处理它。你基本上有一个通用的 Add方法:

public void Add<T>(string key, List<T> list)

(集合本身 不会是泛型的——除非您希望使键类型为泛型。)

但是,您不能以强类型的方式从中获取 提取物值,因为编译器不知道您对特定键使用了哪种类型。如果将键设置为类型本身,那么最终的结果是 有点更好,但是仍然不受现有集合的支持。这就是我最初的答案。

编辑: 原始答案,当我没有完全正确地阅读问题,但这可能是信息无论如何..。

不,恐怕你不能让一个类型的参数依赖于另一个类型的参数。这只是人们可能想在泛型类型系统中表示的事情之一。NET 的约束不允许。总会有这样的问题。NET 设计人员选择使泛型 相对而言保持简单。

但是,您可以编写一个集合来相当容易地实施它。我有 博客文章中的一个例子,它只保持一个单一的值,但它将很容易扩展到使用一个列表。

这样有用吗?

public class GenericDictionary
{
private Dictionary<string, object> _dict = new Dictionary<string, object>();


public void Add<T>(string key, T value) where T : class
{
_dict.Add(key, value);
}


public T GetValue<T>(string key) where T : class
{
return _dict[key] as T;
}
}

基本上,它为您包装了所有的幕后演员。

我更喜欢这种将泛型类型放入集合的方式:

interface IList
{
void Add (object item);
}


class MyList<T> : List<T>, IList
{
public void Add (object item)
{
base.Add ((T) item); // could put a type check here
}
}


class Program
{
static void Main (string [] args)
{
SortedDictionary<int, IList>
dict = new SortedDictionary<int, IList> ();


dict [0] = new MyList<int> ();
dict [1] = new MyList<float> ();


dict [0].Add (42);
dict [1].Add ("Hello"); // Fails! Type cast exception.
}
}

但是在编译时会丢失类型检查。

我们使用了大量的反射来创建一个可扩展的管理工具。我们需要在模块定义中注册全局搜索中的项。每个搜索都会以一致的方式返回结果,但是每个搜索都有不同的依赖关系。下面是我们为单个模块注册搜索的一个例子:

public void ConfigureSearch(ISearchConfiguration config)
{
config.AddGlobalSearchCallback<IEmploymentDataContext>((query, ctx) =>
{
return ctx.Positions.Where(p => p.Name.Contains(query)).ToList().Select(p =>
new SearchResult("Positions", p.Name, p.ThumbnailUrl,
new UrlContext("edit", "position", new RouteValueDictionary(new { Id = p.Id }))
));
});
}

在模块注册期间的后台,我们迭代每个模块,并将 Func 添加到 SearchTable,其实例为:

public class GenericFuncCollection : IEnumerable<Tuple<Type, Type, Object>>
{
private List<Tuple<Type, Type, Object>> objects = new List<Tuple<Type, Type, Object>>();


/// <summary>
/// Stores a list of Func of T where T is unknown at compile time.
/// </summary>
/// <typeparam name="T1">Type of T</typeparam>
/// <typeparam name="T2">Type of the Func</typeparam>
/// <param name="func">Instance of the Func</param>
public void Add<T1, T2>(Object func)
{
objects.Add(new Tuple<Type, Type, Object>(typeof(T1), typeof(T2), func));
}


public IEnumerator<Tuple<Type, Type, object>> GetEnumerator()
{
return objects.GetEnumerator();
}


System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return objects.GetEnumerator();
}
}

然后当我们最终叫它时,我们带着反思:

var dependency = DependencyResolver.Current.GetService(search.Item1);
var methodInfo = search.Item2.GetMethod("Invoke");
return (IEnumerable<SearchResult>)methodInfo.Invoke(search.Item3, new Object[] { query, dependency });

另一种可能是使用动态变量。

例如:

Dictionary < string,List < Dynamic > > d = new Dictionary < string,List < Dynamic > > () ; D. Add (“ Key”,new List < Dynamic > ()) ;

变量在运行时动态解析类型。

我没有在这里找到我要找的东西,但是在阅读之后,我认为它可能就是被要求的东西,所以试图回答。

问题是,当您使用 Dictionary 时,它是一个封闭的构造类型,并且所有元素都必须是 TValue 类型。我在很多地方都看到过这个问题,但没有一个好的答案。

事实是,我希望索引,但每个元素有一个不同的类型,基于 TKey 的值,我们已经知道类型。不是试图绕过这个框,而是试图获得更优雅的访问,比如 DataSetExtensionField。并且不想使用 Dynamic,因为类型是已知的,而且不需要它。

解决方案可以是创建一个不在类级别公开 T 的非泛型类型,从而导致关闭构造字典的 TValue 部分。然后使用一种流畅的方法来帮助初始化。

public class GenericObject
{
private object value;


public T GetValue<T>()
{
return (T)value;
}


public void SetValue<T>(T value)
{
this.value = value;
}


public GenericObject WithValue<T>(T value)
{
this.value = value;
return this;
}
}


class Program
{
static void Main(string[] args)
{
Dictionary<string, GenericObject> dict = new Dictionary<string, GenericObject>();


dict["mystring"] = new GenericObject().WithValue<string>("Hello World");
dict["myint"] = new GenericObject().WithValue<int>(1);


int i = dict["myint"].GetValue<int>();
string s = dict["mystring"].GetValue<string>();
}
}

其中一种方法是创建类型为“ object”的 Dictionary 值,如:

Dictionary<string, object> d = new Dictionary<string, object>();

因此,在这里对象数据类型被用作泛型数据类型,您可以将任何内容作为值放入其中。

Dictionary<string, dynamic>怎么样? (假设你在 C # 4上)

Dictionary<string, dynamic> Dict = new Dictionary<string, dynamic>();

资料来源: https://stackoverflow.com/a/5038029/3270733

不,但是您可以使用 object 而不是泛型类型。

长话短说: C # 的当前版本不允许在 dictionary 中创建泛型类型的条目。您的选项可以是: a)创建一个与 Dictionary 相同的自定义类,但允许它接受泛型类型; 或者 b)使 Dictionary 接受类型对象的值。我认为选项 b 是比较简单的方法。

如果您发送特定类型的列表,那么当您处理这些列表时,您将不得不进行测试,以查看它是什么类型的列表。一种更好的方法是创建对象列表; 这种方法可以输入整数、字符串或任何您想要的数据类型,而不必测试 List 包含哪种类型的对象。这(可能)会产生你想要的效果。

下面是一个简短的控制台程序,它可以起到这样的作用:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;


namespace dictionary
{
class Program
{
static void Main(string[] args)
{
Dictionary<string, object> dic = new Dictionary<string, object>();
var lstIntList = new List<object>();
var lstStrings = new List<object>();
var lstObjects = new List<object>();
string s = "";


lstIntList.Add(1);
lstIntList.Add(2);
lstIntList.Add(3);


lstStrings.Add("a");
lstStrings.Add("b");
lstStrings.Add("c");


dic.Add("Numbers", lstIntList);
dic.Add("Letters", lstStrings);


foreach (KeyValuePair<string, object> kvp in dic)
{
Console.WriteLine("{0}", kvp.Key);
lstObjects = ((IEnumerable)kvp.Value).Cast<object>().ToList();


foreach (var obj in lstObjects)
{s = obj.ToString(); Console.WriteLine(s);}
Console.WriteLine("");
}




Console.WriteLine("");
Console.WriteLine("press any key to exit");
Console.ReadKey();
}//end main
}
}

enter image description here

我使用 ConditionalWeakTable得到了一个类型安全的实现。

public class FieldByType
{
static class Storage<T>
where T : class
{
static readonly ConditionalWeakTable<FieldByType, T> table = new ConditionalWeakTable<FieldByType, T>();


public static T GetValue(FieldByType fieldByType)
{
table.TryGetValue(fieldByType, out var result);
return result;
}


public static void SetValue(FieldByType fieldByType, T value)
{
table.Remove(fieldByType);
table.Add(fieldByType, value);
}
}


public T GetValue<T>()
where T : class
{
return Storage<T>.GetValue(this);
}


public void SetValue<T>(T value)
where T : class
{
Storage<T>.SetValue(this, value);
}
}

它可以这样使用:

/// <summary>
/// This class can be used when cloning multiple related objects to store cloned/original object relationship.
/// </summary>
public class CloningContext
{
readonly FieldByType dictionaries = new FieldByType();


public void RegisterClone<T>(T original, T clone)
{
var dictionary = dictionaries.GetValue<Dictionary<T, T>>();
if (dictionary == null)
{
dictionary = new Dictionary<T, T>();
dictionaries.SetValue(dictionary);
}
dictionary[original] = clone;
}


public bool TryGetClone<T>(T original, out T clone)
{
var dictionary = dictionaries.GetValue<Dictionary<T, T>>();
if (dictionary == null)
{
clone = default(T);
return false;
}


return dictionary.TryGetValue(original, out clone);
}
}

另请参见 这个问题,其中值的类型作为键的通用参数存储在其中。

或者可以像这样使用泛型 Type

public static void SafeUpdateInDictionary<T, L>(T DictionaryToBeUpdated, string Key, L Value) where T : Dictionary<string, L>
{
if (DictionaryToBeUpdated != null)
{
if(Value != null)
{
if (!DictionaryToBeUpdated.ContainsKey(Key))
DictionaryToBeUpdated.Add(Key, Value);
else
DictionaryToBeUpdated[Key] = Value;
}
}
}