Ashkan Mobayen Khiabani
Ashkan Mobayen Khiabani

Reputation: 34180

T type default value

I had several Extension Methods like ParseInt, ParseLong, ParseByte. now I'm trying to make a single extension method for all of them. the problem is that to make the Default parameter optional I have to give it a value like T Default = 0, but it generates the error:

A value of type 'int' cannot be used as a default parameter because there are no standard conversions to type 'T'

If I use it like T Default = (T)0 then I get another error:

Cannot convert type 'int' to 'T'

This is my extension method:

public static T Parse<T>(this string x, T Default = 0)
        {
            Type type = typeof(T);
            if(type == typeof(int))
            { if(!string.IsNullOrEmpty(x) int.TryParse(x , out Defualt); return Default;  }
        }

Upvotes: 4

Views: 12099

Answers (2)

Jon Skeet
Jon Skeet

Reputation: 1502686

You can just use default(T) instead:

public static T Parse<T>(this string x, T defaultValue = default(T))

However, I would strongly question the design here - you're not really writing a generic method, but a method which accepts one of a specific set of types and treats each one differently. There are times where this is enforced on you, but I'd typically have a Dictionary<T, SomeDelegate> to try to handle it more cleanly.

In addition, you're still going to have problems calling int.TryParse - you can't use the parameter to Parse<T> as an argument - you'd need something like:

if (typeof(T) == typeof(int))
{
    // You need to consider what you want to happen if
    // int.TryParse returns false - do you want to return 0,
    // or defaultValue?
    int ret;
    if (int.TryParse(x, out ret))
    {
        // Annoying but required due to which conversions are available
        return (T)(object) ret;
    }
}
return defaultValue;

Upvotes: 12

Like another answer mentioned already, you can get a generic type's default value as a compile-time constant by using the default keyword: default(T) in your case.

  • If T is a class or interface type, default(T) is the null reference.
  • If T is a struct, then default(T) is the value where all the bits are zero. This is 0 for numeric types, false for bool, and a combination of both of these rules for custom structs.

But: Don't do this. Don't create this generic method when it's only going to work for a few handpicked types. As a general rule, generic methods are intended to work for all types. (You can constrain the valid types with generic parameter constraints where T : … but that doesn't change the basic idea.)

In your case, the generic method is only going to work for a few types like int, long, float, double, decimal, etc. You even have to check for these types in your generic method already so that you can defer to the right method (int.TryParse, double.TryParse, etc.). That's a big sign that your method shouldn't be generic at all.

Stay with your previous extension methods ParseInt, ParseSingle, ParseDouble, etc. It was the better design.

Upvotes: 1

Related Questions