【问题标题】:Generic Method with generic return具有泛型返回的泛型方法
【发布时间】:2013-11-12 14:19:06
【问题描述】:

嗯,我有以下场景:

public class Joins<TOuter, TInner, TResult>
{
    public Expression<Func<TOuter, object>> outerKeySelector;
    public Expression<Func<TInner, object>> innerKeySelector;
    public Expression<Func<TOuter, TInner, object>> resultSelector;

    public IEnumerable<TResult> r;

}

public class Test<T>
{
    public IEnumerable<TResult> Join<TInner, TResult>(
        Expression<Func<T, object>> outerKeySelector,
        Expression<Func<TInner, object>> innerKeySelector,
        Expression<Func<T, TInner, TResult>> resultSelector) where TInner : class
    {
        var join = new Joins<T, TInner, TResult>();
        join.innerKeySelector = innerKeySelector;
        join.outerKeySelector = outerKeySelector;

        return join.r;
    }
}

要创建 join 方法,我依靠链接:http://msdn.microsoft.com/en-us/library/bb534644(v=vs.100).aspx

但是,当我尝试调用该方法时,TInner 无法识别,使该方法变得无效我返回以下错误:

无法将表达式类型“type”转换为返回类型“TResult”

注意:'Joins' 类纯粹是一个测试,没有一个是确定的,var 'r' 仅供测试,仅用于方便退货。

预期用途示例:

var test = new Test<User>().Join<Permission>(u => u.Id, p => p.IdUser, (u, p) => new { Id = u.Id , Area = p.Area });

更多细节:

如前所述,TInner 无法识别,因此我无法正确调用方法。

作为测试,我这样做了:

var test = new Test<User>().Join<Permission>(u => u.Id, p => p.ToString(), (u, p) => new {Id = u.Id, Name = p.ToString()});

我知道 p.ToString() 不正确,但无法识别所指示的类的属性(在 Permission 的情况下),然后放入 ToString()只是为了完成编写方法。

编辑:

我需要在 foreach/for 中使用结果

示例:

foreach(var obj in test)
{
    var id = obj.Id;
    var area = obj.Area;
    .
    .
    .
}

【问题讨论】:

  • 你能举个例子说明你是如何称呼它的吗?
  • 我更新了问题
  • Test&lt;T&gt;.Join 不需要两个类型参数吗?您还试图返回一个匿名类,如果没有编译器推断TInnerTResult 或使用dynamic AFAIK,它将无法工作。
  • 你能给我们举个例子说明它应该是怎样的方法吗?
  • 我不确定该方法是否存在问题。你可以在不指定 Join 类型参数的情况下调用它吗:var test = new Test&lt;User&gt;().Join(u =&gt; ...)

标签: c#-4.0 generics methods lambda generic-method


【解决方案1】:

要使其正常工作,您应该执行以下操作:

 var test = new Test<User>().Join<Permission, object>(u => u.Id, p => p.IdUser, (u, p) => new { Id = u.Id, Area = p.Area });
 //                                           ^^ (resolve the second type argument as well)     

当您定义以下内容时:

public TResult Join<TInner, TResult>

那么你应该要么明确地给编译器一个提示(而不是任何,作为类型参数提到:TInner,TResult),或者它必须以某种方式被自动识别编译器(然后你可以从显式定义中省略它),但在你的情况下你必须显式地这样做。


看看this answer。尽管这个问题也与扩展方法有关,但是对于需要解析的类型参数的逻辑有一个很好的解释。

编辑:

object 肯定不是最好的决定,因为您以后无法对该对象执行任何操作(尤其是在匿名类型的情况下)。

所以,你应该改变它,例如,通过以下方式:

    public class Test<T, TInner> where TInner : class where T : class 
    {
        public IEnumerable<TResult> Join<TResult>(

        ...

            Expression<Func<T, TInner, TResult>> resultSelector)

之后你可以按如下方式使用它:

var test = new Test<User, Permission>()
                .Join(u => u.Id, p => p.IdUser, (u, p) => new { Id = u.Id, Area = p.Area });

编辑:

如果您需要将 TInnerTResult 传递给 Join 方法,那是不可能的。匿名类只能由编译器自动解析 - 您不能显式指定它。

所以,你可以解决它的唯一方法,如下所示:

var test = new Test<User>().Join<Permission, dynamic>(...

这将允许您将结果与 LinQ .Where( 方法一起使用,但是,没有智能感知支持(除非您为 Join 输出创建一个具体类)。

【讨论】:

  • 好的。该方法“有效”,但是我的 TResult 仍然无法识别,例如在 foreach 中,我无法读取新对象的属性 =\
  • foreach 是什么意思(如果你在某处使用它,你应该提供一个例子)。另外,“识别 TResult”是什么意思?
  • 我更新了问题。实际上返回的是一个 IEnumerable 对象。 TResult 将是一个未知对象(当我假设它是对象类型时,它不识别对象的实际类型),在调用方法时通知(在 User 类和 Permission 类的情况下由联合表示,并选择两个字段 Id 和 Area,从而生成一个包含属性 Id 和 Area 的新对象)。但是当我尝试执行 foreach 时,无法识别这些属性。
  • 如果你做一些更新,你应该写“EDIT:/UPDATED:”然后添加你的新数据,因为对于已经阅读过你之前想法的人来说,这变得不清楚。
  • 当然,我的错。问题是我无法将 Test 类更改为拥有另一个通用对象,它必须在方法内工作。
猜你喜欢
  • 1970-01-01
  • 2016-12-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多