简体   繁体   中英

Why is *DoesNotReturnAttribute* not working as expected?

Ich have a method ThrowNull covered with DoesNotReturn attribute which indicates that this method will never return.

[DoesNotReturn]
public static void ThrowNull([InvokerParameterName] string argName, string? customErrorText = null, [CallerMemberName] string callerName = "") => throw new ArgumentException(AddMethodName(customErrorText != null ? customErrorText.InsertArgs(argName) : Strings.ArgumentMustNotBeNullArgumentTemplate.InsertArgs(callerName), callerName), customErrorText == null ? argName : null);

but, it does not seem to work (as intended)

public static T ThrowIfNullOrGet<T>([MaybeNull, NotNullIfNotNull("source")] this T source, string argName, string? customErrorText = null, [CallerMemberName] string callerName = "") where T : class
{
    if (source != null)
        return source;

    Requires.ThrowNull(argName, customErrorText, callerName);
    return default; // still necessary to prevent compile error
}

Why?

Does DoesNotReturn not omit the necessity to put an return statement as it only avoids warnings?

The DoesNotReturn attribute has only declarative character and does not save you from putting return statement to non void methods/properties

use throw directly in your code and get the exception from somewhere else. (this can be seen often in decompiled MS code)

public static T GetOrThrowIfNull<T>([MaybeNull, NotNullIfNotNull("source")] this T source, string argName, string? customErrorText = null, [CallerMemberName] string callerName = "") where T : class
{
    if (source != null)
        return source;

    throw Exceptions.ArgumentNull(argName, customErrorText, callerName);
}

If you're using throw helpers then the throw helper should do the throw, not the method calling the throw helper. The right way to write this is to invert the if condition:

public static T GetOrThrowIfNull<T>([MaybeNull, NotNullIfNotNull("source")] this T source, string argName, string? customErrorText = null, [CallerMemberName] string callerName = "") where T : class
{
    if (source == null)
        Requires.ThrowNull(argName, customErrorText, callerName);

    return source;
}

It is good practice to do validation and exception throwing at the beginning of the method. It lets you reduce the nesting of the actual functionality of the method, and like shown above, lets you properly use throw helpers.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM