locked
conditional casting to generic type for value types

    Question

  • Hey,

    I have the following code for reference types that works perfectly and does what I would like to:

    public T GetAttribute<T>(string attributeName) where T : class
    {
        if (attributeName == null)
            throw new ArgumentNullException("attributeName");

        if (typeof(T) == typeof(string))
            return this[attributeName] as T; // this[string attributeName] returns string

        return null;
    }

    Of course, the as operator I can only use because of where T : class. If I try to do something very similar for value types, I can't get through the compiler unfortunately. Something similar to this:

    public override T? GetAttributeValue<T>(string attributeName) : where T : struct
    {
        if (attributeName == null)
            throw new ArgumentNullException("attributeName");

        if (typeof(T) == typeof(int))
        {
            int value;
            if (Int32.TryParse(this[attributeName], out value))
                return (int?)value;
            else
                return null;
        }

        return null;
    }

    Of course, because there's no implicit cast (at least the compiler doesn't know about it at compile time) between int? and T?, this results in a compiler error. How could I get the compilerto assume this at compile-time / runtime or what different way I can implement something similar without having to declare a method for each value type I might return (GetIntValue, GetDateTimeValue, etc) and use a single generic method? Maybe even combine together the two methods for value and reference types into one? :)

    Thanks for the help,

    Gabor

    Monday, March 06, 2006 5:29 PM

Answers

  • public T GetAttribute<T>(string attributeName) {
        T value;
        if (TryGetAttribute<T>(attributeName, out value))
            return value;
        else
            throw new ArgumentException("No attribute by that name.", "attributeName");
    }

    public bool TryGetAttribute<T>(string attributeName, out T value) {
        if (string.IsNullOrEmpty(attributeName))
            throw new ArgumentNullException("attributeName");

        value = default(T);
        string rawValue = this[attributeName];
        if (rawValue == null)
            return false;

        // parse string to target type
        if (typeof(T) == typeof(string)) {
            value = (T)(object)rawValue;
            return true;
        }
        else if (typeof(T) == typeof(int)) {
            int parsedValue;
            bool result = int.TryParse(rawValue, out parsedValue);
            if (result)
                value = (T)(object)parsedValue;
            return result;
        }
        return false;
    }

    Wednesday, March 08, 2006 12:16 PM
  • The simplest solution would be something like:

    public delegate T Parser<T>(string value);
     
    public T GetAttribute<T>(string attributeName, Parser<T> parser)
    {
        if (attributeName == null)
            throw new ArgumentNullException("attributeName");
        
        string value = this[attributeName];
        if (typeof(T) == typeof(string))
            return (T)(object)value;
        
        if (parser == null)
            throw new ArgumentNullException("parser");
        
        return parser(value);
    }
     
    int valueInt32 = GetAttribute(attributeName, int.Parse);
    bool valueBoolean = GetAttribute(attributeName, bool.Parse);
    // etc.
    Friday, March 10, 2006 5:49 PM
  • This should cover all the options:

    public delegate T Parser<T>(string value);
    public delegate bool TryParser<T>(string value, out T result);
     
    public static bool TryGetAttribute<T>(string attributeName, TryParser<T> parser, out T result)
    {
        if (string.IsNullOrEmpty(attributeName))
            throw new ArgumentNullException("attributeName");
     
        string value = this[attributeName];
        if (typeof(T) == typeof(string))
        {
            result = (T)(object)value;
            return true;
        }
        
        if (string.IsNullOrEmpty(value))
        {
            result = default(T);
            return false;
        }
        
        if (null == parser)
            throw new ArgumentNullException("parser");
        
        return parser(value, out result);
    }
     
    public static bool TryGetNullableAttribute<T>(string attributeName, TryParser<T> parser, out T? result) where T : struct
    {
        if (string.IsNullOrEmpty(attributeName))
            throw new ArgumentNullException("attributeName");
     
        string value = this[attributeName];
        if (string.IsNullOrEmpty(value))
        {
            result = null;
            return false;
        }
        
        if (null == parser)
            throw new ArgumentNullException("parser");
          
        T parsedValue;
        if (parser(value, out parsedValue))
        {
            result = parsedValue;
            return true;
        }
        
        result = null;
        return false;
    }
     
    public static T GetAttribute<T>(string attributeName, Parser<T> parser)
    {
        if (string.IsNullOrEmpty(attributeName))
            throw new ArgumentNullException("attributeName");
        
        string value = attributeName;
        if (typeof(T) == typeof(string))
            return (T)(object)value;
        
        if (string.IsNullOrEmpty(value))
            return default(T);
        
        if (null == parser)
            throw new ArgumentNullException("parser");
        
        return parser(value);
    }
     
    public static T? GetNullableAttribute<T>(string attributeName, Parser<T> parser) where T : struct
    {
        if (string.IsNullOrEmpty(attributeName))
            throw new ArgumentNullException("attributeName");
     
        string value = attributeName;
        if (string.IsNullOrEmpty(value))
            return null;
         
        if (null == parser)
            throw new ArgumentNullException("parser");
        
        return parser(value);
    }
    Friday, March 10, 2006 6:19 PM

