为什么Select()不将IEnumerable <dynamic>转换为IEnumerable <StrongType>?

Dou*_*son 5 c# linq dapper

我正在尝试使用Dapper简单地将我的数据库表映射到C#中的类型,但是,我的一些类型需要不在表中的其他元素.为此,我使用的工厂可以获取列值并设置适当的属性.

public IEnumerable<IMyType> All() {
  var query = _connection.Query("SELECT * FROM [table]");
  return query.Select(o => _myTypeFactory.Create(o));
}
Run Code Online (Sandbox Code Playgroud)

目前这导致return语句生成错误:

无法将表达式转换'System.Collections.Generic.IEnumerable<dynamic>'为返回类型'System.Collections.Generic.IEnumerable<IMyType>'

我的工厂类看起来像这样:

public class MyTypeFactory {
  public IMyType Create(dynamic o) {
    return Create((String) o.Code, (Int32) o.KeyID);
  }
  public IMyType Create(String code, Int32 keyID) {
    return new MyType(code, Cache.Lookup(keyID));
  }
}
Run Code Online (Sandbox Code Playgroud)

为什么Select()方法不返回IEnumerable<IMyType>?我需要做些什么来完成这项工作?这只是错误的做法,还有更好的方法吗?

Jon*_*eet 9

最简单的解决方法就是使用Cast<>LINQ运算符:

public IEnumerable<IMyType> All() {
  var query = _connection.Query("SELECT * FROM [table]");
  return query.Select(o => _myTypeFactory.Create(o))
              .Cast<IMyType>();
}
Run Code Online (Sandbox Code Playgroud)

或者,您可以投射每个元素:

public IEnumerable<IMyType> All() {
  var query = _connection.Query("SELECT * FROM [table]");
  return query.Select(o => (IMyType) _myTypeFactory.Create(o));
}
Run Code Online (Sandbox Code Playgroud)

它目前不起作用,因为在IEnumerable<dynamic>和之间根本没有可用的隐式转换IEnumerable<IMyType>.IEnumerable<dynamic>可以通过多种方式实现,并且假设每个项目将动态生成,则没有理由假设结果值将实现IEnumerable<IMyType>.

我同意它看起来第二种形式实际上并没有添加任何东西,但是编译器没有检查所有可能的返回类型_myTypeFactory.Create(o)- 它将整个表达式视为动态值,即表达式是类型dynamic.因此Select结果仍然是类型IEnumerable<dynamic>.

另一种选择是指定泛型类型参数Select.

public IEnumerable<IMyType> All() {
  var query = _connection.Query("SELECT * FROM [table]");
  return query.Select<IMyType>(o => _myTypeFactory.Create(o));
}
Run Code Online (Sandbox Code Playgroud)

那是试图强制lambda表达式Func<dynamic, IMyType>- 我相信这将有效......

编辑:如注释中所述,强制在编译时解析方法调用也将修复它.基本上它取决于你发现最可读的东西.