Search code examples
c#genericsmethodsreturn

Method with Multiple Return Types


I've looked through many questions that are similar to this, but none of them really touched on what I precisely want to do. What I am trying to do is read from an external source a list of variables that also include their data type into a string array:

Example:

ID/Key      Type    Value/Data; 
varName1    bool    true;
varName2    string  str;
varName3    int     5;

I then store these are objects into a dictionary as objects containing several strings, with the ID also serving as the key.

What I want to do is now create a method that uses a switch statement that casts the string into the correct datatype, and returns it without having to specify anything in the method call. The function should look something like this:

public ??? Method(string key)
{
    if(dictionary.ContainsKey(ID))
    {
        Var temp = dictionary[ID];

        switch (temp.Type)
        {
            case "bool":
                return Convert.ToBoolean(temp.Value);

            case "int"
                return Convert.ToInt(temp.Value);

            case "string"
                return temp.Value;
        }
    }

    return "NULL"; 
}

The method call should look something like this:

int x = Method(string key);
string word = Method(string key);
bool isTrue = Method(string key);

Maybe I've missed something, but I have yet to find something that really does something quite like this. Any and all thoughts about this are welcome as well.


Solution

  • Update

    I believe a lot of people are arriving at this question because they're looking for ways to return multiple values generally, not necessarily for the purposes given in the original question. If this is what you want, there are a few options to choose from.

    If the combination of your returned types represents a concept that may be useful outside of your method call, consider creating a type to represent that concept. C#'s records provide a nice, concise way to do that:

    public record ExtractedValue(bool? BooleanValue, string? StringValue, int? IntValue);
    
    public ExtractedValue Method(string key)
    {
       ...
    }
    

    If this is the only place these values will appear together, and it's not really worth coming up with a named type to represent the values, you can also use a Value Tuple. Just be aware that there are some behavioral implications that might bite you if you plan to use the type for things like serialization.

    public (bool? BooleanValue, string? StringValue, int? IntValue) Method(string key)
    {
       ...
    }
    

    Original Answer

    The compiler has no way to distinguish between the three method calls you've provided, because they all look like Method(key);

    One option is to return an object and then expect the consuming code to cast it to what they want:

    public object Method(string key)
    {
        if(dictionary.ContainsKey(key))
        {
            var temp = dictionary[key];
    
            switch (temp.Type)
            {
                case "bool":
                    return Convert.ToBoolean(temp.Value);
    
                case "int"
                    return Convert.ToInt(temp.Value);
    
                case "string"
                    return temp.Value;
            }
        }
    
        return "NULL"; 
    }
    
    ...
    
    int x = (int) Method(key);
    string word = (string) Method(key);
    bool isTrue = (bool) Method(key);
    

    You could also use the dynamic keyword to make the cast implicit:

    public dynamic Method(string key)
    {
        if(dictionary.ContainsKey(key))
        {
            var temp = dictionary[key];
    
            switch (temp.Type)
            {
                case "bool":
                    return Convert.ToBoolean(temp.Value);
    
                case "int"
                    return Convert.ToInt(temp.Value);
    
                case "string"
                    return temp.Value;
            }
        }
    
        return "NULL"; 
    }
    
    ...
    
    int x = Method(key);
    string word = Method(key);
    bool isTrue = Method(key);
    

    However, dynamic is a very powerful concept, and it's easy for it to get out of hand, so you have to be really careful with that.

    It seems to me that you're expecting your calling code to know which type of object it's expecting to get for each key. It seems like maybe the best approach is to just let the user supply that information:

    public T Method<T>(string key)
    {
        if(dictionary.ContainsKey(key))
            return (T) Convert.ChangeType(dictionary[key].Value, typeof(T));
        return default(T);
    }
    
    ...
    
    int x = Method<int>(key);
    string word = Method<string>(key);
    bool isTrue = Method<bool>(key);
    

    That way, there's no need to track the Type value in your dictionary objects in the first place.