我还是代表们的新手,我一直在玩Steven John Metsker的“C#中的设计模式”一书中描述的基于代理的数据访问层(非常好的阅读!)。它定义了数据访问委托,如下所示:
public delegate object BorrowReader(IDataReader reader);
使用它的结果是看起来像其中之一的代码:
var result = Foo.Bar(new BorrowReader(DoFooBarMagic));
var result = Foo.Bar(DoFooBarMagic);
但是,由于委托的返回类型是“object”,因此需要强制转换以获取任何方法(本例中为“DoFooBarMagic”)才能返回。因此,如果“DoFooBarMagic”返回List,则需要执行以下操作:
var result = Foo.Bar(DoFooBarMagic) as List<string>;
我想要的是能够跳过强制转换,并从委托方法的返回类型推断出委托的返回类型。我的想法可能是有一种方法可以使用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);
如果从委托方法的返回类型推断出返回的类型,但看起来不起作用。相反,你必须这样做:
public delegate T BorrowReader<T>(IDataReader reader);
var result = Foo.Bar(new BorrowReader<List<string>>(DoFooBarMagic));
这几乎不比演员更好。
那么有没有办法从委托方法的返回类型推断委托的返回类型?
编辑添加: 如果需要,我可以更改Foo.Bar的签名。目前的签名基本上是这样的:
public static T Bar<T>(string sprocName,
DbParameter[] params,
BorrowReader<T> borrower);
注意:该签名是当前状态的结果,该状态使用此委托定义:
public delegate T BorrowReader<T>(IDataReader reader);
答案 0 :(得分:6)
怎么样:
public static T Bar2<T>(Func<IDataReader,T> func) where T : class
{
BorrowReader borrower = new BorrowReader(func);
return (T) Foo.Bar(borrower);
}
我知道它仍在进行演员表演,这很难看,但它应该有效。 (我原本以为你可以从func
隐式转换,但显然不是。至少在C#4.0之前没有。)
当然,如果您可以将Foo.Bar
的签名更改为通用,那么您就是在笑......
编辑:回答评论:如果方法的签名被更改为采用通用委托,例如
public static T Bar<T>(Func<IDataReader, T> func)
然后调用代码可以几乎只是:
var result = Foo.Bar(DoFooBarMagic);
不幸的是,类型推断不适用于方法组,所以你必须使用:
Func<IDataReader, List<string>> func = DoFooBarMagic;
var result = Foo.Bar(func);
或(更好,如果略微效率低下)
var result = Foo.Bar(reader => DoFooBarMagic(reader));
所以你是对的 - 这个答案并没有让OP完全符合要求,但可能它已接近足以获得认可。希望这个编辑有助于解释其余部分:)
答案 1 :(得分:0)
这很难看,但你可以使用out参数。从我的枚举解析器:
public static T Parse<T>(string value)
{
// return a value of type T
}
public static void Parse<T>(string value, out T eValue)
{
// do something and set the out parameter
}
// now can be called via either
SomeEnum blah = Enums.Parse<SomeEnum>("blah");
// OR
SomeEnum blah;
Enums.Parse("blah", out blah);
第二个会推断出类型,但就像我说的那样,它很难看。
答案 2 :(得分:0)
不使用泛型。类型推断是一个编译时事件。一种解决方案是在您发布时拥有一个通用委托。通用委托会比演员更快。
答案 3 :(得分:0)
我认为没有办法绕过它。至少不是你提出的方式。主要的问题是,由于它必须在编译时被驱动,如果你没有显式的返回类型,那么编译器实际上不能推断返回类型。
答案 4 :(得分:0)
// if BorrowReader is generic...
public delegate T BorrowReader<T>(IDataReader reader);
public class Foo
{
// ... and Foo.Bar() is also generic
public static T Bar<T>(BorrowReader<T> borrower) { ... }
public void SomeMethod()
{
// this does *not* work (compiler needs more help)
var result1 = Foo.Bar(DoFooBarMagic);
// but instead of this (which works)
var result2 = Foo.Bar(new BorrowReader<List<string>>(DoFooBarMagic));
// you can do this (also works)
// which emits the same IL, anyway
var result3 = Foo.Bar<List<string>>(DoFooBarMagic);
}
}
答案 5 :(得分:0)
我希望F#可以做到这一点。我不是专家,但F#确实使用了返回类型类型推断(details on MSDN)。