Add方法泛型参数的集合初始值设定项?

时间:2016-10-11 17:46:16

标签: c# object-initializers

我可以在我的类上使用一个带有Add方法的集合初始值设定项,该方法采用泛型参数吗?

我的班级看起来像这样:

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");

但我想使用集合初始化程序。我能这样做吗?怎么样?

2 个答案:

答案 0 :(得分:1)

你可以试试这个:

    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&lt; Type&gt;)

或者,这也将按预期编译和运行:

            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
            }

但这不会编译(因为Alien):

            var map =
                new StringToTypeMap
                {
                    default(Foo),
                    default(Bar),
                    default(Baz),
                    default(Alien)
                };

(这是有效的,因为集合初始值设定者也会尊重&#34;添加&#34;扩展方法,当它们在范围内时)

请参阅:https://msdn.microsoft.com/en-us/library/bb384062.aspx

(引用)

&#34;当初始化实现IEnumerable 的集合类或具有Add扩展方法的类 [...]&#34;时,集合初始值设定项允许您指定一个或多个元素初始值设定项。

&#39;希望这会有所帮助。

答案 1 :(得分:0)

我认为使用通用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) },
};

不幸的是,正如您正确指出的那样,这消除了添加泛型类型约束的可能性。除非您实际提供可用于推断类型的泛型类型的参数,否则我认为这是不可能的。