简体   繁体   中英

Returning multiple results from a function

I have the following code :

public object[] Dispatch(string arg)
{
    int time;
    int i = 0;
    object[] array = new object[10];
    if (int.Parse(arg) >= 0 && int.Parse(arg) <= 20)
    {
        array[i] = new ComputeParam(int.Parse(arg));
    }
    else
    {
        if (arg[0] == '/' && arg[1] == 't')
        {
            Options opt = new Options();
            time = opt.Option(arg);
        }
    }
    return array;
}

I pass arguments to my program and ArgsParser either puts them into an array if they are numbers or sets a delay time if the argument is something like /t:=Max . The thing is I need both the array and the time and I can't return two values. How can I go about solving this problem?

You can use a return class for that, just create a custom object:

public class DataRC {
      public object[] aObj { get; set;}
      public DateTime dtTime {get; set;}
}

and change your function, so:

public class ArgsParser
{

   public DataRC Dispatch(string arg)
   {
       DataRC dResult = new DataRC();
       int time;
       int i = 0;
       dResult.aObj = new object[10];
       if (int.Parse(arg) >= 0 && int.Parse(arg) <= 20)
       {
           dResult.aObj[i] = new ComputeParam(int.Parse(arg));
       }
       else
       {
           if (arg[0] == '/' && arg[1] == 't')
           {
               Options opt = new Options();
               // Is this where you need the time?
               dResult.dtTime = opt.Option(arg);
           }
       }
       return dResult;
   }
 }
}

Use ac sharp out parameter for returning time. This will let you return more than one values from a function. The out method parameter keyword on a method parameter causes a method to refer to the same variable that was passed into the method. Any changes made to the parameter in the method will be reflected in that variable when control passes back to the calling method.

http://msdn.microsoft.com/en-us/library/t3c3bfhx(v=vs.71).aspx

As long as it is not specified what .net framework it is, you can use Tuple type on newer framework versions:

Tuple<object[], DateTime> Dispatch(string arg)

But as Shai wrote, it is better to create a return class for that.

You can either:

  1. Use out parameters
  2. Create a custom class for the return type and encapsulate what you want to return in there.

I prefer approach 2 because return parameters can get messy and calling code will be a lot cleaner if it got a custom object back with what was expected. But of course it depends on each situation.

Parse() will crash! Use TryParse()

  1. If the arg equals something like /t:=Max or any other non-integer, then int.Parse(arg) will throw an exception .
  2. You are invoking int.Parse() twice unnecessarily (even more!).

So, you should change your if-else to:

...
int argInt;
if(int.TryParse(arg, out argInt) && ...)
{
    array[i] = new ComputeParam(argInt);
}
else
...


Your answer:

Option 1: out parameter

Change the method definition to below, and set time as you already did:

public object[] Dispatch(string arg, out int time)

Option 2: Encapsulate return value in an object

Define a class like below, and return an instance of it:

class DispatchReturn
{
    object[] array;
    int      time;
}

Then return it:

public DispatchReturn Dispatch(string arg)

Option 3: Changing parser class. Don't!

You can put both the array and time inside the parser as fields, but avoid it! It violates separation of concerns .


Wrap-up

public ComputeParam[] Dispatch(string arg, out time)
{
    if (arg == null)
        throw new ArgumentNullException("arg");

    ComputeParam[] array = new ComputeParam[1];
    int argInt;

    if (int.TryParse(arg, out argInt) && 0 <= argInt && argInt <= 20)
    {
        array[0] = new ComputeParam(argInt);
        time     = 0; // You must always set an out param
    }
    else if (arg.StartsWith("/t")
    {
        time = new Options().Option(arg);
    }

    return array;
}

You should answer these questions:

  1. What does i ? Is this always equals to 0 ?
  2. Why your return type is an array of object s, instead of ComputeParam s?
  3. Why do you create the array for 10 elements and put only one?

The above code can be significantly change according to your answers.

As a further elaboration of Shai's answer you can make ArgsParser to hold output parameter itself. The parsing can be done in its constructor, if it feels right:

public class ArgsParser
{
   public object[] aObj { get; set;}
   public DateTime dtTime {get; set;}

   public ArgsParser(string arg)
   {
       int time;
       int i = 0;
       aObj = new object[10];
       if (int.Parse(arg) >= 0 && int.Parse(arg) <= 20)
       {
           aObj[i] = new ComputeParam(int.Parse(arg));
       }
       else
       {
           if (arg[0] == '/' && arg[1] == 't')
           {
               Options opt = new Options();
               // Is this where you need to time?
               dtTime = opt.Option(arg);
           }
       }
   }
 }
}

I assume ArgsParser exists only for parameters parsing

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM