添加方法泛型参数的集合初始值设定项?
Collection initializer on Add method generic parameter?
我可以在 class 上使用集合初始值设定项吗?Add
方法采用通用参数?
我的 class 看起来像这样:
public class FooCollection : IEnumerable<KeyValuePair<string, Type>>
{
private readonly IDictionary<string, Type> _directory = new Dictionary<string, Type>();
public void Add<T>(string name)
{
_directory.Add(name, typeof(T));
}
public IEnumerator<KeyValuePair<string, Type>> GetEnumerator()
{
return _directory.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return _directory.GetEnumerator();
}
}
我能做到:
var collection = new FooCollection();
collection.Add<Foo>("Foo");
collection.Add<Bar>("Bar");
collection.Add<Baz>("Baz");
但我想使用集合初始化器。我可以这样做吗?怎么样?
我认为使用您拥有的通用 Add
方法是不可能的。由于泛型类型参数与实际参数之间没有关系,因此无法通过集合初始值设定项确定泛型类型。
一个想法可能是添加一个看起来像这样的重载:
public void Add(string name, Type t)
{
_directory.Add(name, t);
}
然后使用集合初始化器:
var collection = new FooCollection()
{
{ "Foo", typeof(Foo) },
{ "Bar", typeof(Bar) },
{ "Baz", typeof(Baz) },
};
不幸的是,正如您正确指出的那样,这消除了添加泛型类型约束的可能性。除非您实际提供可用于推断类型的泛型类型的参数,否则我认为这是不可能的。
你可以试试这个:
public static class StringToTypeMapExtensions
{
public static void Add<T>(this StringToTypeMap map, T prototype)
where T : SomeBase
{
map.Add(typeof(T).Name, typeof(T));
}
}
public class StringToTypeMap : Dictionary<string, Type>
{
}
public class SomeBase { }
public class Foo : SomeBase { }
public class Bar : SomeBase { }
public class Baz : Bar { }
public class Alien { }
这将允许你写:
class Program
{
static void Main(string[] args)
{
var map =
new StringToTypeMap
{
default(Foo),
default(Bar),
default(Baz)
};
foreach (var key in map.Keys)
{
Console.WriteLine("{0} : {1}", key, (object)map[key] ?? "(null)");
}
Console.ReadKey();
}
}
(因此,避免仅仅为了它的 Add(Type value) 方法而强迫您实现 ICollection < Type >)
或者这也将按预期进行编译和运行:
var map =
new StringToTypeMap
{
{ string.Empty, null },
{ "Integer", typeof(int) },
{ nameof(Decimal), typeof(decimal) },
default(Foo),
default(Bar),
default(Baz)
};
foreach (var key in map.Keys)
{
// etc
}
但这不会编译(因为外星人):
var map =
new StringToTypeMap
{
default(Foo),
default(Bar),
default(Baz),
default(Alien)
};
(这是有效的,因为集合初始化器也支持 "Add" 扩展方法,当它们在范围内时)
参见:https://msdn.microsoft.com/en-us/library/bb384062.aspx
(引用)
"Collection initializers let you specify one or more element initializers when you initialize a collection class that implements IEnumerable or a class with an Add extension method [...]"
'希望对您有所帮助。
我可以在 class 上使用集合初始值设定项吗?Add
方法采用通用参数?
我的 class 看起来像这样:
public class FooCollection : IEnumerable<KeyValuePair<string, Type>>
{
private readonly IDictionary<string, Type> _directory = new Dictionary<string, Type>();
public void Add<T>(string name)
{
_directory.Add(name, typeof(T));
}
public IEnumerator<KeyValuePair<string, Type>> GetEnumerator()
{
return _directory.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return _directory.GetEnumerator();
}
}
我能做到:
var collection = new FooCollection();
collection.Add<Foo>("Foo");
collection.Add<Bar>("Bar");
collection.Add<Baz>("Baz");
但我想使用集合初始化器。我可以这样做吗?怎么样?
我认为使用您拥有的通用 Add
方法是不可能的。由于泛型类型参数与实际参数之间没有关系,因此无法通过集合初始值设定项确定泛型类型。
一个想法可能是添加一个看起来像这样的重载:
public void Add(string name, Type t)
{
_directory.Add(name, t);
}
然后使用集合初始化器:
var collection = new FooCollection()
{
{ "Foo", typeof(Foo) },
{ "Bar", typeof(Bar) },
{ "Baz", typeof(Baz) },
};
不幸的是,正如您正确指出的那样,这消除了添加泛型类型约束的可能性。除非您实际提供可用于推断类型的泛型类型的参数,否则我认为这是不可能的。
你可以试试这个:
public static class StringToTypeMapExtensions
{
public static void Add<T>(this StringToTypeMap map, T prototype)
where T : SomeBase
{
map.Add(typeof(T).Name, typeof(T));
}
}
public class StringToTypeMap : Dictionary<string, Type>
{
}
public class SomeBase { }
public class Foo : SomeBase { }
public class Bar : SomeBase { }
public class Baz : Bar { }
public class Alien { }
这将允许你写:
class Program
{
static void Main(string[] args)
{
var map =
new StringToTypeMap
{
default(Foo),
default(Bar),
default(Baz)
};
foreach (var key in map.Keys)
{
Console.WriteLine("{0} : {1}", key, (object)map[key] ?? "(null)");
}
Console.ReadKey();
}
}
(因此,避免仅仅为了它的 Add(Type value) 方法而强迫您实现 ICollection < Type >)
或者这也将按预期进行编译和运行:
var map =
new StringToTypeMap
{
{ string.Empty, null },
{ "Integer", typeof(int) },
{ nameof(Decimal), typeof(decimal) },
default(Foo),
default(Bar),
default(Baz)
};
foreach (var key in map.Keys)
{
// etc
}
但这不会编译(因为外星人):
var map =
new StringToTypeMap
{
default(Foo),
default(Bar),
default(Baz),
default(Alien)
};
(这是有效的,因为集合初始化器也支持 "Add" 扩展方法,当它们在范围内时)
参见:https://msdn.microsoft.com/en-us/library/bb384062.aspx
(引用)
"Collection initializers let you specify one or more element initializers when you initialize a collection class that implements IEnumerable or a class with an Add extension method [...]"
'希望对您有所帮助。