具有返回值类型推断的委托 (C#)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/853018/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Delegates with return value type inference (C#)
提问by Josh
I'm still new to delegates and I've been playing with the Delegate-based Data Access Layer described in Steven John Metsker's "Design Patterns in C#" book (an excellent read!). It defines the data access delegate like this:
我对委托还是个新手,我一直在使用 Steven John Metsker 的“C# 中的设计模式”一书中描述的基于委托的数据访问层(一本很好的读物!)。它定义了这样的数据访问委托:
public delegate object BorrowReader(IDataReader reader);
The result of using this is code that looks like one of these:
使用它的结果是如下代码之一:
var result = Foo.Bar(new BorrowReader(DoFooBarMagic));
var result = Foo.Bar(DoFooBarMagic);
However, since the delegate's return type is "object", you need to cast to get whatever the method ("DoFooBarMagic" in this example) really returns. So if "DoFooBarMagic" returns List, you'd need to do something like this:
但是,由于委托的返回类型是“对象”,因此您需要强制转换以获取方法(在本例中为“DoFooBarMagic”)真正返回的任何内容。因此,如果“DoFooBarMagic”返回列表,您需要执行以下操作:
var result = Foo.Bar(DoFooBarMagic) as List<string>;
What I'd like is to be able to skip the cast and have the return type of the delegate inferred from the return type of the delegate method. My thought was maybe there's a way to use a Type parameter to inference the return type. Something like one of these:
我想要的是能够跳过强制转换并从委托方法的返回类型推断出委托的返回类型。我的想法是也许有一种方法可以使用 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);
Where the type of the return is inferred from the return type of the delegate method, but that appears not to work. Instead you have to do this:
从委托方法的返回类型推断返回的类型,但这似乎不起作用。相反,您必须这样做:
public delegate T BorrowReader<T>(IDataReader reader);
var result = Foo.Bar(new BorrowReader<List<string>>(DoFooBarMagic));
Which hardly seems better than the cast.
这似乎比演员阵容更好。
So is there a way to infer the return type of the delegate from the return type of the delegate method?
那么有没有办法从委托方法的返回类型推断委托的返回类型呢?
Edit to Add:I can change the signature of Foo.Bar if need be. The current signature is essentially this:
编辑添加:如果需要,我可以更改 Foo.Bar 的签名。当前的签名基本上是这样的:
public static T Bar<T>(string sprocName,
DbParameter[] params,
BorrowReader<T> borrower);
Note: that signature is the result of the current state, which is using this delegate definition:
注意:该签名是当前状态的结果,它使用此委托定义:
public delegate T BorrowReader<T>(IDataReader reader);
采纳答案by Jon Skeet
How about:
怎么样:
public static T Bar2<T>(Func<IDataReader,T> func) where T : class
{
BorrowReader borrower = new BorrowReader(func);
return (T) Foo.Bar(borrower);
}
I know it's still doing the cast anyway, which is ugly, but it should work. (I originally thought you could get away with an implicit conversion from func
, but apparently not. At least not before C# 4.0.)
我知道它仍然在做演员,这很丑陋,但它应该有效。(我最初认为你可以从 隐式转换中逃脱func
,但显然不是。至少在 C# 4.0 之前不会。)
Of course, if you can change the signature of Foo.Bar
to be generic, you're laughing...
当然,如果你能把签名改成Foo.Bar
泛型,那你就笑了……
EDIT: To answer the comment: if the signature of the method is changed to take a generic delegate, e.g.
编辑:回答评论:如果方法的签名更改为采用通用委托,例如
public static T Bar<T>(Func<IDataReader, T> func)
then the calling code can nearlyjust be:
那么调用代码几乎可以是:
var result = Foo.Bar(DoFooBarMagic);
Unfortunately, type inference doesn't work with method groups so you have to use either:
不幸的是,类型推断不适用于方法组,因此您必须使用:
Func<IDataReader, List<string>> func = DoFooBarMagic;
var result = Foo.Bar(func);
or (nicer, if slightlyless efficient)
或(更好,如果效率稍低)
var result = Foo.Bar(reader => DoFooBarMagic(reader));
So you're right - this answer didn't quite get the OP to exactly what was required, but presumably it came close enough to get acceptance. Hopefully this edit is helpful to explain the rest :)
所以你是对的 - 这个答案并没有完全让 OP 完全符合要求,但大概它已经足够接近获得接受了。希望此编辑有助于解释其余部分:)
回答by Chris Doggett
It's ugly, but you can use an out parameter. From my enum parser:
这很丑陋,但您可以使用 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);
The second one will infer the type, but like I said, it's ugly.
第二个将推断类型,但就像我说的那样,它很难看。
回答by JohnOpincar
Not using generics. Type inference is a compile-time event. One solution would be to have a generic delegate as you posted. The generic delegate would be faster than a cast.
不使用泛型。类型推断是一个编译时事件。一种解决方案是在您发布时使用通用委托。通用委托将比强制转换更快。
回答by enriquein
I don't think there's a way around it. At least not in the way you propose it. The main problem being that since it has to be infered at compile time, if you don't have an explicit return type, then the compiler can't actually infer the return type.
我不认为有办法解决它。至少不是你提出的那样。主要问题是,由于必须在编译时推断它,如果您没有显式返回类型,那么编译器实际上无法推断返回类型。
回答by Lucas
// 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);
}
}
回答by Alex
I expect F# can do this. I'm no expert, but F# does use return type type inference (details on MSDN).
我希望 F# 可以做到这一点。我不是专家,但 F# 确实使用了返回类型类型推断(MSDN 上的详细信息)。