C# 函数内泛型类型的访问属性

C# 函数内泛型类型的访问属性,c#,generics,azure-cosmosdb,C#,Generics,Azure Cosmosdb,我有一个查询CosmosDB API的通用函数GetDocuments。泛型受自定义i文档接口的约束。目前,我正在将一个枚举作为参数传递给这个函数,该函数确定文档的类型——但是,我的接口将文档类型作为属性,因此我似乎应该能够以某种方式访问它,而不是传递另一个参数 因为我的参数位于表达式中,所以我不确定如何访问该值(我不确定使用API访问表达式参数是否正确)。如果我有一个IDocument作为参数,那么访问它似乎非常简单 给定此代码,如何访问DocumentType,而不将其传递给GetDocum

我有一个查询CosmosDB API的通用函数
GetDocuments
。泛型受自定义
i文档
接口的约束。目前,我正在将一个枚举作为参数传递给这个函数,该函数确定文档的类型——但是,我的接口将文档类型作为属性,因此我似乎应该能够以某种方式访问它,而不是传递另一个参数

因为我的参数位于
表达式中,所以我不确定如何访问该值(我不确定使用API访问表达式参数是否正确)。如果我有一个
IDocument
作为参数,那么访问它似乎非常简单

给定此代码,如何访问
DocumentType
,而不将其传递给
GetDocuments

功能定义:

public IEnumerable<T> GetDocuments<T>(Expression<Func<T, bool>> predicate, Enumerations.DocumentType type) where T : IDocument
{
    var results = Client.CreateDocumentQuery<T>(GetDocumentCollectionUri(), GetFeedOptions())
        .Where(predicate)
        .Where(s => s.DocumentType == type)
        .ToList();

    return results;
}
函数调用:

var messages = mailboxRepository.GetDocuments<MailboxMessageTemplate>(
            s => s.UserId == user.ID,
            Enumerations.DocumentType.MessageTemplate);
var messages=mailboxRepository.GetDocuments(
s=>s.UserId==user.ID,
枚举.DocumentType.MessageTemplate);

那么您正在寻找一种将
表达式
转换为
函数
的方法

你可以打电话

将表达式树描述的lambda表达式编译为可执行代码,并生成表示lambda表达式的委托

var results=Client.CreateDocumentQuery(GetDocumentCollectionUri(),GetFeedOptions())
.Where(predicate.Compile())
.其中(s=>s.DocumentType==type)
.ToList();

您可以通过预先创建表达式并将其添加到查询中来实现

下面是一个可以实现此目的的表达式

internal static Expression<Func<T, bool>> TypeSpecificExpression<T>() where T : class
{
    var parameter = Expression.Parameter(typeof(IDocument));
    var member = Expression.Property(parameter, nameof(IDocument.Enumerations.DocumentType));
    var contant = Expression.Constant(nameof(T));
    var body = Expression.Equal(member, contant);
    var extra = Expression.Lambda<Func<T, bool>>(body, parameter);
    return extra;
}
内部静态表达式TypeSpecificExpression(),其中T:class
{
var参数=表达式参数(typeof(IDocument));
var member=Expression.Property(参数,nameof(IDocument.Enumerations.DocumentType));
var contant=表达式常数(名称(T));
变量体=表达式.Equal(成员,contant);
var extra=表达式.Lambda(主体,参数);
额外返还;
}
然后,您可以简单地将方法更改为:

public IEnumerable<T> GetDocuments<T>(Expression<Func<T, bool>> predicate) where T : IDocument
{
    var results = Client.CreateDocumentQuery<T>(GetDocumentCollectionUri(), GetFeedOptions())
        .Where(predicate && TypeSpecificExpression())
        .ToList();

    return results;
}
public IEnumerable GetDocuments(表达式谓词),其中T:IDocument
{
var results=Client.CreateDocumentQuery(GetDocumentCollectionUri(),GetFeedOptions())
.Where(谓词和类型特定表达式())
.ToList();
返回结果;
}
显然,我没有权限访问
枚举.DocumentType
枚举,因此您可能需要对此处设置的值进行一些推文:
var contant=Expression.Constant(nameof(t))

另外,您不应该像在
CreateDocumentQuery
上那样调用
.ToList()
。您正在同步一个可能会严重影响性能的查询。您应该使用
.AsDocumentQuery()
方法获取查询,然后在
query.HasMoreResults
时调用
query.ExecuteNextAsync

另一方面,看起来您正在尝试构建库已经完成的功能,包括您刚才询问的功能(您可以找到该方法)。值得一看


免责声明:我让宇航员

表达式只是围绕谓词的一棵树。你的论点在表达式中是什么意思?你能举个例子说明你期望的结果吗?哦,我想我明白你的意思了。让我写一个答案。我认为这是不可能的。T是一个类型参数,不是T的实例。T保证是IDocument,但它不是它的实例,因此不能查询它的任何属性。唯一可行的方法是使用new T()创建一个T实例(您需要一个“new()”泛型约束),然后询问您的新实例它的文档类型。似乎是浪费,但Houghop希望消除向方法传递DocumentType值的需要。OP想从类型参数@Dave提供的信息中得到它,你是说实现
IDocument
的每个类型都对应一个
枚举值。DocumentType
?我不确定,你必须问OP。我所说的是OP希望在他们的方法签名中不需要DocumentType参数(至少他们的问题似乎暗示了这一点)
internal static Expression<Func<T, bool>> TypeSpecificExpression<T>() where T : class
{
    var parameter = Expression.Parameter(typeof(IDocument));
    var member = Expression.Property(parameter, nameof(IDocument.Enumerations.DocumentType));
    var contant = Expression.Constant(nameof(T));
    var body = Expression.Equal(member, contant);
    var extra = Expression.Lambda<Func<T, bool>>(body, parameter);
    return extra;
}
public IEnumerable<T> GetDocuments<T>(Expression<Func<T, bool>> predicate) where T : IDocument
{
    var results = Client.CreateDocumentQuery<T>(GetDocumentCollectionUri(), GetFeedOptions())
        .Where(predicate && TypeSpecificExpression())
        .ToList();

    return results;
}