0

I'm trying to get the name of a calling property in my extension method to use it in case of an exception.

My extension method looks like this:

/// <summary>
/// Parse string to value of T 
/// Can throw on Default or Exception
/// </summary>
/// <typeparam name="T">Type to Convert to</typeparam>
/// <param name="value">value for conversion</param>
/// <param name="throwOnDefault">set <see langword="true"/>for throw on Exception or Default</param>
/// <returns></returns>
/// <exception cref="NotSupportedException">If string can't be converted</exception>
/// <exception cref="Exception">If converted value is defaut</exception>
public static T ParseOrDefault<T>(this string value, bool throwOnDefault = false, [CallerMemberName]string methodName = "")
{
    if (Nullable.GetUnderlyingType(typeof(T)) == null && value.IsNullOrWhitespace()) 
        throw new ArgumentNullException(value, $"{methodName} : value of string is null");

    System.ComponentModel.TypeConverter converter = System.ComponentModel.TypeDescriptor.GetConverter(typeof(T));

    try
    {
        var converted = (T)converter.ConvertFromString(null, System.Globalization.CultureInfo.InvariantCulture, value);

        var type = converted?.GetType();

        if (type != null && type.IsValueType)
        {
            var defaultValue = Activator.CreateInstance(type);
            return !value.Equals(defaultValue) ? converted : throw new Exception("Converted value is default value");
        }
        else
        {
            return converted;
        }
    }
    catch (Exception)
    {
        if (throwOnDefault)
            throw;
        else
            return default;
    }
}

And I'am using it like this :

var parsedVal = property.ParseOrDefault<Guid>();

or like this :

public void SomeMethod (RequestModel request)
{
    Dto dto = new()
    {
        intProperty = request.IntValue.ParseOrDefault<int>(), // IntValue in the requestObject is a string 
        guidProperty = request.GuidValue.ParseOrDefault<Guid>() // GuidValue in the requestObject is a string
    }
}

I tried already some of the suggestions in the following link but they all just get me the name of the calling method, not the name of the property.

How to get current property name via reflection?

My Goal is to get the method and property to make my exceptions look something like this:

if (Nullable.GetUnderlyingType(typeof(T)) == null && value.IsNullOrWhitespace()) 
        throw new ArgumentNullException(value, $"{methodName} : value of {propertyName} is null");
  • 1
    There is no way to obtain what you want. You don't write extension methods for properties, you write them for values, and once the value has been obtained from the property, the property is no longer involved in the rest of the expression. At most you could get, from the stacktrace, where the expression was *written*, but you can't easily figure out which property the value was obtained from. – Lasse V. Karlsen Dec 01 '21 at 12:30
  • Well there was actually a way. @richard-deeming helped me out achieving what I wanted. I marked it as answer already. But thanks for trying to help out anyway^^ – Trickster91 Dec 01 '21 at 12:50

1 Answers1

3

[CallerMemberName] will give you the name of the method/property which called your extension method. In your example, that would be SomeMethod.

If you can update to C# 10, you can use the [CallerArgumentExpression] attribute instead.

public static T ParseOrDefault<T>(this string value, bool throwOnDefault = false, [CallerArgumentExpression("value")] string memberName = "")

For request.IntValue.ParseOrDefault<int>(), the memberName would be set to request.IntValue.

If you're using .NET Framework, you can still use this approach so long as you're using an up-to-date compiler. You will just need to manually define the attribute class.

Richard Deeming
  • 29,830
  • 10
  • 79
  • 151
  • I am using the latest version for a gRPC Service and the mapping and parsing stuff is quite a neckbreaker. thank you very much for the quick response. that worked out quite nice. <3 – Trickster91 Dec 01 '21 at 12:46