【问题标题】:Using Dynamic Column Names in a Linq Query在 Linq 查询中使用动态列名
【发布时间】:2012-11-11 06:46:07
【问题描述】:
foreach (Dimension dimensions in Enum.GetValues(typeof(Dimension)))
{
    var r = new ReferenceTable(dimensions).referenceItems;
    List<TVRawDataRecord> qry = TVRawDataList.Where(p => !r.Any(d => d.Value == p.BrandVariant))
                                             .ToList();                
    DimensionItem di = new DimensionItem(qry, dimensions);
    newDimensions.Add(di); 
 }

我正在尝试创建一个 Linq 查询,将 TVRawDataRecords 列表与 Dimensions 枚举中的列表进行比较,如果没有匹配项,则将它们添加到新的 DimensionIem 列表中。这一切都很好,但我需要在我的Where 语句中用维度枚举值动态替换p.BrandVariant,因为维度值与TVRawDataRecord 属性名称相同。这意味着我可以只用这几行代码循环 8 个维度等。

谁能解释我如何在 Where 语句中包含维度?谢谢!

【问题讨论】:

  • 为什么不用代码中的维度值替换属性?当你这样做时会发生什么?什么不工作?
  • 维度值是我所关注的字段的名称,所以我实际上是在尝试在每个循环中将 p.BrandVariant 替换为 'p + dimension'。
  • 只是编译。你检查过自己吗?您的意思是 p.DimensionDimension 枚举一致?那根本不是问题?你试过了吗?
  • 我的问题是在每个 foreach 循环上用等效的 'p.BrandVariant 动态替换 p.BrandVariant。 + dimension' 所以第一遍将是 p.BrandVariant,然后是 p.Creative 等等 - 每个枚举都有一个。所以我认为问题是如何动态更新 Where 语句。
  • 那么 p.Property 和 Dimension 枚举之间的联系是什么?哪个枚举值映射到 p 的哪个属性?还是它们只是一个接一个,等等?

标签: c# linq dynamic


【解决方案1】:

首先,这确实是一件很奇怪的事情。您应该首先考虑替代设计。现在有一对夫妇来找我。

无论如何,您都可以使用反射来实现您想要实现的目标。,差不多......

foreach (Dimension dimension in Enum.GetValues(typeof(Dimension)))
{
    var r = new ReferenceTable(dimension).referenceItems;
    var qry = TVRawDataList.Where(p => !r.Any(d => IsAMatch(p, dimension, d.Value)))
                           .ToList();     

    DimensionItem di = new DimensionItem(qry, dimension);
    newDimensions.Add(di); 
}

bool IsAMatch<T>(TVRawDataRecord obj, Dimension dimension, T valueToMatch)
{
    return valueToMatch == dimension.MapToTvRecordProperty<T>(obj);
}

T MapToTvRecordProperty<T>(this Dimension dimension, TVRawDataRecord obj)
{
    return obj.GetPropertyValue<T>(dimension.ToString());
}

T GetPropertyValue<T>(this TVRawDataRecord obj, string propertyName)
{
     var property = typeof(TVRawDataRecord).GetProperty(propertyName);
     if (property == null)
         return null; //or throw whatever

     return (T)property.GetValue(obj, null);
}

严格未经测试,未经编译。但这应该可以让您了解它是如何完成的。您可以使GetPropertyValue 函数更通用,但这是另一回事。传递Map 函数中的T 类型参数(将维度枚举映射到TVRawDataRecord 类的属性),因为您需要知道属性的返回类型。

我想说一个更好的替代设计就是创建一个简单的函数,使用 if else 逻辑返回正确的类型。所以把Map函数改成这样:

T MapToTvRecordProperty<T>(this Dimension dimension, TVRawDataRecord obj)
{
    switch (dimension)
    {
        case Dimension.BrandVariant:
            return obj.BrandVariant;
        case Dimension.Creative:
            return obj.Creative;

        .....

        default:
            throw;
    }
}

优点是即使您将来更改任何变量的名称,您的代码也不会中断(与反射方法不同)。但这里的问题是选择返回类型T。第二个示例无法编译,因为返回类型与返回的内容不匹配。如果所有属性都属于同一类型,那么您可以选择该类型。如果它真的很可变,那么您必须先将您的属性转换为对象,然后再转换为T,但仍然比反射更好!

更好的方法是指定属性to propertyto enum

如果BrandVariantCreative 等是它们自己的类,你可以让它们都实现一个接口,该接口将在它们上具有只读属性Dimension可以访问您的电视记录属性的该属性以获得正确的尺寸值!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-02
    • 1970-01-01
    • 1970-01-01
    • 2011-03-28
    • 1970-01-01
    相关资源
    最近更新 更多