C# 从一个方法返回多个结果
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/8930333/
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
Returning multiple results from a method
提问by Chad Richardson
I trying to improve my skills using Try Catch blocks and better error handling.
我尝试使用 Try Catch 块和更好的错误处理来提高我的技能。
I have a class that performs a common task, in this case retrieving a Facebook AccessToken. If successful, I want to return the AccessToken string, if not I want to return an error message. These are both strings, so no problem. But when checking the return value on the calling side of the code, how can you do this effectively?
我有一个执行常见任务的类,在本例中是检索 Facebook AccessToken。如果成功,我想返回 AccessToken 字符串,否则我想返回一条错误消息。这两个都是字符串,所以没问题。但是在代码的调用端检查返回值时,如何有效地做到这一点?
It's like I need to return 2 values. In the case of a successful attempt, return = true, "ACESSCODEACXDJGKEIDJ", or if it fails, return = false, "Ooops, there was an error" + ex.ToString();
就像我需要返回 2 个值。在成功尝试的情况下,return = true, "ACESCODEACXDJGKEIDJ",或者如果失败,则 return = false, "Ooops, there was an error" + ex.ToString();
Then checking the return value is easy (in theory). I could think of returning simply a true/false for return and then setting a Session variable for the strings.
然后检查返回值很容易(理论上)。我可以考虑简单地返回一个真/假返回,然后为字符串设置一个会话变量。
What is a way to return multiple results from a method?
从一个方法返回多个结果的方法是什么?
采纳答案by musefan
Create a Result class and return that instead...
创建一个 Result 类并返回它......
public class Result
{
public bool Success {get;set;}
public string AccessToken {get;set;}
public string ErrorMessage {get;set;}
}
public Result GetFacebookToken()
{
Result result = new Result();
try{
result.AccessToken = "FACEBOOK TOKEN";
result.Success = true;
}
catch(Exception ex){
result.ErrorMessage = ex.Message;
result.Success = false;
}
return result;
}
Then you can call this code like...
然后你可以像这样调用这段代码......
Result result = GetFacebookToken();
if(result.Success)
{
//do something with result.AccessToken
}
else
{
//do something with result.ErrorMessage
}
回答by Abe Miessler
I wouldn't return the error message. Return a meaningful value or error out and let it bubble up. How you handle the error is up to you, but at a minimum I would gracefully handle it on the front end and log/notify someone on the backend.
我不会返回错误消息。返回一个有意义的值或错误并让它冒泡。您如何处理错误取决于您,但至少我会在前端优雅地处理它并在后端记录/通知某人。
If you insist on returning something even when your function errors out then I would return an object that has the following members:
如果您坚持在函数出错时返回某些内容,那么我将返回一个具有以下成员的对象:
Value - String
Success - Bool
Then you can check for success and handle the value accordingly.
然后您可以检查是否成功并相应地处理该值。
回答by Ilya Kogan
A pretty way to do this is return an object that includes both a Success/Failure status and a detailed error message.
一个很好的方法是返回一个包含成功/失败状态和详细错误消息的对象。
Something like:
就像是:
class Result
{
bool IsSuccessful { get; set; }
string DetailedStatus { get; set; }
}
回答by Darin Dimitrov
2 possibilities spring to mind
2 种可能性浮现在脑海
- Use the TryXXX pattern (used in some BCL methods such as DateTime.TryParse).
- Design a class that contains the status of the operation and the result and then have your method return this class.
- 使用 TryXXX 模式(在一些 BCL 方法中使用,例如DateTime.TryParse)。
- 设计一个包含操作状态和结果的类,然后让您的方法返回此类。
Let's first see the TryXXX pattern. It's basically a method that returns a boolean value and the result as outparameter.
我们先来看看 TryXXX 模式。它基本上是一种返回布尔值和结果作为out参数的方法。
public bool TryXXX(string someInput, out string someResult, out string errorMessage)
{
...
}
which will be consumed like this:
它将像这样被消耗:
string someResult;
string errorMessage;
if (!TryXXX("some parameter", out someResult, out errorMessage))
{
// an error occurred => use errorMessage to get more details
}
else
{
// everything went fine => use the results here
}
In the second approach you would simply design a class that will contain all the necessary information:
在第二种方法中,您只需设计一个包含所有必要信息的类:
public class MyResult
{
public bool Success { get; set; }
public string ErrorMessage { get; set; }
public string SomeResult { get; set; }
}
and then have your method return this class:
然后让你的方法返回这个类:
public MyResult MyMethod(string someParameter)
{
...
}
which will be consumed like this:
它将像这样被消耗:
MyResult result = MyMethod("someParameter");
if (!result.Success)
{
// an error occurred => use result.ErrorMessage to get more details
}
else
{
// everything went fine => use the result.SomeResult here
}
Of course the results can be any other complex object instead of (as shown in this example) a string.
当然,结果可以是任何其他复杂对象,而不是(如本例所示)字符串。
回答by Magrangs
Why don't you create a class with 3 properties. success (bool), message (string) and token (string). You can create an instance of that class, populate the values and return that.
为什么不创建一个具有 3 个属性的类。成功(布尔)、消息(字符串)和令牌(字符串)。您可以创建该类的实例,填充值并返回该值。
回答by joe_coolish
If you want to return 2 objects, you can do something like this:
如果要返回 2 个对象,可以执行以下操作:
private bool TestThing(out string errorMessage)
{
bool error = true;
if(error)
{
errorMessage = "This is a message!";
return false;
}
errorMessage = "";
return true;
}
then you get the bool and the error message
然后你会得到 bool 和错误消息
回答by Adam Robinson
You are definitely correct that using an outside storage location (a session variable, for example) is the wrongway.
您绝对正确,使用外部存储位置(例如会话变量)是错误的方式。
The correct approach depends on whether or not you consider an error to be an exceptionalcircumstance. If not, then follow the example set in the framework by prefixing your function with the word Tryand having its signature look like this:
正确的方法取决于您是否将错误视为特殊情况。如果没有,则按照框架中设置的示例,在您的函数前加上单词Try并使其签名如下所示:
public bool TryGetFacebookToken(<necessary parameters>, out string token)
{
... set the token within the body and return true if it succeeded or false if it did not
}
The important thing to note here is that this approach is generally used when you only care whether or not the operation worked (and you don't really care whyit didn't work if it failed) and have a reasonable expectation that it may not.
这里要注意的重要一点是,当您只关心操作是否有效(并且您并不真正关心为什么它失败时它不起作用)并且有合理的期望它可能不起作用时,通常会使用这种方法.
If a failure is exceptional(meaning that a properly configured program should notencounter this error), then you should use an exception. In fact, if your function cannot actually doanything with the exception you're getting, then there's no point in actually catching it. Proper exception handling means letting the exception "bubble up" to whatever layer in your program can actually do something meaningful and appropriate with the exception.
如果失败是异常的(意味着正确配置的程序不应遇到此错误),那么您应该使用异常。事实上,如果你的函数实际上不能对你得到的异常做任何事情,那么实际捕捉它就没有意义了。正确的异常处理意味着让异常“冒泡”到程序中的任何层实际上可以对异常做一些有意义和适当的事情。
This also simplifies your scenario, since you only need to return a string.
这也简化了您的场景,因为您只需要返回一个字符串。
回答by Mark Brackett
If successful, I want to return the AccessToken string, if not I want to return an error message. These are both strings, so no problem. But when checking the return value on the calling side of the code, how can you do this effectively?
如果成功,我想返回 AccessToken 字符串,否则我想返回一条错误消息。这两个都是字符串,所以没问题。但是在代码的调用端检查返回值时,如何有效地做到这一点?
C# doesn't really use error messages, we use exceptions. The correct way to do this is to just throw an exception, and let the caller ignore or catch it.
C# 并没有真正使用错误消息,我们使用异常。正确的做法是抛出一个异常,让调用者忽略或捕获它。
If it's not "exceptional" to fail (eg., if some users have tokens and some don't), then an alternative would be to return a null string to indicate the absence of a token (and still throw an exception for "exceptional" cases such as not being able to contact Facebook, etc.). I don't think that's the case for you, since your example failure included an Exception object.
如果失败不是“异常”(例如,如果某些用户有令牌而某些用户没有),那么另一种方法是返回空字符串以指示缺少令牌(并且仍然为“异常”抛出异常" 无法联系 Facebook 等情况)。我认为您的情况并非如此,因为您的示例失败包括一个 Exception 对象。
Bottom line, is that you generally leave exception handling (catch) to the top-most of the stack (usually, the UI) since that has the most context of the current operation. It's of no use to catch an exception, reformat to a string, and then return that instead - losing valuable exception info along the way. Just let the caller have the exception instead, and they can decide how to present that failure to the user (or to carry on without FB integration).
最重要的是,您通常将异常处理(捕获)留在堆栈的最顶部(通常是 UI),因为它具有当前操作的最多上下文。捕获异常,重新格式化为字符串,然后返回它是没有用的 - 在此过程中丢失了有价值的异常信息。只是让调用者有例外,他们可以决定如何向用户呈现该故障(或在没有 FB 集成的情况下继续)。
This is obviously mocked up, but hopefully gets my point across (code speaks louder than words):
这显然是模拟的,但希望能理解我的观点(代码胜于雄辩):
class Facebook {
...
public string GetAccessToken(string username, string password) {
// can throw WebException if can't connect to FB
this.Connect();
// returns null token if not a Facebook user
if (!this.IsUser(username)) return null;
// can throw ArgumentException if password is wrong
var fbInfo = this.GetInfo(username, password);
return fbInfo.AccessToken;
}
...
}
class Page {
void Page_Load(object sender, EventArgs e) {
var fb = new Facebook();
string accessToken;
try {
accessToken = fb.GetAccessToken(this.User.Name, this.txtPassword.Text);
} catch (WebException ex) {
Log(ex);
this.divError.Text = "Sorry, Facebook is down";
// continue processing without Facebook
} catch (ArgumentException ex) {
// Don't log - we don't care
this.divError.Text = "Your password is invalid";
// stop processing, let the user correct password
return;
} catch (Exception ex) {
Log(ex);
// Unknown error. Stop processing and show friendly message
throw;
}
if (!string.IsNullOrEmpty(accessToken)) {
// enable Facebook integration
this.FillFacebookWallPosts(accessToken);
} else {
// disable Facebook integration
this.HideFacebook();
}
}
}
回答by epylar
Try a tuple?
试试元组?
public Tuple<bool, string> ReturnsBoolAndString() {
return Tuple.Create(false, "string");
}
回答by user1454265
To build on musefan's answer, I like the same pattern but with a generic Result type so I can use it throughout the whole codebase:
为了建立在 musefan 的答案之上,我喜欢相同的模式,但具有通用的 Result 类型,因此我可以在整个代码库中使用它:
public class Result
{
public bool Success { get; set; }
public string ErrorMessage { get; set; }
}
public class Result<T> : Result
{
public T Data;
}
One reason I like this vs. throwing an exception out of a function that otherwise returns data, is that this helps you map that function over a collection, capturing exception details in error messages, so you don't have to worry about an exception on one item blowing up the whole chain. This is good for situations like parsing lines out of a flat data file, where successful lines should move forward but any errors should be dealt with individually:
我喜欢这个而不是从返回数据的函数中抛出异常的一个原因是,这有助于您将该函数映射到集合上,捕获错误消息中的异常详细信息,因此您不必担心异常一个项目炸毁了整个链条。这对于解析平面数据文件中的行这样的情况很有用,在这种情况下,成功的行应该向前移动,但任何错误都应该单独处理:
public static Result<Thing> ParseThing(string line)
{
try
{
// Parse a Thing (or return a parsing error.)
return new Result<Thing> { Data = thing, Success = true };
}
catch (Exception ex)
{
return new Result<Thing> { Data = null, Success = false, ErrorMessage = "..." };
}
}
...
var results = lines.Select(ParseThing);
foreach (var result in results)
{
// Check result.Success and deal with successes/failures here.
}
Of course, you still have the option of throwing an exception out of that function for truly exceptional situations when blowing up the whole chain of processing is what you want.
当然,当您想要炸毁整个处理链时,您仍然可以选择在真正的异常情况下从该函数中抛出异常。
P.S. Every day is the day I wish C# had multiple return values.
PS 每一天都是我希望 C# 有多个返回值的一天。

