用C#

时间:2017-06-23 13:34:05

标签: c# syntax open-closed-principle

我正在尝试创建一种优雅且可扩展的查询字典的方法,该字典将枚举映射到一组字符串。

所以我有这个类SearchFragments,里面有字典。然后我想要一个方法,其中这个类的消费者可以简单地问“HasAny”,这是我正在努力的一点,只需传递一些查询,如表达式并获得布尔答案。

public class SearchFragments
{
    private readonly IDictionary<SearchFragmentEnum, IEnumerable<string>> _fragments;

    public SearchFragments()
    {
        _fragments = new Dictionary<SearchFragmentEnum, IEnumerable<string>>();
    }

    public bool HasAny(IEnumerable<SearchFragmentEnum> of)
    {
        int has = 0;
        _fragments.ForEach(x => of.ForEach(y => has += x.Key == y ? 1 : 0));
        return has >= 1;
    }
}

目前的问题是,这个类的消费者现在必须构建一个可能非常混乱的IEnumerable<SearchFragmentEnum>

我正在寻找的是消费代码能够写下以下内容:

searchFragments.HasAny(SearchFragmentEnum.Name, SearchFragmentEnum.PhoneNumber)

但是这个参数列表的大小可能会有所不同(没有我必须在SearchFragments类中为每个可能的组合编写方法重载(如果在将来将新值添加到SearchFragmentEnum中约会我不必更新课程。

3 个答案:

答案 0 :(得分:5)

您可以使用params[]

public bool HasAny(params SearchFragmentEnum[] of)
{ ...

旁注:您知道LIN(Q)查询应该只查询源并且不会引起任何副作用吗?但是您的查询会不必要地增加整数:

_fragments.ForEach(x => of.ForEach(y => has += x.Key == y ? 1 : 0));

而是使用它(也更有效,更可读):

return _fragments.Keys.Intersect(of).Any();

更有效的替代方案是Sergey's想法:

return of?.Any(_fragments.ContainsKey) == true; 

答案 1 :(得分:3)

对于c#中可变大小的参数,请使用params关键字:     public int HasAny(params SearchFragmentEnum [] of)

出于性能原因,.Net API通常会提供一些重载;传递的参数将复制到新数组中。明确地为最常见的情况提供重载可以避免这种情况。

public int HasAny(SearchfragmentEnum of1)
public int HasAny(SearchFragmentEnum of1, SearchFragmentEnum of2)
etc.

您也可以考虑使用[Flags]属性标记枚举,而不是使用参数。参数可以像HasAny(SearchFragmentEnum.Name | SearchFragmentEnum.PhoneNumber一样传递。 StackOverflow上丰富的示例(例如Using a bitmask in C#

答案 2 :(得分:3)

使用params关键字允许不同数量的参数。此外,您可以通过循环较小的of数组来简化代码。此外,您正在使用具有O(1)密钥检查的字典,因此没有内部循环:

public bool HasAny(params SearchFragmentEnum[] of)
{
    foreach(var o in of) {
        if (this._fragments.ContainsKey(o))
            return true;
    }   
    return false;
}

或更短的LINQ

public bool HasAny(params SearchFragmentEnum[] of) {
    return of?.Any(_fragments.ContainsKey) ?? false;
}