如何使用Dynamic LINQ同时查询不同对象类型的表达式

时间:2012-01-05 11:55:02

标签: c# linq dynamic-linq

我一直在尝试使用Dynamic LINQ作为场景的解决方案,我需要允许用户根据分配给它的“标记”选择一系列文件。 E.g。

File A - tagged as "a",
File B - tagged as "b",
File C - tagged as "c",
File D - tagged as "d" and "a"

因此,如果我想找到标记为“a”的所有文件,我会输入:

tag = "a"

我会得到文件和文件d。但我也可以输入

tag = "a" OR tag = "b"

所以我会检索文件a,b和d

这只是一个例子!

因此,在这种情况下,我可以使用以下代码实现此目的:

List<FileMeta.Filetag> tags = fetchAllTags(file); //this fetches the tags from the file and places them in a list
            if (tags != null) //just in case
            {
                //declare the type of parameter we are looking for - in this case a "tag"
                var p = Expression.Parameter(typeof(string), "Tag");
                //setup the lambda parser to accept the param type, and use the expression
                var z = System.Linq.Dynamic.DynamicExpression.ParseLambda(new[] { p }, null, equation);

                //for each tag in this file
                foreach (FileMeta.Filetag t in tags)
                {
                    //if it hasn't been found yet
                    if (!bFound)
                    {
                        bFound = (bool)z.Compile().DynamicInvoke(t.tag);
                    }
                }
            }

所以我在这里检索文件中的标签,并枚举它们以检查它们是否符合输入的公式。这一切都很好,工作正常。

我遇到的问题是以下情况。

这些文件的“标签”实际上存储在文件的备用流信息中,以及有效的文件“元”信息的其他信息。文件可能包含1个或多个元信息。因此,所有内容都被序列化为单个流,文件作为来自类型对象的XML数据 - 您可能已经注意到上面代码中的List是FileMeta.Filetag类型。所有对象都从名为Filemetabaseobject的基础对象继承。

所以我无法理解的是,如果我想看一下不同类型的物体,例如一个Filedate对象,与Filetag对象同时,动态LINQ是否可以传递它的基类型(Filemetabaseobject)中的每个对象,并以某种方式进行某些转换?

我问,因为在一个完美的场景中,我希望能够查询这个元信息,例如,例如,tag =“a”AND date =“01/01/2012”,但我遇到的问题是“标签”将出现在Filetag对象中,“日期”显然位于Filedate对象中作为属性:例如在一个简单的场景中:

public class Filemetabaseobject
{

}
public class Filetag : Filemetabaseobject
    {
        public string tag { get; set; }
    }
public class Filedate : Filemetabaseobject
{
    public string date { get; set; }
}

有解决方法吗?

提前致谢!

抱歉,我已添加,用户可以输入几乎任何类型的查询,例如(tag =“a”AND tag =“b”)OR tag =“c”或者他们可以输入(tag =“a例如,“AND tag =”b“AND tag =”c“)。

2 个答案:

答案 0 :(得分:0)

您可以为FileMetabaseObject提供一个名为Value的抽象只读字符串属性,然后在所有子类中覆盖它:

public abstract class FileMetabaseObject {
    public abstract string Value { get; }
}

public class FileTag : FileMetabaseObject {
    public string Tag { get; set; }
    public override string Value { get { return Tag; } }
}

然后你就可以使用

List<Func<FileMetabaseObject,bool>> whereClauses = 
    new List<Func<FileMetabaseObject,bool>> { 
        m => m.Value == "foo", 
        m => m.Value == DateTime.Today.ToShortDateString() };

bool meetsCriteria = whereClauses.
    All(criteria => fileMetadataColl.
        Any(meta => criteria(meta));

不过很清楚Linq在这方面的动态是多么有用。

答案 1 :(得分:0)

在sq33G上面提出的有关暴露值属性的抽象类的建议的帮助下,我已经能够解决这个问题。

基本上所有类型(包括标签)都继承自Filemetabaseobject,具有一个名为“value”的可覆盖属性,该属性设置为您要为搜索公开的内容,您可以从继承的对象设置get值来检索您想要的任何内容要找到的那个对象。

然后使用Dynamic LINQ ParseLambda方法的以下实现,您可以传递继承的对象类型,因为它的基类等效,并且它仍然能够查看任何类型的继承对象,基于能够看到这个被覆盖属性:

//If we pass in type of filemetabaseobject, because all file metas inherit from it, and we have exposed an overridde property of "value" to all objects, we can just consult that on all types (where lequation is the string representing the equation):
var z = System.Linq.Dynamic.DynamicExpression.ParseLambda(typeof(FileMeta.Filemetabaseobject), typeof(bool), lequation);
//invoke the query - true will be returned if the query is valid against the property(ies) exposes
bFound = (bool)z.Compile().DynamicInvoke(t); //where t is my filetag that I'm querying against, but could be anything that inherits from filemetabaseobject