views:

467

answers:

4

Is it possible to cast out param arguments in C#? I have:

Dictionary<string,object> dict;  // but I know all values are strings
string key, value;

Roughly speaking (and if I didn't have static typing) I want to do:

dict.TryGetValue(key, out value);

but this obviously won't compile because it "cannot convert from 'out string' to 'out object'".

The workaround I'm using is:

object valueAsObject;
dict.TryGetValue(key, out valueAsObject);
value = (string) valueAsObject;

but that seems rather awkward.

Is there any kind of language feature to let me cast an out param in the method call, so it does this switcheroo for me? I can't figure out any syntax that'll help, and I can't seem to find anything with google.

+3  A: 

If you know all values are strings use Dictionary<string, string> instead. The out parameter type is set by the type of the second generic type parameter. Since yours is currently object, it will return an object when retrieving from the dictionary. If you change it to string, it will return strings.

John Sheehan
The Dictionary<string,object> is provided by an interface I'm using. I know all values are strings for my use of it, because that's what I'm filling it with here.
Ken
A: 

No, you can't. The code inside the method is directly modifying the variable passed to it, it is not passed a copy of the content of the variable.

AnthonyWJones
+1  A: 

No, there is no way around that. The out parameter must have a variable that matches exactly.

Using a string reference is not safe, as the dictionary can contain other things than strings. However if you had a dictionary of strings and tried to use an object variable in the TryGetValue call, that won't work either even though that would be safe. The variable type has to match exactly.

Guffa
+7  A: 

I don't know if it is a great idea, but you could add a generic extension method:

    static bool TryGetTypedValue<TKey, TValue, TActual>(
        this IDictionary<TKey, TValue> data,
        TKey key,
        out TActual value) where TActual : TValue
    {
        TValue tmp;
        if (data.TryGetValue(key, out tmp))
        {
            value = (TActual)tmp;
            return true;
        }
        value = default(TActual);
        return false;
    }
    static void Main()
    {
        Dictionary<string,object> dict
            = new Dictionary<string,object>();
        dict.Add("abc","def");
        string key = "abc", value;
        dict.TryGetTypedValue(key, out value);
    }
Marc Gravell
This is an interesting bit of syntactic sugar.
Steven Sudit
+1 never done this on a dictionary, but have some very similar helper ext methods.
Rex M
The only thing I'd possibly consider changing would be the handling of the case where the value is found but is of the wrong type. Instead of throwing, I might want it to just return false. Then again, I might not. I'd have to think this over, but it's worth mentioning.
Steven Sudit
That's pretty cool. I don't think I'll use that (yet -- since it's way overkill for my case), but it's definitely cool.
Ken