【问题标题】:Look-up table in C# with Types and Actions在 C# 中使用类型和操作查找表
【发布时间】:2019-06-15 15:24:18
【问题描述】:

我想将我的许多 if 更改为查找表。

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

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>> - 这听起来就像您向我们展示的内容一样。
  • @JonSkeet 谢谢,当我创建这个字典时,我如何使用它来代替 if 语句?
  • if (myDictionary.TryGetValue(myType, out var action)) action(myType);:检查给定类型(myType)是否存在action,如果存在,则执行action
  • 如果您确信总会有一个条目,您可以使用dictionary[propertyType].Invoke(propertyType)。否则,您需要使用 TryGetValue 并仅在有条目时才调用该值。鉴于propertyType 无论如何都是关键,您当然可以使用Dictionary<Type, Action> 并只注册将在必要时传递适当参数的操作。如果不了解您的方法,很难知道什么是最好的。
  • @JonSkeet 感谢您的回答,对我帮助很大。

标签: c# dictionary methods types lookup-tables


【解决方案1】:

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

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

基类:

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();
}

后代类:

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;
}

【讨论】:

    【解决方案2】:

    您可以创建一个方法来初始化具有指定类型的查找表,以避免重复。

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

    【讨论】:

    • 谢谢约翰尼,我会在找到时混合,这足以开始我自己的解决方案。
    【解决方案3】:

    由于这更多地是关于控制代码流而不是纯粹的查找,我可能会使用面向对象的方法并将每个“处理程序”的代码放在单独的类中(在基类中包含通用的东西)。

    您可以创建一个通用接口,如

    public interface ITypeHandler {
        void HandleType(Type type);
    }
    

    ...如果您愿意,可以将处理程序的实现放在Dictionary&lt;Type, ITypeHandler&gt; 类型的字典中,或者您可以在接口上设置一个属性来显示它处理的类型并从列表中选择(可能是依赖注入)基于此属性的处理程序。

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

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

    【讨论】:

      【解决方案4】:

      你可以创建一个Dictionary&lt;Type, Action&lt;Type&gt;&gt;:

      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)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-12-07
        • 2016-05-28
        • 2021-02-09
        • 1970-01-01
        相关资源
        最近更新 更多