Casting C# out parameters?

后端 未结 6 1580
孤城傲影
孤城傲影 2020-12-30 20:35

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

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


        
相关标签:
6条回答
  • 2020-12-30 20:41

    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.

    0 讨论(0)
  • 2020-12-30 20:44

    I spy with my little eye an old post that was still active a month ago... Here's what you do:

    public static class DictionaryExtensions
    {
        public static bool TryGetValueAs<Key, Value, ValueAs>(this IDictionary<Key, Value> dictionary, Key key, out ValueAs valueAs) where ValueAs : Value
        {
            if(dictionary.TryGetValue(key, out Value value))
            {
                valueAs = (ValueAs)value;
                return true;
            }
    
            valueAs = default;
            return false;
        }
    }
    

    And because compilers are great, you can just call it like this:

    dict.TryGetValueAs(key, out bool valueAs); // All generic types are filled in implicitely! :D
    

    But say you're not creating a blackboard AI and just need to call this operation the one time. You can simply do a quicksedoodle inliner like this:

    var valueAs = dict.TryGetValue(key, out var value) ? (bool)value : default;
    

    I know these answers have been given already, but they must be pretty old because there is no cool hip modern inlining going on to condense these methods to the size we really want: no more than 1 line.

    0 讨论(0)
  • 2020-12-30 20:50

    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.

    0 讨论(0)
  • 2020-12-30 20:58

    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);
        }
    
    0 讨论(0)
  • 2020-12-30 20:59

    I used Marc's extension method but added a bit to it.

    My problem with the original was that in some cases my dictionary would contain an int64 whereas I would expect an int 32. In other cases the dictionary would contain a string (for example "42") while I would like to get it as an int.

    There is no way to handle conversion in Marc's method so I added the ability to pass in a delegate to a conversion method:

    internal static bool TryGetTypedValue<TKey, TValue, TActual>(
            this IDictionary<TKey, TValue> data,
            TKey key,
            out TActual value, Func<TValue, TActual> converter = null) where TActual : TValue
        {
            TValue tmp;
            if (data.TryGetValue(key, out tmp))
            {
                if (converter != null)
                {
                    value = converter(tmp);
                    return true;
                }
                if (tmp is TActual)
                {
                    value = (TActual) tmp;
                    return true;
                }
                value = default(TActual);
                return false;
            }
            value = default(TActual);
            return false;
        }
    

    Which you can call like this:

    int limit;
    myParameters.TryGetTypedValue("limitValue", out limit, Convert.ToInt32)
    
    0 讨论(0)
  • 2020-12-30 20:59

    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.

    0 讨论(0)
提交回复
热议问题