c# - 是否可以在空检查中推断类型的名称

标签 c# error-handling asp.net-web-api2

我正在玩一个webapi2项目。
使用 Controller 类->

调用处理业务逻辑的服务类,->

它使用一个处理数据库调用的存储库。
为了提高可读性,我决定在服务类中使用nullchecks(即:

var object = _repository.GetById(5) ?? throw new CustomException(CustomException.Object1NotFound_Exception_Message);

)。

这样,我的 Controller 逻辑将保持清晰易读,避免在 Controller 方法[get/post/put/delete]中进行这些检查。

这样,我可以尝试/捕获我的 Controller 逻辑,然后捕获(customexception ex)
并调用扩展方法ex.converttostatuscoderesult。 (如下所示)。
public class CustomException : Exception
{
    public const string Object1NotFound_Exception_Message = "Object not found using ID.";
    public const string Object2NotFound_Exception_Message = "Object2 not found using ID.";
    public const string UserNotAllowedX_Exception_Message = "Current user not allowed to do X.";
    public const string UserNotAllowedY_Exception_Message = "Current user not allowed to do Y.";
    <~even more strings containing ExceptionMessages> 

    public int ExceptionStatusCodeDefinition { get; set; }

    public CustomException(string message) : base(message)
    {
        switch (message)
        {
            case Object1NotFound_Exception_Message:
            case Object2NotFound_Exception_Message:

                ExceptionStatusCodeDefinition = 404;
                break;
            case UserNotAllowedX_Exception_Message:
            case UserNotAllowedY_Exception_Message:
            case UserNotAllowedZ_Exception_Message:
                ExceptionStatusCodeDefinition = 403;
                break;
            default:
                ExceptionStatusCodeDefinition = 400;
                break;
        }
    }
}

public static class CustomExceptionExtention
{
    public static IActionResult ConvertToStatusCodeResult(this CustomException exception)
    {
        return new Microsoft.AspNetCore.MvcStatusCodeResult(exception.ExceptionStatusCodeDefinition);
    }
}

但是,此方法要求我事先设置异常消息。
这不可避免地意味着我的异常消息列表太长了。

我试图重构这种方法,以推断类型的名称并具有一条异常消息NotFound_Exception_Message。并在运行时附加类型名称。

最初,我尝试对Type进行切换,由于编译器原因(我理解它的方式,如果继承起着作用,编译器就无法告诉我需要哪种类型名),该开关不起作用。

为了避免这种情况,我开设了此类:
 public class TypeCase
{

 public static TypeCase GetType(Type type)
    {
        return new TypeCase(type);
    }

    public string TypeName { get; set; }

    public TypeCase(object type)
    {
        TypeName = type.GetType().Name;
    }
}

只要对象具有值,此方法就可以正常工作,因为如果该对象引用为null,则无法反射(reflect)该对象的实例。

我一直在为这个问题烦恼。
我希望有人可以阐明这个问题,或者向我解释为什么这是一个不好的解决方案。
因为我开始认为这种方法是确定的代码气味。

(我知道这种方法不会在IActionResult中返回异常消息。这也是一个问题,但超出了此问题的范围。)

我非常感谢您在此问题上的帮助。

最佳答案

直接的答案是不,您不能做自己想做的事情。如果由于函数返回null而引发异常,则无法检查将要返回的对象的类型。

您所知道的只是GetById返回的声明类型。换句话说,如果该函数声明为

Foo GetById(int id)

那么您知道它返回的是Foo。如果返回结果,则可以检查它的类型是否是Foo或从Foo继承的其他类型。但是,如果您没有得到结果,那么您所能知道的就是它是Foo。但是由于您要的是Foo,所以这是唯一重要的类型。

换句话说,无需推断该方法返回的类型。它声明返回的类型。您知道类型是什么,因为您正在调用方法来获取该类型的对象。如果您还不知道类型是什么,则没有理由调用该方法。

由于您知道类型,并且唯一使下一个异常消息与下一个异常消息不同的细节是类型,因此下一步是弄清楚如何在异常消息中传达该类型。

老实说,这是我们经常忽略的事情。您可能对此表示满意:
var object = _repository.GetById(5) ?? throw new CustomException("Foo not found using ID.");

真的,有多糟?即使消息只是“未找到Foo”,stacktrace也会向您显示该方法,然后您可以从中确定使用ID检索它的方法。

使用常量很好,但是当值具有重要意义时,它就更重要。如果您的下一个异常有错别字-“未使用ID标记错误”-会很杂乱,但不会破坏任何内容。我还可以看到使用常数,如果消息要长得多并且重复很多。

到目前为止,这是我的第一个建议。如果您确实想确保异常消息是恒定的,并且只在一个地方声明,并且无论如何都在创建自定义异常,则可以执行类似的操作(尽管我真的不是。)
// Really, don't do this.
public class ItemNotFoundByIdException<T> : Exception
{
    public ItemNotFoundByIdException()
    :base($"{typeof(T).Name} not found by ID.") { }
}

然后,如果您尝试通过ID获取Foo,则可以执行以下操作:
var foo = _repository.GetById(5) ?? throw new ItemNotFoundByIdException<Foo>();

但这导致异常的复杂层次结构。除非您或其他人要捕获此特定的异常类型并以与其他异常类型不同的方式处理它,否则这将是额外的复杂性,并且没有任何好处。

我知道我们会如何沉迷于此类事情,但这不是您应用程序的重要部分。这不值得。我只是将这些简短的异常消息硬编码在需要的地方。

关于c# - 是否可以在空检查中推断类型的名称,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55856154/

相关文章:

c# - 在 Entity Framework 中更新数据库

c# - 在递归调用中使用 lock(obj)

c# - 听WaveOutDevice

c++ - OpenGL不报告着色器编译器错误

c# - Web Api 在发生异常时总是返回 http 状态码 200

带有 Web API 的 Azure B2C

c# - RoutePrefix 与路由

c# - 如何将多个文件附加到电子邮件

powershell - Powershell 中未处理异常的默认行为

error-handling - 存在哪些日志记录已处理和未处理的异常的Web服务或应用程序错误?