使用具有"Type"键的字典对类型安全设置

Jus*_*tin 6 c# generics dictionary type-safety

我有一个对象的通用字典,其中键的类型为Type:

public class DynamicObject : IDictionary<Type, object>
Run Code Online (Sandbox Code Playgroud)

这个想法是这个对象在基于插件的架构中共享,因此一个类型(可以驻留在插件.dll中)被用作键,以防止插件之间的冲突.此类型还用于存储有关字段的元数据(例如该字段的描述或该字段的实际类型).

目前,插件需要使用与此类似的代码设置此对象上的字段值:

DynamicObject someObject;
string someValue;
someObject[typeof(UsernameField)] = someValue;
Run Code Online (Sandbox Code Playgroud)

唯一的问题是这不是类型安全的 - 即使类型UsernameField知道它所期望的值的确切类型(例如int或在这种情况下string),这里提供的值只是作为对象键入.我想使用泛型来设置/获取属性类型安全,但我不确定如何.到目前为止,我提出的最好的是:

// Field is a base class for all types used as keys on DynamicObject
[Description("Username of the user")]
public class UsernameField : Field
{
    public static void Set(DynamicObject obj, string value)
    {
        obj[typeof(UsernameField)] = someValue;
    }
}

// To set fields
UsernameField.Set(obj, someValue);
Run Code Online (Sandbox Code Playgroud)

这是类型安全的,但这意味着我的每个字段类型(例如UsernameField)都具有几乎相同的静态Set方法.

如何在不对每种字段类型使用大量几乎相同的方法的情况下以这种方式对值进行类型安全访问?

顺便Type说一句,使用像这样的关键是一个好主意还是有一些隐藏的陷阱,我还没有意识到?

Oli*_*bes 2

定义所有插件都必须实现的接口:

public interface IPlugin {
    string Name { get; }
    string Author { get; }
    string Description { get; }
    void Init();
}
Run Code Online (Sandbox Code Playgroud)

然后使用一个Dictionary<Type, IPlugIn>.

通常,该接口在单独的 dll 中声明(如“MyCompany.MyProject.PlugIns.Contracts.dll”)。


编辑:好的,我想我现在明白你的意思了。

诀窍是在泛型方法之间建立一个泛型类Field,并UsernameField使用泛型Set方法。事实上,它Field不是通用的,使得所有字段类型都可以分配给它。如果将其声明为 ,情况就不会如此Field<T>

public abstract class Field
{
}

public abstract class GenericField<T> : Field
{
    public void Set(DynamicObject obj, T value)
    {
        obj[this.GetType()] = value;
    }
}

public class UsernameField : GenericField<string>
{
    #region Singleton Pattern

    public static readonly UsernameField Instance = new UsernameField();

    private UsernameField() { }

    #endregion

}
Run Code Online (Sandbox Code Playgroud)

因为我们需要调用GetTypeSet方法,所以我们不能将其声明为static. 因此,我使用了单例模式。

现在,我们可以以类型安全的方式设置字段:

UsernameField.Instance.Set(obj, "Joe");
Run Code Online (Sandbox Code Playgroud)

附加 1:

由于现在字段是单例,因此您可以使用字段作为字典的键而不是它们的类型。

public class DynamicObject : IDictionary<Field, object> { }
Run Code Online (Sandbox Code Playgroud)

Set会变成:

public void Set(DynamicObject obj, T value)
{
    obj[this] = value;
}
Run Code Online (Sandbox Code Playgroud)

补充 2:

你也可以DynamicObject这样定义:

public class DynamicObject : Dictionary<Field, object>
{
    public void Set<T>(GenericField<T> field, T value)
    {
        this[field] = value;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在您可以像这样设置值:

obj.Set(UsernameField.Instance, "Sue");
Run Code Online (Sandbox Code Playgroud)

这是类型安全的并且看起来更自然。Set中的方法现在GenericField已经过时了。