函数内部通用类型的访问属性

时间:2019-01-14 17:56:09

标签: c# generics azure-cosmosdb

我有一个通用函数GetDocuments<T>,用于查询CosmosDB API。泛型受自定义IDocument接口的约束。目前,我正在将枚举作为参数传递给该函数,该函数确定文档的类型-但是,我的界面将文档类型作为属性,因此看来我应该能够以某种方式访问​​它通过另一个arg。

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

鉴于此代码,如何在不将其传递给DocumentType的情况下访问GetDocuments<T>

函数定义:

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

接口定义:

public interface IDocument
{
    [JsonProperty(PropertyName = "id")]
    string Id { get; set; }
    [JsonProperty(PropertyName = "documentType")]
    Enumerations.DocumentType DocumentType { get; }
}

函数调用:

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

2 个答案:

答案 0 :(得分:2)

您可以通过预先创建表达式并将其添加到查询中来做到这一点。

这是可以解决问题的表达式。

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

很显然,我无权访问Enumerations.DocumentType枚举,因此您可能需要对以下内容进行微博:var contant = Expression.Constant(nameof(T));

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

另一方面,您似乎正在尝试构建库Cosmonaut已经完成的工作,包括您刚刚询问问题的功能(您可以找到方法here) 。值得一看。

免责声明:我是宇航员

答案 1 :(得分:0)

所以您正在寻找一种将Expression<Func<T, bool>>转换为Func<T, bool>的方法吗?

您可以致电Compile

  

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

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