Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is *DoesNotReturnAttribute* not working as expected?

Tags:

c#

I 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?

like image 910
CleanCoder Avatar asked Jun 29 '26 01:06

CleanCoder


2 Answers

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);
}
like image 64
CleanCoder Avatar answered Jul 01 '26 19:07

CleanCoder


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.

like image 33
Mike Marynowski Avatar answered Jul 01 '26 21:07

Mike Marynowski