使用类型和操作在 C# 中查找 table

Look-up table in C# with Types and Actions

我想将我的 many if 更改为查找 table。

我有类型和方法。我想把它们配对。

if (propertyType == typeof(bool) || propertyType == typeof(bool?))
DoBool(propertyType);

if (propertyType == typeof(DateTime) || propertyType == typeof(DateTime?))
DoDateTime(propertyType);

if (propertyType == typeof(Guid) || propertyType == typeof(Guid?))
DoGuid(propertyType);

我必须创建一个 Dictionary<Type, Action>()?或者哪种方法最优雅?

你能给我一些建议吗?我可以从哪里开始或在哪里可以找到解决方案?

您可以创建 Dictionary<Type, Action<Type>>:

var dict = new Dictionary<Type, Action<Type>>() {
    {typeof(bool), DoBool},
    {typeof(bool?), DoBool},
    {typeof(DateTime), DoDateTime},
    {typeof(Datetime?), DoDateTime},
    {typeof(Guid), DoGuid},
    {typeof(Guid?), DoGuid}
};

然后这样称呼它:

dict[propertyType](propertyType)

您可以创建一个方法来使用指定类型初始化查找 table,以避免重复。

private readonly IDictionary<Type, Action<Type>> _lookup;

然后你可以定义初始化方法 _dict,

private void AddEntry<T>(Action<Type> action) where T : struct
{       
    _lookup[typeof(T)] = action;
    _lookup[typeof(Nullable<T>)] = action;
}

private void DoInt(Type type) { /* implementation */ }

AddEntry<bool>(type => { /* implementation */ });
AddEntry<int>(DoInt);

因为这更多的是控制代码流而不是纯粹的查找,我可能会使用面向对象的方法并将每个 "handler" 的代码放在单独的 classes 中(使用公共基地里面的东西 class)。

你可以创建一个像

这样的通用接口
public interface ITypeHandler {
    void HandleType(Type type);
}

... 如果愿意,将处理程序的实现放在类型 Dictionary<Type, ITypeHandler> 的字典中,或者您可以在接口上有一个 属性 来显示它处理的类型和 select 来自基于此 属性.

的(可能是依赖注入的)处理程序列表

这增加了关注点分离、可测试性等好处。

(请注意,*Handler 不是一个很好的名称,您必须根据所涵盖的场景创建一个更好的名称。)

我创建了自己的实现,有点不同,但我使用了@DaggeJ 的建议,非常感谢!

首先,我创建了一个基本处理程序 class。之后我在不同类型 classes 上使用了这个基础。你可以在下面看到它。

基类:

public abstract class QueryHandler<T> where T : class
{
    //I added here more property. 

    public abstract Type[] Types { get; }

    protected QueryHandler(//Properties)
    {
        //Properties null check
    }

    public abstract IQueryable<T> Handle();
}

后代 class:

internal class GuidQuery<T> : QueryHandler<T> where T : class
{
    public override Type[] Types => new Type[] { typeof(Guid), typeof(Guid?) };

    public GuidQuery(//Properties) : base(//Properties)
    {
    }

    public override IQueryable<T> Handle()
    {
        // Implementation
    }
}

用法:

public IQueryable<T> GetQuery()
{
    var queryHandlerList = new List<QueryHandler<T>>()
    {
        new IntQuery<T>(//Properties),
        new DateTimeQuery<T>(//Properties),
        new StringQuery<T>(//Properties),
        new BoolQuery<T>(//Properties),
        new GuidQuery<T>(//Properties),
        new EnumQuery<T>(//Properties)
    };
}

return query = queryHandlerList.FirstOrDefault(h => GetType<T>(h, property.PropertyType)).Handle();

private bool GetType<T>(QueryHandler<T> handler, Type type) where T: class
{
    if (handler.Types.FirstOrDefault(t => t == type) == type || handler.Types.FirstOrDefault(t => t == type.BaseType) == type.BaseType) return true;

    return false;
}