Kumar
Kumar

Reputation: 11349

Refactor using generics

I have a simple interface with methods such as

     bool TryGetValue(string key, out string value);
     bool TryGetValue(string key, out int value);
     bool TryGetValue(string key, out double value);
     bool TryGetValue(string key, out DateTime value);
     // only value types allowed 

     //with the implementation based on dictionary<string, object> 
     bool TryGetValue(string key, out string value)
     {
        object rc;
        if ( dict.TryGetValue(key, out rc) )
        {
            value = rc.ToString();
            return true;
        }

        value = null;
        return false;
     }

Looks like a perfect case for generics as

     bool TryGetValue<T>(string key, out T value) where T: ValueType;

except not able to work out the func implementation, anyone ?

UPDATE - the following does not compile, i'd like to avoid creating multiple TryGet... funcs !

     bool TryGetValue<T>(string key, out T value)
     {
         return dict.TryGetValue(key, out value) ;
     }

Upvotes: 2

Views: 686

Answers (6)

Oliver Dixon
Oliver Dixon

Reputation: 7405

Extension method.

namespace AssemblyCSharp
{
    public static class ExtentionMethod {

        public static bool TryGetValue<T, T2>(this Dictionary<T, T2> dict, string key, out T value) {
            return dict.TryGetValue(key, out value);
        }
    }
}

Upvotes: 0

kvb
kvb

Reputation: 55184

I'd probably go for something like this, although as Marc points out the struct constraint won't allow strings:

private static class Container<T> where T : struct
{
    public static Dictionary<string, T> Dict = new Dictionary<string, T>();
}

public bool TryGetValue<T>(string key, out T value) where T : struct
{
    return Container<T>.Dict.TryGetValue(key, out value);
}

Upvotes: 0

Aaronaught
Aaronaught

Reputation: 122644

I'm guessing that what you want is this:

 bool TryGetValue<TValue>(string key, out TValue value)
 {
    object rc;
    if (dict.TryGetValue(key, out rc))
    {
        value = (TValue)rc;
        return true;
    }

    value = default(TValue);
    return false;
 }

This doesn't actually convert the values if they are the wrong type - it assumes that the generic System.Object instances sitting in the dictionary are actually of type TValue when the TryGetValue method is invoked.

If you want to restrict the method to only allow value types for the generic parameter, just change the method signature to this:

 bool TryGetValue<TValue>(string key, out TValue value) where TValue : struct

Note - JaredPar had the first answer but seems to have deleted his, so I am undeleting mine because I think it's what the OP wanted. I apologize for any unintended duplication.

Upvotes: 5

Marc Gravell
Marc Gravell

Reputation: 1062820

I believe Aaronaught has caught the main crux of the problem (capturing the object and casting/unboxing to T), but some additional points:

  • to limit to value-types(*), you use where T : struct, not where T : ValueType...
  • ...but note that string is not a value-type, so this probably isn't a good "fit"
  • ...and (*=) note that where T : struct also excludes Nullable<T>

So I think you just need to remove that constraint completely.

Upvotes: 0

Nick Craver
Nick Craver

Reputation: 630419

Try this:

public bool TryGetValue<T>(string key, out T value) where T : struct
{
  object obj;
  var result = dict.TryGetValue(key, out obj);
  value = (T)obj;
  return result;
}

It' not pretty, but deals with the limitations of out...maybe someone can shorten it even more? If so please comment...always up to learn new ways.

Upvotes: 1

Woot4Moo
Woot4Moo

Reputation: 24316

Take a look at: http://msdn.microsoft.com/en-us/library/s4ys34ea.aspx it may prove useful to you. Also why not just extend Dictionary?

Upvotes: 0

Related Questions