13

This is a very basic question, and if what I am thinking of doing is complicated/involved, then I don't expect you to go into detail... I've read that this may involve structs or hash or some other scary procedure I've not gotten to yet. If so, I'm sure it'll get me soon.

Working on learning classes, methods, and return values.

I'd like to have my class/method return Current Hour and Minute. Simple enough, really. Is this constructed correctly, or properly?

class MyClass
{
    public int GetHour (int hr, int min)
    {
        DateTime dt = DateTime.Now;
        int hour = dt.Hour;
        int minute = dt.Minute;

        return hour;
        return minute;

    }
}

And, calling it from Main(): Getting some errors (No overload for method and Unreachable code detected)

static void Main ( string[] args )
{
    MyClass mc = new MyClass ();
    Console.WriteLine ("Hour: {0} \n Minute: {1}", mc.GetHour());   
    Console.ReadLine ();
}

Question is: Am I Close?

Matt Ellen
  • 11,268
  • 4
  • 68
  • 90
DonG
  • 801
  • 3
  • 11
  • 13
  • 1
    short answer : NO , you can return multiple values in array , list , dictionary , or any collection – Mahmoud Farahat Oct 21 '10 at 22:26
  • Why don't you store `DateTime.Now` on `mc` instead and use its properties? – BrunoLM Oct 21 '10 at 22:30
  • possible duplicate of [How can I return multiple values from a function in C#?](http://stackoverflow.com/questions/748062/how-can-i-return-multiple-values-from-a-function-in-c) – nawfal Jan 15 '14 at 05:08

11 Answers11

33

As mentioned by @ChaosPandion, in that specific case you would return a DateTime struct.

In general, however, you would have the following options:

Using out parameters

This is a simple way that will usually always work. However, it is a bit clunky, as the result is returned where you usually would expect the function arguments to be passed and the method signature might get lengthy and hard to refactor.

public void GetTime(out int hr, out int min) 
{ 
    DateTime dt = DateTime.Now;
    hr = dt.Hour;
    min = dt.Minute;
}

static void Main(string[] args)
{
     // declare variables for out parameters first
     int hour, minute;
     GetTime(out hour, out minute);
}

Using an array

This is a simple method that works well if the values to be returned have the same type.

public int[] GetTime() 
{ 
    DateTime dt = DateTime.Now;
    return new[] { dt.Hour, dt.Minute};
}

Using a property bag (A property bag is a simple class which only has properties)

This is very convenient and allows easy modification of the type and number of returned values later on without changing the method signature.

class A
{ 
     int Prop1 { get; set; }
     int Prop2 { get; set; }
}

public A SomeMethod()
{
    return new A() { Prop1 = 1, Prop2 = 2 }
}    

Using a Tuple

In C# 4.0 (requires VS 2010) you can use the Tuple<T1, T2, ...> class:

public Tuple<int, int> GetTime() 
{ 
    DateTime dt = DateTime.Now;
    return Tuple.Create(dt.Hour, dt.Minute);
}

C# 7.0 Tuples

C# 7.0 adds support for multiple return values. You can write code like this to return an implicitly created tuple:

(string, string, string) LookupName(long id) // tuple return type
{
    ... // retrieve first, middle and last from data storage
    return (first, middle, last); // tuple literal
}

The tuple elements are names Item1, Item2, etc by default, but you can also specify names, e.g.

(string first, string middle, string last) LookupName(long id) // tuple return type
{
    ... // retrieve first, middle and last from data storage
    return (first, middle, last); // tuple literal
}

and then access the tuple elements via those names:

var names = LookupName(id);
WriteLine($"found {names.first} {names.last}.");
Dirk Vollmar
  • 172,527
  • 53
  • 255
  • 316
  • I find out parameters to be a bit clunky but this is certainly a viable solution. – ChaosPandion Oct 21 '10 at 22:25
  • 1
    @ChaosPandion: Yes, there are certainly often better approaches, I'm just trying to give an overview of the possibilities. – Dirk Vollmar Oct 21 '10 at 22:27
  • Please fix the spelling: Tupel should be Tuple. – mtreit Oct 21 '10 at 23:02
  • @mtreit: Thanks. Sorry if this caused any confusion. – Dirk Vollmar Oct 21 '10 at 23:20
  • I'd suggest a struct rather than a class. While the garbage collector is pretty good at handling really-short-lived objects, it still doesn't "feel" right to create heap objects needlessly. – supercat Oct 22 '10 at 00:39
  • you can use reference variables as well (ref int x, ref int y) . You can alternatively declare a struct value type and pass that back. But as stated above, C# doesnt support multiple returns – Kirit Chandran Oct 22 '10 at 01:04
6

C# does not support multiple return values so in this case you should return a DateTime struct which is the idiomatic approach. The client code can simply ignore the properties that they don't care about. You could create your own simple struct but it really isn't worth the effort.

ChaosPandion
  • 77,506
  • 18
  • 119
  • 157
  • My very first thought to this was to create a new method, called GetMinute that would look very much like GetHour... but man that'd be a lot of code for one easy thing. I know not a whit about structs yet. Thank you! – DonG Oct 21 '10 at 22:21
  • 2
    @DonG - The biggest advantage of using `DateTime` is clarity. Almost every .NET developer will know exactly how to use your code. – ChaosPandion Oct 21 '10 at 22:28
3

C# doesn't support the idea of directly returning multiple values from a method in that fashion. However there are a couple of ways to create methods which return multiple values. The first is to use ref / out parameters.

public void GetHourMinute(out int hour, out int minute) { 
  var now = DateTime.Now;
  hour = now.Hour;
  minute = now.Minute;
}

The second is to create a wrapper type which encapsulates the two values. Starting in 4.0 this can be made a bit easier by using the Tuple type.

public Tuple<int,int> GetHourMinute() {
  var now = DateTime.Now;
  return Tuple.Create(now.Hour, now.Minute);
}
spender
  • 117,338
  • 33
  • 229
  • 351
JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
  • 1
    Without first class tuple support I generally keep such things private. – ChaosPandion Oct 21 '10 at 22:24
  • Okay, I'll burn, I mean cross that bridge when I get to it. This was my own little exploration into returning values. Thanks! – DonG Oct 21 '10 at 22:25
  • @DonG, regarding the suggestion of using `out` parameters, I refer you to http://stackoverflow.com/questions/2366741/what-is-bad-practice-when-using-out-parameters – DaveDev Oct 21 '10 at 23:05
2

1: You can't have two returns. Once the compiler reaches the return statement, the operation of the method is finished.
2: Why would you want your method to receive parameters if you don't use them? DateTime.Now gives you the current time, if you'll think of yourself as that method - what do you need in order to complete your task? Nothing.

So, practical tips:
1. Actually, the DateTime does what you need better than your method.

Console.WriteLine ("Hour: {0} \n Minute: {1}", DateTime.Now.Hour,DateTime.Now.Minute);

Would have been better,
but let's ignore that and consider it an exercise in classes.

2 Returning two values is against the concept of a method - a method returns one thing (there are exceptions as out ref, but we'll ignore them).
You can actually see that in your own code - your method name is GetHour not GetHourAndMinutes. I don't think I've ever seen a method's name with the word "and" - a method does only one thing.

Oren A
  • 5,870
  • 6
  • 43
  • 64
2

I suggest you return the DateTime object. Then in your main method you call Hour and Minute properties.

Peanut
  • 18,967
  • 20
  • 72
  • 78
1

Yeah, you can only return one 'thing' from method in C#.

The other problem you have is you are calling a method without any parameters. The things in the brackets:

public int GetHour (int hr, int min) // here
{
}

Are parameters. And you need to specify them when calling the method, like so:

mc.GetHour(1, 2);

But of course, in your case, it doesn't make sense to do this.

To answer the general question of: "How do I return more than one thing?" You encapsulate it in a class, set the properties, and return that class. It so happens, in the example you've given, the DateTime class does just that.

Hope this is helpful.

Noon Silk
  • 54,084
  • 6
  • 88
  • 105
1

Sorry, you can't do that. You'd be better served returning an array or an object. You could return the DateTime object and use it.

Also as stated, your function signature wasn't being called properly.

class MyClass
        {
        public int[] GetHour ()
            {
            DateTime dt = DateTime.Now;

            int hour = dt.Hour;
            int minute = dt.Minute;

            return new int[]{hour, minute};
            }
        }

static void Main ( string[] args )
            {
            MyClass mc = new MyClass ();
int[] temp = mc.GetHour();
            Console.WriteLine ("Hour: {0} \n Minute: {1}", temp[0], temp[1]);

            Console.ReadLine ();
            }
TheClair
  • 721
  • 4
  • 8
1

You cant return multiple value. TimeSpan is exactly what you are looking for. Create an object of that with hour, minute and even second that you want to capture and return it.

Come to think about it, for what you need above, you dont even have to write the method above. Just use DateTime.Now.TimeOfDay directly in your code

Fadrian Sudaman
  • 6,405
  • 21
  • 29
  • Yeah, that's def a better idea to just use TimeOfDay, but my experiment here was to play around with returning multiple values. I'm in week 3 of C# class...Thanks! – DonG Oct 21 '10 at 22:28
1

You can't return twice, only once.
Several return values at once require lambda expressions, and AFAIK, only Python is capable of that.
Syntax there goes like this:

return x, y

So maybe you should try IronPython, and then decompile to C#.

In C#, there are exactly two ways to return more than one value:
1. Use arguments as call by reference, that way you can assign 3 variables and then return.
2. Use some kind of struct/class/array/tuple/vector and place your multiple values into it.

Call by reference is something like this:

public static void xxx(ref var1, ref var2, ref var3) { var1 = 123; var2 = 456; var3 = 789; return; }

then you do:

int a =1;
int b=2;
int c=3;

xxx(ref a, ref b, ref c);

Console.WriteLine(a.ToString());
Console.WriteLine(b.ToString());
Console.WriteLine(c.ToString());
Stefan Steiger
  • 78,642
  • 66
  • 377
  • 442
1

In C# a method can return multiple times, if you use yield return format.

using System.Collections.Generic;

namespace YieldReturn
{
    class Program
    {
        public static void Main(string[] args)
        {
            MyClass mc = new MyClass();
            IEnumerator<int> enu = mc.GetHour().GetEnumerator();
            enu.MoveNext();
            int hour = enu.Current;
            enu.MoveNext();
            int min = enu.Current;
            Console.WriteLine("Hour {0} min {1}", hour, min);
            Console.ReadKey(true);
        }
    }

    class MyClass
    {
        DateTime dt;

        public MyClass()
        {
            dt = DateTime.Now;
        }
        public IEnumerable<int> GetHour()
        {
            int hour = dt.Hour;
            int minute = dt.Minute;
            yield return hour;
            yield return minute;
        }
    }
}

Gives "Hour 8 min 50"

0

The question I would like to ask you is why do you want to return multiple values? Returning multiple values for me means having multiple responsibilities in the function and that should be a big don't since it is violating SRP. But, if those return values are related maybe they make an object that you're missing and should be created instead? Or a list with one type of object.

So for short. Why? Encapsulate your return values in ONE object? Don't do multiple things in one function.

EDIT: In your case I wouldn't even wrap your functionality in a function just write:

static void Main ( string[] args )
        {
        MyClass mc = new MyClass ();
        DateTime now = DateTime.Now;
        int hour = now.Hour;
        int min = now.Minute;
        Console.WriteLine ("Hour: {0} \n Minute: {1}", hour, min);

        Console.ReadLine ();
        }

And your function name GetHour doesn't do what the function says... if it says GetHour it should return the hour and not the hour plus the minute.

Tomas Jansson
  • 22,767
  • 13
  • 83
  • 137