从枚举列表生成Linq或子句

Gar*_*rry 3 c# linq

问候Overflowers,

我正在开发一个允许用户生成自定义报告的应用程序,我有一个场景,我需要从枚举值列表中生成Linq Or子句.我遇到的问题是我看不到生成Or子句的优雅方式.

例如:

//Enumeration of possible 'OR' conditions
public enum Conditions
{
    ByAlpha,
    ByBeta,
    ByGamma
}

//'Entity' I'm querying against.
class ResultObject
{
    public bool AlphaValue { get; set; }
    public bool BetaValue { get; set; }
    public bool GammaValue { get; set; }
    public string Name { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        //Create list of desired conditions.  
        //Basically I want this to mimic the query, 
        // "Show me all of the ResultObjects where the AlphaValue is true or the GammaValue is true".
        var conditions = new List<Conditions>
        {
            Conditions.ByAlpha,
            Conditions.ByGamma
        };

        //Sample collection of objects.  This would normally be a collection of EF entities. 
        var sampleCollection = new List<ResultObject>
        {
            new ResultObject
            {
                Name = "Sample 1",
                AlphaValue = true,
                BetaValue = true,
                GammaValue = true,
            },
            new ResultObject
            {
                Name = "Sample 2",
                AlphaValue = false,
                BetaValue = false,
                GammaValue = false,
            },
            new ResultObject
            {
                Name = "Sample 3",
                AlphaValue = true,
                BetaValue = false,
                GammaValue = true,
            }
        };

        var sampleCollectionQueryable = sampleCollection.AsQueryable();

        //This should filter the sampleCollection down to containing only the 
        //"Sample 3" ResultObject; instead, it filters out all of the ResultObjects.
        var query = GenerateOrClause(sampleCollectionQueryable, conditions);
    }

    static IQueryable<ResultObject> GenerateOrClause(IQueryable<ResultObject> query, List<Conditions> conditions)
    {
        //This approach generates a series of AND statements, instead I need a series of OR statements
        //for each condition.
        foreach (var condition in conditions)
        {
            switch (condition)
            {
                case Conditions.ByAlpha:
                    query = query.Where(x => x.AlphaValue);
                    break;
                case Conditions.ByBeta:
                    query = query.Where(x => x.BetaValue);
                    break;
                case Conditions.ByGamma:
                    query = query.Where(x => x.GammaValue);
                    break;
                default:
                    throw new ArgumentOutOfRangeException();
            }
        }

        return query;
    }
}
Run Code Online (Sandbox Code Playgroud)

有任何想法吗?

jas*_*son 6

你应该做Conditions一个Flags枚举:

[Flags]
public enum Conditions {
    ByNone = 0,
    ByAlpha = 1,
    ByBeta = 2,
    ByGamma = 4
}
Run Code Online (Sandbox Code Playgroud)

并更改ResultObject:

class ResultObject {
    public Conditions Conditions { get; set; }
    public string Name { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

然后你可以说:

var conditions = new List<Conditions> { Conditions.ByAlpha, Conditions.ByGamma };
var matches = sampleCollection
                  .Where(x => conditions.Select(c => c & x != 0).Any());
Run Code Online (Sandbox Code Playgroud)

您尝试解决的问题的正确设计.

如果由于某种原因你需要保持你的电流ResultObject,我现在OldResultObject将为了清楚起见:

class OldResultObject {
    public bool AlphaValue { get; set; }
    public bool BetaValue { get; set; }
    public bool GammaValue { get; set; }
    public string Name { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

将它投射到新的很容易ResultObject:

var resultObject = new ResultObject {
    Conditions =
        (oldResultObject.AlphaValue ? Conditions.ByAlpha : Conditions.ByNone) | 
        (oldResultObject.BetaValue ? Conditions.ByBeta : Conditions.ByNone) |
        (oldResultObject.GammaValue ? Conditions.ByGamma : Conditions.ByNone),
    Name = oldResult.Name;
}
Run Code Online (Sandbox Code Playgroud)

所以这对你来说真的很难重新设计.