泛型类型中的确切类型约束 - C#

时间:2016-07-09 11:35:00

标签: c# .net generics lambda mapping

我想实现一个泛型类型映射器,我正在努力解决与泛型类型约束相关的问题。

我有以下定义的实体映射器类:

public class EntityMapper<TDto, TEntity>
{
    public void RegisterMapping<TDtoProperty, TEntityProperty>(
        Expression<Func<TDto, TDtoProperty>> expressionFrom,
        Expression<Func<TEntity, TEntityProperty>> expressionTo,
        Func<TDtoProperty, TEntityProperty> mapper)
    {
        // mapping
    }
}

我还有2个类要映射的属性:

public class Foo
{
    public long FooLongProp { get; set; }

    public decimal? FooDecimalNullProp { get; set; }

    public string FooStringProp { get; set; }
}

public class Bar
{
    public long? BarLongNullProp { get; set; }

    public decimal BarDecimalProp { get; set; }
}

映射正在执行如下:

public void Map()
{
    var mapper = new EntityMapper<Foo, Bar>();

    mapper.RegisterMapping(x => x.FooLongProp, x => x.BarLongNullProp, x => x); // FooLongProp -> long, BarLongNullProp -> long?
    mapper.RegisterMapping(x => x.FooDecimalNullProp, x => x.BarLongNullProp, x => x); // FooDecimalNullProp -> decimal?, BarLongNullProp -> long?
    mapper.RegisterMapping(x => x.FooDecimalNullProp, x => x.BarDecimalProp, x => x); // FooDecimalNullProp -> decimal?, BarDecimalProp -> decimal

    mapper.RegisterMapping(x => x.FooStringProp, x => x.BarLongNullProp, x => x); // FooStringProp -> string, BarLongNullProp -> long?
}

我希望RegisterMapping中的第三个参数返回与TEntityProperty完全相同的类型。 遗憾的是,编译器不会将下面long -> long?之间的映射代码报告为错误。它甚至不会报告错误映射decimal? -> decimal(它将在运行时中断)。

编译器报告错误的唯一地方是我想要投射string -> decimal?的行。

所以我有以下问题:

  1. 为什么前3个映射不能像我预期的那样工作?它似乎 该编译器无法正确解析其类型。
  2. 有没有办法在通用约束中指定完全相同的类型约束?
  3. 有没有其他可能实现我想做的事情并在编译过程中遇到错误?
  4. 欢迎任何其他建议,评论。

1 个答案:

答案 0 :(得分:0)

mapper.RegisterMapping(x => x.FooLongProp, x => x.BarLongNullProp, x => x); // FooLongProp -> long, BarLongNullProp -> long?
  1. x => x.FooLongProp编译器推断(Expression<Func<Foo, long>>
  2. x => x.BarLongNullProp编译器推断(Expression<Func<Bar, long?>>
  3. x => x编译器推断(Func<long, long?>>
  4. mapper.RegisterMapping(x => x.FooDecimalNullProp, x => x.BarLongNullProp, x => x); // FooDecimalNullProp -> decimal?, BarLongNullProp -> long?
    
    1. x => x.FooDecimalNullProp编译器推断(Expression<Func<Foo, decimal?>>

    2. x => x编译器推断(Func<decimal?, decimal?>>)!!为什么??因为x=>xFunc<type of x,type of x>

    3. x => x.BarLongNullProp编译器推断(Expression<Func<Bar, decimal?>>)!!为什么?因为第2行它向long?转发decimal?所以它可以匹配通用参数。

    4. 在其他情况下会发生类似的事情。在最后一种情况下,编译器会查找Func<string, long?>。当您提供x=>xFunc<string,string>)时,编译器无法推断出您的泛型类型的正确类型,因此它会失败。将鼠标光标悬停在方法调用上将显示编译器推断的泛型参数。也许你应该为你的lambdas指定一个明确的输入。

      mapper.RegisterMapping(x => x.FooLongProp, x => x.BarLongNullProp, x => x); 
      mapper.RegisterMapping(x => x.FooDecimalNullProp, x => x.BarLongNullProp, x => (long?)x);
      mapper.RegisterMapping(x => x.FooDecimalNullProp, x => x.BarDecimalProp, x => (decimal)x); 
      
      mapper.RegisterMapping(x => x.FooStringProp, x => x.BarLongNullProp, x => (long?)(object)x ); //or any lambda which returns long?