【问题标题】:Expression to create a Tuple with variable number of generic type arguments用于创建具有可变数量的泛型类型参数的元组的表达式
【发布时间】:2017-11-13 16:04:06
【问题描述】:

我正在尝试构建一个表达式来创建具有可变数量的泛型类型参数的泛型 Tuple<> 实例。

生成Tuple<> 实例的想法是基于具有KeyAttribute 的属性为实体类型动态创建复合键值。然后复合键将用作Dictionary<object, TEntity> 中的键。因此,应该为某个实体类型构建 lambda 表达式,然后调用 lambda,传递 TEntity 的实例以获取 Tuple<> 形式的复合键。

实体模型示例

public class MyEntityModel
{
    [Key]
    public string Key1 { get; set; }
    [Key]
    public Guid Key2 { get; set; }
    public int OtherProperty { get; set; }
}

应该怎么表达

public Func<MyEntityModel, object> BuildKeyFactory()
{
    // This is how the LambdaExpression should look like, but then for a generic entity type instead of fixed to MyEntityModel
    return new Func<MyEntityModel, object>(entity => new Tuple<string, Guid>(entity.Key1, entity.Key2));
}

当然,实体模型需要是泛型类型。

我目前所拥有的

public Func<TEntity, object> BuildKeyFactory<TEntity>()
{
    var entityType = typeof(TEntity);

    // Get properties that have the [Key] attribute
    var keyProperties = entityType.GetProperties(BindingFlags.Instance | BindingFlags.Public)
        .Where(x => x.GetCustomAttribute(typeof(KeyAttribute)) != null)
        .ToArray();

    var tupleType = Type.GetType($"System.Tuple`{keyProperties.Length}");
    if (tupleType == null) throw new InvalidOperationException($"No tuple type found for {keyProperties.Length} generic arguments");

    var keyPropertyTypes = keyProperties.Select(x => x.PropertyType).ToArray();
    var tupleConstructor = tupleType.MakeGenericType(keyPropertyTypes).GetConstructor(keyPropertyTypes);
    if (tupleConstructor == null) throw new InvalidOperationException($"No tuple constructor found for key in {entityType.Name} entity");

    // The following part is where I need some help with...
    var newTupleExpression = Expression.New(tupleConstructor, keyProperties.Select(x => ????));

    return Expression.Lambda<Func<TEntity, object>>(????).Compile();
}

如您所见,我无法弄清楚我需要如何创建属性表达式以传递给 Expression.New() 调用(可能与 Expression.MakeMemberAccess(Expression.Property()) 相关,但不知道如何传递 TEntity来自 lambda 参数的实例)以及如何使用 Expression.Lambda 调用“链接”它。任何帮助将不胜感激!

【问题讨论】:

    标签: c# linq-expressions


    【解决方案1】:

    你很接近。

    // we need to build entity => new Tuple<..>(entity.Property1, entity.Property2...)
    // arg represents "entity" above
    var arg = Expression.Parameter(typeof(TEntity));
    // The following part is where I need some help with...
    // Expression.Property(arg, "name) represents "entity.Property1" above
    var newTupleExpression = Expression.New(tupleConstructor, keyProperties.Select(c => Expression.Property(arg, c)));
    return Expression.Lambda<Func<TEntity, object>>(newTupleExpression, arg).Compile();
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-05
      相关资源
      最近更新 更多