C# 有更好的编写方式吗?

8
int uploadsID;
int pageNumber;
int x;
int y;
int w;
int h;

bool isValidUploadID = int.TryParse(context.Request.QueryString["uploadID"], out uploadsID);
bool isValidPage = int.TryParse(context.Request.QueryString["page"], out pageNumber);
bool isValidX = int.TryParse(context.Request.QueryString["x"], out x);
bool isValidY = int.TryParse(context.Request.QueryString["y"], out y);
bool isValidW = int.TryParse(context.Request.QueryString["w"], out w);
bool isValidH = int.TryParse(context.Request.QueryString["h"], out h);

if (isValidUploadID && isValidPage && isValidX && isValidY & isValidW & isValidH)
{

这是一个ajax处理程序,检查所有传递的参数是否正确。这样做是否被认为不好,是否有更好的编写方式,或者它并不重要?


1
您可以使用一个包含所有属性和一个构造函数的对象,该构造函数需要一个NameValueCollection(Request.QueryString或仅Request),并准备好该对象,此对象公开一个方法:“IsValid”,并检查当前请求的所有参数是否都正确。 - Roberto Conte Rosito
1
你可能想考虑在codereview上发布这个。 - Benjol
6个回答

7

假设您不会在其他地方使用单独的bool变量,那么您可以将其写为:

int uploadsID, pageNumber, x, y, w, h;
if (int.TryParse(context.Request.QueryString["uploadID"], out uploadsID) &&
    int.TryParse(context.Request.QueryString["page"], out pageNumber) &&
    int.TryParse(context.Request.QueryString["x"], out x) &&
    int.TryParse(context.Request.QueryString["y"], out y) &&
    int.TryParse(context.Request.QueryString["w"], out w) &&
    int.TryParse(context.Request.QueryString["h"], out h))
{
}

您可能希望将int.TryParse(context.Request.QueryString[name], out variable提取到单独的方法中,使您得到以下代码:

int uploadsID, pageNumber, x, y, w, h;
if (TryParseContextInt32("uploadID", out uploadsID) &&
    TryParseContextInt32("page", out pageNumber) &&
    TryParseContextInt32("x", out x) &&
    TryParseContextInt32("y", out y) &&
    TryParseContextInt32("w", out w) &&
    TryParseContextInt32("h", out h))
{
}

或者,您可以将所有这些上下文数据封装到一个新类型中,并使用TryParse方法,这样您就会得到类似于:

PageDetails details;
if (PageDetails.TryParse(context.Request.QueryString))
{
    // Now access details.Page, details.UploadID etc
}

显然这需要更多的工作,但我认为它会使代码更清晰。


6

是的,首先将您的int.TryParse(etc.)提取到一个单独的函数中。

(可能受F#影响过度)

//return a tuple (valid, value) from querystring of context, indexed with key
private Tuple<bool, int> TryGet(HttpContext context, string key)
{
    int val = 0;
    bool ok = int.TryParse(context.request.QueryString[key], out val);
    return Tuple.New(ok, val);
}

然后:

var UploadId = TryGet(context, "uploadID");
//...
if(UploadId.Item1 && etc..) 
{
    //do something with UploadId.Item2;

为了让事情更加清晰,你可以:
private class ValidValue
{
    public bool Valid { get; private set; }
    public int Value { get; private set; }
    public ValidValue(bool valid, int value)
    { 
        Valid = valid;
        Value = value;
    }
    //etc., but this seems a bit too much like hard work, and you don't get 
    // equality for free as you would with Tuple, (if you need it)

更像是一个独立的类,用于验证自己的属性。 - Turrau

3
我会选择这种格式进行排版

int uploadsID, pageNumber, x, y, h;

if (Int32.TryParse(context.Request.QueryString["uploadID"], out uploadsID)
    && Int32.TryParse(context.Request.QueryString["page"], out pageNumber)
    && Int32.TryParse(context.Request.QueryString["x"], out x)
    && Int32.TryParse(context.Request.QueryString["y"], out y)
    && Int32.TryParse(context.Request.QueryString["w"], out w)
    && Int32.TryParse(context.Request.QueryString["h"], out h))
{
    ...
}


但我认为你的方法没有任何问题。

2

你可以做的一件事是替换这个:

int uploadsID;
int pageNumber;
int x;
int y;
int w;
int h;

使用此功能

int uploadsID, pageNumber, x, y, w, h;

可以点踩,但是请给出一个理由。你显然认为第一段代码比我修改后的代码更易读? - Øyvind Bråthen

1
try
{
    // use Parse instead of TryParse

    // all are valid, proceed
}
catch
{
    // at least one is not valid
}

通常将异常作为正常程序流程的一部分是一个不好的想法,在这种情况下,用户输入错误显然是程序流程的正常部分,不应该通过异常来处理。用户输入错误并不是非常特殊的情况。 - Øyvind Bråthen
这很糟糕。你不仅在使用异常来控制流程,而且还会影响性能。 - Stilgar
如果catch语句返回错误代码或重新抛出异常,我认为这是一个不错的解决方案。@Stilgar:你真的关心错误情况下的性能吗? - adrianm
取决于错误情况下你要做什么以及你生成了多少个错误。如果页面可以在没有参数的情况下提供服务,并且这是最常见(默认)的情况,那该怎么办? - Stilgar
@Stilgar:你确定这会影响性能吗?我记得有一篇博客文章比较了Guid.TryParse和try{Guid.Parse},结果它们的性能相同... - Turrau

0
你可以编写一个帮助程序来消除 TryParse 中丑陋的 out 传递样式,例如:
public delegate bool TryParser<T>(string text, out T result) where T : struct;

public static T? TryParse<T>(string text, TryParser<T> tryParser)
                             where T : struct
{
    // null checks here.
    T result;
    return tryParser(text, out result) ? result : new T?();
}

然后(假设您只对有效性感兴趣):

bool isValid = new [] { "uploadID" , "page", "x", "y", "w", "h" }
              .Select(q => context.Request.QueryString[q])
              .All(t => TryParse<int>(t, int.TryParse).HasValue);

如果您需要单独的值:
var numsByKey = new [] { "uploadID" , "page", "x", "y", "w", "h" }
               .ToDictionary(q => q,
                             q => TryParse<int>(context.Request.QueryString[q], 
                                                int.TryParse));

bool isValid = numsByKey.Values.All(n => n.HasValue);

这保留了与之前几乎相同的信息,除了细粒度信息需要查找而不是本地变量访问。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接