声明具有有界类型的泛型字典

本文关键字:泛型 字典 声明 类型 | 更新日期: 2023-09-27 18:00:28

我需要声明一个以Type为键、以实例为值的Dictionary

我需要将键类型限制为特定的类层次结构。

对于Java地图,我可以做如下操作:

Map<Class<? extends MySuperClass>, ? extends MySuperClass>

我如何在C#中实现这一点?

声明具有有界类型的泛型字典

不要直接暴露Dictionary,这样可以手动控制何时添加

public void AddToDictionary(Type key, object value)
{
    if(!key.IsAssignableFrom(typeof(SomeBaseClass))
        throw new ArgumentException("Must be an inherited from SomeBaseClass type");
    dictionary.Add(key, value);
}

我认为Sinatr公开一个添加到字典而不是字典本身的方法是一个非常好的主意。唯一的缺点是没有编译时的安全性;如果某些代码添加了错误类型的对象,那么直到运行时才会发现。

然而,使用泛型,我们可以调整方法,以便添加对象是万无一失的:

public void AddToDictionary<T>(T value) where T: MySuperClass
{
    dict.Add(typeof(T), value);
}

现在,编写一个添加了错误类型的对象却仍在编译的程序是不可能的。

您可以使用typeof来获取类的类型,例如:

Map<System.Type, object>

我不确定你会如何强制执行这项延期。在添加到地图之前,这可能应该作为一个测试来进行。

您可以:

public class MyType<TBase>
{
    private Type Value;
    protected MyType()
    {
    }
    public static implicit operator Type(MyType<TBase> type)
    {
        return type.Value;
    }
    public static implicit operator MyType<TBase>(Type type)
    {
        if (type == null)
        {
            throw new ArgumentNullException();
        }
        if (!typeof(TBase).IsAssignableFrom(type))
        {
            throw new ArgumentException();
        }
        return new MyType<TBase> { Value = type };
    }
    public override bool Equals(object obj)
    {
        if (obj == null)
        {
            return false;
        }
        var type = obj as MyType<TBase>;
        return type != null && Value.Equals(type.Value);
    }
    public override int GetHashCode()
    {
        return Value.GetHashCode();
    }
    public override string ToString()
    {
        return Value.ToString();
    }
}

然后:

Dictionary<MyType<MySuperClass>, MySuperClass> dict = new Dictionary<MyType<MySuperClass>, MySuperClass>();
dict.Add(typeof(MyClass1), new MyClass1());

MyType具有从/到Type的隐式运算符,因此使用起来非常简单。您只需将Type强制转换为MyType(或将MyType强制转换为Type),它就可以正常工作。TryGetValue():示例

MySuperClass ms;
if (!dict.TryGetValue(typeof(MyClass1), out ms))
{
    throw new Exception();
}

请注意,检查是在运行时完成的