All replies

  • public T GetAttribute<T>(string attributeName) {
        T value;
        if (TryGetAttribute<T>(attributeName, out value))
            return value;
        else
            throw new ArgumentException("No attribute by that name.", "attributeName");
    }

    public bool TryGetAttribute<T>(string attributeName, out T value) {
        if (string.IsNullOrEmpty(attributeName))
            throw new ArgumentNullException("attributeName");

        value = default(T);
        string rawValue = this[attributeName];
        if (rawValue == null)
            return false;

        // parse string to target type
        if (typeof(T) == typeof(string)) {
            value = (T)(object)rawValue;
            return true;
        }
        else if (typeof(T) == typeof(int)) {
            int parsedValue;
            bool result = int.TryParse(rawValue, out parsedValue);
            if (result)
                value = (T)(object)parsedValue;
            return result;
        }
        return false;
    }

    Wednesday, March 08, 2006 12:16 PM
  • Beautiful! You are the king of the hill :)

    I would expect there's no solution without boxing/unboxing because of no conditions on the type parameters..

    Because I will have to take care of nullable types and handle accordingly, this will still have to be improved but I really like the direction and the idea, thank you!

    I will definitely post if I figure out anything else.

    Thursday, March 09, 2006 11:24 AM
  • The simplest solution would be something like:

    public delegate T Parser<T>(string value);
     
    public T GetAttribute<T>(string attributeName, Parser<T> parser)
    {
        if (attributeName == null)
            throw new ArgumentNullException("attributeName");
        
        string value = this[attributeName];
        if (typeof(T) == typeof(string))
            return (T)(object)value;
        
        if (parser == null)
            throw new ArgumentNullException("parser");
        
        return parser(value);
    }
     
    int valueInt32 = GetAttribute(attributeName, int.Parse);
    bool valueBoolean = GetAttribute(attributeName, bool.Parse);
    // etc.
    Friday, March 10, 2006 5:49 PM
  • This should cover all the options:

    public delegate T Parser<T>(string value);
    public delegate bool TryParser<T>(string value, out T result);
     
    public static bool TryGetAttribute<T>(string attributeName, TryParser<T> parser, out T result)
    {
        if (string.IsNullOrEmpty(attributeName))
            throw new ArgumentNullException("attributeName");
     
        string value = this[attributeName];
        if (typeof(T) == typeof(string))
        {
            result = (T)(object)value;
            return true;
        }
        
        if (string.IsNullOrEmpty(value))
        {
            result = default(T);
            return false;
        }
        
        if (null == parser)
            throw new ArgumentNullException("parser");
        
        return parser(value, out result);
    }
     
    public static bool TryGetNullableAttribute<T>(string attributeName, TryParser<T> parser, out T? result) where T : struct
    {
        if (string.IsNullOrEmpty(attributeName))
            throw new ArgumentNullException("attributeName");
     
        string value = this[attributeName];
        if (string.IsNullOrEmpty(value))
        {
            result = null;
            return false;
        }
        
        if (null == parser)
            throw new ArgumentNullException("parser");
          
        T parsedValue;
        if (parser(value, out parsedValue))
        {
            result = parsedValue;
            return true;
        }
        
        result = null;
        return false;
    }
     
    public static T GetAttribute<T>(string attributeName, Parser<T> parser)
    {
        if (string.IsNullOrEmpty(attributeName))
            throw new ArgumentNullException("attributeName");
        
        string value = attributeName;
        if (typeof(T) == typeof(string))
            return (T)(object)value;
        
        if (string.IsNullOrEmpty(value))
            return default(T);
        
        if (null == parser)
            throw new ArgumentNullException("parser");
        
        return parser(value);
    }
     
    public static T? GetNullableAttribute<T>(string attributeName, Parser<T> parser) where T : struct
    {
        if (string.IsNullOrEmpty(attributeName))
            throw new ArgumentNullException("attributeName");
     
        string value = attributeName;
        if (string.IsNullOrEmpty(value))
            return null;
         
        if (null == parser)
            throw new ArgumentNullException("parser");
        
        return parser(value);
    }
    Friday, March 10, 2006 6:19 PM