函数调用决定函数的返回类型

时间:2014-04-18 14:53:48

标签: c# overloading return-type

我在c#中遇到了烦恼:我有两个几乎完全正常的功能;函数中唯一不同的是它们的返回类型。

如果可能的话,你如何实现一个函数,它将具有由调用决定的返回类型?

这两个功能在以下两个方框中:

static public int GetNumberFromUser(string Info)
{
    int TheDesiredNumber;

    while (true)
    {
        Console.Write("Please type " + Info + " : ");

        if (int.TryParse(Console.ReadLine(), out TheDesiredNumber))
        {
            Console.ForegroundColor = ConsoleColor.Green;
            Console.WriteLine(" - " + Info + " is set to " + TheDesiredNumber.ToString() + "!");
            Console.ForegroundColor = ConsoleColor.Gray;
            return TheDesiredNumber;
        }

        WrongInput(" - Invalid input!");
    }
}

static public double GetNumberFromUser(string Info)
{
    double TheDesiredNumber;

    while (true)
    {
        Console.Write("Please type " + Info + " : ");

        if (double.TryParse(Console.ReadLine(), out TheDesiredNumber))
        {
            Console.ForegroundColor = ConsoleColor.Green;
            Console.WriteLine(" - " + Info + " is set to " + TheDesiredNumber.ToString() + "!");
            Console.ForegroundColor = ConsoleColor.Gray;
            return TheDesiredNumber;
        }

        WrongInput(" - Invalid input!");
    }
}

4 个答案:

答案 0 :(得分:3)

你的问题的答案是肯定的......这是可能的。您的问题表明唯一的区别是返回类型(使用泛型处理),但这不是真的。另一个区别是TryParse函数也依赖于一个类型。因此,您需要一种方法来指定一个类型安全的TryParse函数,该函数由委托处理。

因此,使用泛型和委托的组合。指定要在括号中使用的类型。定义一个名为TryParse的委托,它也是键入的。然后,您可以传递执行解析的函数。我已经为控制台应用程序提供了一个完整的示例。如果你看一下main,那么这是一个简单的函数调用,你传递正确的TryParse函数。这种方法很酷的是你可以使用任何类型的TryParse。如果您创建自己的有理类或分数类,则可以为您的类传递函数。

using System;

namespace DelegateSample
{
    public class Program
    {
        // delegate to handle tryparse
        public delegate bool TryParse<T>(string txt, out T desiredNumber);

        // generic function that will get a number from a user and utilize the existing TryParse for the specified type
        public static T GetNumberFromUser<T>(string info, TryParse<T> tryParseFunction)
        {
            T TheDesiredNumber;

            while (true)
            {
                Console.Write("Please type " + info + " : ");

                string input = Console.ReadLine();

                // use the delegate here to run the TryParse, which is passed in
                if (tryParseFunction(input, out TheDesiredNumber))
                {
                    Console.ForegroundColor = ConsoleColor.Green;
                    Console.WriteLine(" - " + info + " is set to " + TheDesiredNumber.ToString() + "!");
                    Console.ForegroundColor = ConsoleColor.Gray;
                    return TheDesiredNumber;
                }

                // WrongInput isn't defined, this should suffice for the sample
                Console.WriteLine(input + " - Invalid input!");
            }
        }

        public static void Main(string[] args)
        {
            // this can be used for any function which implements the TryParse function which matches the delegate
            // it is a simple function call.  Specify the type between the brackets, and then pass the function in that
            // does the TryParse.  You could even write your own TryParse for your own classes, if needed.
            int iVal = GetNumberFromUser<int>("integer", int.TryParse);
            double dVal = GetNumberFromUser<double>("double", double.TryParse);
            float fVal = GetNumberFromUser<float>("float", float.TryParse);
        }
    }
}

答案 1 :(得分:0)

这有效,但它让我感到畏缩。太糟糕了C#并不允许泛型为T指定多个可接受的类型。

static public T GetNumberFromUser<T>(string Info)
{
    Type t = typeof(T);
    if (t.Equals(typeof(int)) || t.Equals(typeof(double)))
        return (T)GetNumberFromUser2<T>(Info);
    throw new ArgumentException(string.Format("GetNumberFromUser<T> only works with int and double. Type '{0}' is not valid.", t.Name));
}
static private object GetNumberFromUser2<T>(string Info)
{
    object TheDesiredNumber = null;
    Type t = typeof(T);
    while (true)
    {
        Console.Write("Please type " + Info + " : ");

        if (t.Equals(typeof(int)))
        {
            int TheDesiredInt;
            if (int.TryParse(Console.ReadLine(), out TheDesiredInt))
            {
                TheDesiredNumber = TheDesiredInt;
            }
        }
        else if (t.Equals(typeof(double)))
        {
            double TheDesiredDouble;
            if (double.TryParse(Console.ReadLine(), out TheDesiredDouble))
            {
                TheDesiredNumber = TheDesiredDouble;
            }
        }

        if (TheDesiredNumber != null)
        {
            Console.ForegroundColor = ConsoleColor.Green;
            Console.WriteLine(" - " + Info + " is set to " + TheDesiredNumber.ToString() + "!");
            Console.ForegroundColor = ConsoleColor.Gray;
            return TheDesiredNumber;
        }

        WrongInput(" - Invalid input!");
    }
}

答案 2 :(得分:-1)

使用out参数:

static public void GetNumberFromUser(string Info, out int number);
static public void GetNumberFromUser(string Info, out double number);

或使用不同的名称:

static public int GetIntFromUser(string Info);
static public double GetDoubleFromUser(string Info);

或将输出声明为object

static public object GetNumberFromUser(string Info);

或使用泛型:

static public T GetNumberFromUser<T>(string Info)
{
    // ...
    return (T)(object)TheDesiredNumber;
}

答案 3 :(得分:-1)

这可以使用泛型和扩展方法的一点帮助&amp;这里的反思就是一个例子:

public static class Extensions
{
    public static bool TryParse<T>(this string source, out T result)
        where T : struct
    {
        result = default(T);
        var method = typeof (T)
            .GetMethod("TryParse", new [] {typeof (string), typeof (T).MakeByRefType()});

        if(method == null) return false;

        bool isValid =  (bool)method
            .Invoke(null, new object[] {source, result});

        if (isValid) return true;

        return false;
    }
}

此通用TryParse允许我们在任何类型的 struct 上调用TryParse。然后我们可以推广GetNumberFromUser方法并得到如下结果:

public static T GetNumberFromUser<T>(string Info)
    where T : struct
{
    T TheDesiredNumber = default(T);

    while (true)
    {
        Console.Write("Please type " + Info + " : ");

        // this it the key point
        if (Console.ReadLine().TryParse<T>(out TheDesiredNumber)) 
        {
            Console.ForegroundColor = ConsoleColor.Green;
            Console.WriteLine(" - " + Info + " is set to " + TheDesiredNumber.ToString() + "!");
            Console.ForegroundColor = ConsoleColor.Gray;
            return TheDesiredNumber;
        }

        WrongInput(" - Invalid input!");
}

用法:

var result = GetNumberFromUser<int>("Integer");