我正在尝试从c#中的函数/方法中找到最简单的返回值或错误消息的解决方案。
现在我试过了:
public float ValidateValue (float value)
{
if (value == VALID_VALUE)
{
return value;
}
else
{
throw new ArgumentException("Invalid value", "value");
}
}
这个解决方案似乎已经足够好了,但我在Clean Code Cheap Sheet找到了:
使用控制流的例外 - 不要这样做
使用控制流的例外: 表现不好,难以理解,结果很难 处理真实例外情况。
答案 0 :(得分:4)
如果您想要验证某些输入值,我希望会返回bool
,表示“有效”'或者'无效',或者没有返回值,当值无效时抛出异常。
所以我建议使用它:
public bool ValidateValue(float value)
{
return value == VALID_VALUE;
}
或者这个:
public void ValidateValue(float value)
{
if (value != VALID_VALUE)
{
throw new ArgumentException("Invalid value", "value");
}
}
因此抛出异常不是问题,特别是当有多种理由拒绝时,您想区分各种原因。否则,只需使用bool
,例如int.TryParse
。
答案 1 :(得分:3)
如果输入无效,您会怎么做?
如果您正在从用户输入的UI级别编写代码,那么执行以下操作最有意义:
private bool IsValid(float value)
{
return value == VALID_VALUE; // replace with real check.
}
然后在调用代码中你会得到:
public void ReactToInput()
{
float value = HoweverYouGetTheFloatFromTheUser();
if(!IsValid)
{
//Code to display error message.
}
else
{
//Code to do something useful.
//
//Code to display result.
}
}
因为你在这个级别的工作是"采取用户给我的东西,尽可能地回报他们想要的东西"在这个层面上,最好有可能让用户做一些不正确的前端和中心。
如果您正在编写其他代码的代码以供使用,那么最合适的做法是:
private void CheckValid(float valid)
{
if(value != VALID_VALUE) // replace with real check.
throw new ArgumentException();
}
然后在调用代码中你会得到:
public float DoWork(float value)
{
CheckValid(value)
//Code to do something useful.
//
//Code to return result.
}
在这里,你的工作是干净地完成方法的任务并返回一个有意义的结果(如果没有,则为void
)。如果你不能做这项工作,因为你给出的输入是无稽之谈(或任何其他原因),那么你需要尽快停止并处理这个问题。你可以通过每次返回一个错误/成功代码并且每次调用代码来检查它来做到这一点,但是虽然这种方法确实有一些优点,但是例外让我们:
例如1,比较:
private bool WithExceptions()
{
return A() > B() && C() > D();
}
private bool WithExplicitChecks(out bool result)
{
result = false;
int a;
int b;
if(!A(out a))
return false;
if(!B(out b))
return false;
if(a <= b)
return true;
int c;
int d;
if(!C(out c))
return false;
if(!D(out d))
return false;
result = c > d;
return true;
}
对于2的示例,请考虑:
private void A()
{
if(_someField == null)
throw new InvalidOperationException("field not ready");
_someField.DoSomething();
}
private void B()
{
A();
}
private void C()
{
B();
}
private string D()
{
try
{
C();
}
catch(InvalidOperationException)
{
Console.Error.WriteLine("Was not ready");
}
}
显然,一个真实的案例会B()
和C()
执行更多操作,但我们可以在此处看到只有A()
必须担心提出异常而且只有D()
关于交易与他们一起,B()
和C()
都可以专注于主要问题。*
这两种方法可以混合使用。考虑:
private static string CheckValid(string path)
{
if(path.Length == 0)
return "You cannot enter an empty file path";
switch(path[path.Length - 1])
{
case '\\':
case '/':
return "You cannot enter a directory path";
}
return null;
}
public static void Main(string[] args)
{
Console.WriteLine("Enter a file path");
var path = Console.ReadLine().Trim();
var validationError = CheckValid(path);
if(validationError != null)
Console.Error.WriteLine(validationError);
else
{
try
{
using(var reader = new StreamReader(path))
Console.WriteLine(reader.ReadToEnd());
}
catch(FileNotFoundException)
{
Console.Error.WriteLine("File not found");
}
catch(UnauthorizedAccessException)
{
Console.Error.WriteLine("Access denied");
}
catch(IOException ioe)
{
Console.Error.WriteLine(string.Format("I/O Exception: {0}", ioe.Message));
}
}
Console.Read();
}
这个简单的程序从用户获取文件路径,并打开相关文件并以文本形式输出内容。它采用两种错误处理方法。
因为我们可以轻松检查空的无效输入,或以/
或\
结尾的无效输入,这是通过简单的控制流来完成的,我们会提供错误消息而不是做某事。
我们只能通过尝试打开文件并失败来了解其他问题,因此在这些情况下我们会处理异常。我将两种类型问题的显式检查结合起来,并将其与一类问题结合起来,并采取相应的行动。
这里有第三种异常处理方式;如果发生了我根本不期望的异常,程序将失败并转发异常消息以进行调试。在任何你不能捕获所有异常的情况下都是如此,但这是非常有用的;因为我没有毯子catch
或catch(Exception)
我不会混淆我期望处理的异常(让我处理它们!),例外情况是因为我没有意识到他们可能会发生错误(嘘我!现在我必须解决它)。
这是一个简单的程序,它从用户获取文件路径,并输出文件的内容。请注意,它结合了两种方法:
*尽管如此,如果异常通过它,可能会始终认为某个方法中的某些内容可能无法完成。
答案 2 :(得分:1)
元组可能对于解决该问题很有帮助:
public Tuple<float,string> ValidateValue (float value)
if (value == VALID_VALUE)
{
return new Tuple<bool, string>(value,string.Empty);
}
else
{
return new Tuple<bool, string>(false,"Invalid value");
}
调用函数时,请先检查错误字符串是否为空:
var validation = ValidateValue(myFloatValue);
if (validation.Item2 != string.Empty)
{
// report error
}
else
{
// No error core here validation.Item1 is your result
}
答案 3 :(得分:0)
一个想法可能是拥有一些通用模型。你可能有一些模型大致如下:
public class MyReturnModel
{
public bool Success { get; set; }
public string ErrorOrSuccessMessage { get; set; }
public dynamic AnyModelToReturn { get; set; }
}
现在让我们将此应用于您提供的案例:
public MyReturnModel ValidateValue(float value)
{
//function logic here
bool result = value == VALID_VALUE;
string msg = result ? "valud is valid" : "value is invalid";
return new MyReturnModel { Success = result, ErrorOrSuccessMessage = msg }
}