【问题标题】:How to change return type in Lambda Expression如何在 Lambda 表达式中更改返回类型
【发布时间】:2018-02-27 04:01:35
【问题描述】:

我想通过嵌套接口类型从序列(IEnumerable和IQueryable)中查询数据,例如,

public interface IData
{
    TypeInEnum? Value1 { get; set; }
    string Value2 { get; set; }
}

public class DataModel : IData
{
    public int? Value1 { get; set; }
    public string Value2 { get; set; }

    TypeInEnum? IData.Value1
    {
        get
        {
            return Value1.HasValue ? (TypeInEnum?)Value1.Value : null;
        }
        set
        {
            //ignore enum validation here
            this.Value1 = value.HasValue ? (int?)value.Value : null;
        }
    }
}

public enum TypeInEnum
{
    A = 1,
    B,
    C
}

查询:

//source is IEnumerable<DataModel>
var query = source.Where(item => item.Value1 == 1); //item is DataModel
var query1 = source.Where1(item => item.Value1 == TypeInEnum.A); //item is IData
Assert.IsTrue(query.SequenceEqual(query1));

但这仅适用于类和接口中的属性类型相同的情况。比如,

使用Where时,报错:

System.InvalidOperationException: Rewriting child expression from type 'System.Nullable&lt;TypeInEnum&gt;' to type 'System.Nullable&lt;System.Int32&gt;' is not allowed, because it would change the meaning of the operation. If this is intentional, override 'VisitUnary' and change it to allow this rewrite.

使用Select,错误是:

System.ArgumentException: Expression of type 'System.Nullable&lt;System.Int32&gt;' cannot be used for return type 'System.Nullable&lt;TypeInEnum&gt;'

我不知道在哪里添加Convert

所有示例代码here

我在这上面浪费了一个月的时间......

已编辑

在我当前使用EntityFramework的项目中,每个表的数据库中都有一些基本列,但我发现一些基本列名称不同,例如CreatedDateTimeDateTimeCreated。将包含不同名称的基本列的表放入一个Entity Data Model 时会出现问题。在数据库和项目中更改这些列名会很困难并且会导致一些新问题,svn 分支很多,并且在许多模块中使用了一些表。所以我创建了一个包含所有这些基本列的接口,并将枚举字段从数字类型(在数据库中)更改为枚举类型(在项目中),并让 EF 生成的类实现这个接口,如果列名和类型不一样,实现接口中显式属性,因此可以忽略对原始项目的影响。

这确实解决了问题,但是通过EF使用接口比较困难,比如基于接口查询数据和修改值然后保存到数据库,创建一些基于接口的通用查询扩展。如果可以的话,可以减少很多代码,项目会更容易维护。

在实体模型和接口中查询相同类型的数据库数据,即使字段名称不同。

【问题讨论】:

  • 这样做的目的是什么?我的意思是,对于Where,例如你可以做source.Where&lt;IData&gt;(item =&gt; item.Value1 == TypeInEnum.A);,为什么要使用表达式和自定义访问者?
  • @Evk 我想通过EntityFramework从数据库中查询数据,如果属性名和表中的列名不同,会报错。所以我使用访问者将提交的名称“替换”为真实名称。

标签: c#


【解决方案1】:

您可以使用OfType 仅筛选出可分配给类型的那些。

例子:

var query = source.OfType<DataModel>().Where(item => item.Value1 == 1);
var query1 = source.OfType<IData>().Where(item => item.Value1 == TypeInEnum.A);

【讨论】:

    【解决方案2】:

    您能否尝试在Where 谓词中将该项目强制转换为IData

    var query = source.Where(item => item.Value1 == 1); //item is DataModel
    var query1 = source.Where(item => ((IData)item).Value1 == TypeInEnum.A); //item is IData
    Assert.IsTrue(query.SequenceEqual(query1));
    

    上面的代码适用于我的投射。

    【讨论】:

      【解决方案3】:

      技术解释和解决方法是,您无法在不强制转换的情况下比较 Nullable int 和 Nullable 枚举(这不像 comparing an int and an enum!)。

      在这篇文章的末尾,您将找到一个如何解决该问题的示例。

      然而,更有趣的问题是为什么你有一个

      DataModelpublic int? Value1 成员
      实现
      接口IData 声明了TypeInEnum? Value1 成员?

      我认为如果DataModel 实现IData 它也应该有Value1 类型TypeInEnum? 即:

      public class DataModel : IData
      {
          public TypeInEnum? Value1 { get; set; }
          ...
      }
      

      您可以找到重构代码的示例here

      至于技术解决方案:

      通过强制转换来查看您的代码:
      https://dotnetfiddle.net/8MqXnr

      var query = source.Where(item => item.Value1.HasValue).Where(item => (int)(item.Value1.Value) == 1); //item is DataModel
      var query1 = source.Where(item => item.Value1.HasValue).Where(item => item.Value1.Value ==  (int)TypeInEnum.A); //item is IData
      
      var eq = query.SequenceEqual(query1);   
      Console.WriteLine(String.Format("results: {0}",eq? "Equal": "Not equal")); 
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-08-06
        • 1970-01-01
        • 2018-10-09
        • 2021-11-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多