具有返回值类型推断(C#)的代理

Jos*_*osh 4 .net c# delegates type-inference

我还是代表们的新手,我一直在玩Steven John Metsker的"C#中的设计模式"一书中描述的基于代理的数据访问层(非常好的阅读!).它定义了数据访问委托,如下所示:

public delegate object BorrowReader(IDataReader reader);
Run Code Online (Sandbox Code Playgroud)

使用它的结果是看起来像这样的代码:

var result = Foo.Bar(new BorrowReader(DoFooBarMagic));
var result = Foo.Bar(DoFooBarMagic);
Run Code Online (Sandbox Code Playgroud)

但是,由于委托的返回类型是"对象",因此需要强制转换以获取任何方法(本例中为"DoFooBarMagic")确实返回.因此,如果"DoFooBarMagic"返回List,则需要执行以下操作:

var result = Foo.Bar(DoFooBarMagic) as List<string>;
Run Code Online (Sandbox Code Playgroud)

我想要的是能够跳过强制转换,并从委托方法的返回类型推断出委托的返回类型.我的想法可能是有一种方法可以使用Type参数来推断返回类型.像这样的东西之一:

public delegate T BorrowReader<T>(IDataReader reader);
List<string> result = Foo.Bar(new BorrowReader(DoFooBarMagic)); 
//Look, Ma, no cast!
var result2 = Foo.Bar(DoFooBarMagic);
Run Code Online (Sandbox Code Playgroud)

返回的类型是从委托方法的返回类型推断出来的,但似乎不起作用.相反,你必须这样做:

public delegate T BorrowReader<T>(IDataReader reader);
var result = Foo.Bar(new BorrowReader<List<string>>(DoFooBarMagic));
Run Code Online (Sandbox Code Playgroud)

这几乎不比演员更好.

那么有没有办法从委托方法的返回类型推断委托的返回类型?

编辑添加: 如果需要,我可以更改Foo.Bar的签名.目前的签名基本上是这样的:

public static T Bar<T>(string sprocName,
                       DbParameter[] params, 
                       BorrowReader<T> borrower);
Run Code Online (Sandbox Code Playgroud)

注意:该签名是当前状态的结果,该状态使用此委托定义:

public delegate T BorrowReader<T>(IDataReader reader);
Run Code Online (Sandbox Code Playgroud)

Jon*_*eet 6

怎么样:

public static T Bar2<T>(Func<IDataReader,T> func) where T : class
{
    BorrowReader borrower = new BorrowReader(func);
    return (T) Foo.Bar(borrower);
}
Run Code Online (Sandbox Code Playgroud)

我知道它仍然在做演员,这很难看,但它应该有效.(我原本以为你可以通过隐式转换逃脱func,但显然不是.至少在C#4.0之前没有.)

当然,如果你可以改变签名Foo.Bar是通用的,你就笑了......

编辑:回答评论:如果方法的签名被更改为采用通用委托,例如

public static T Bar<T>(Func<IDataReader, T> func)
Run Code Online (Sandbox Code Playgroud)

然后调用代码几乎可以是:

var result = Foo.Bar(DoFooBarMagic);
Run Code Online (Sandbox Code Playgroud)

遗憾的是,类型推断不适用于方法组,因此您必须使用以下任一方法:

Func<IDataReader, List<string>> func = DoFooBarMagic;
var result = Foo.Bar(func);
Run Code Online (Sandbox Code Playgroud)

或者(更好,如果效率稍低)

var result = Foo.Bar(reader => DoFooBarMagic(reader));
Run Code Online (Sandbox Code Playgroud)

所以你是对的 - 这个答案并没有完全得到所需要的OP,但可能它已接近足以获得认可.希望这个编辑有助于解释其余:)