函数调用决定函数';s返回类型
本文关键字:返回类型 决定 函数 函数调用 | 更新日期: 2023-09-27 17:58:59
我在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!");
}
}
您的问题的答案是肯定的。。。这是可能的。您的问题表明,唯一的区别是返回类型(用泛型处理),但事实并非如此。另一个区别是TryParse函数也依赖于一个类型。因此,您需要一种方法来指定类型安全的TryParse函数,该函数由委托处理。
因此,使用泛型和委托的组合。指定要在方括号之间使用的类型。定义一个名为TryParse的委托,该委托也是类型化的。然后,您可以传递进行解析的函数。我已经包含了一个控制台应用程序的完整示例。如果您查看main,那么它是一个简单的函数调用,您可以在其中传递正确的TryParse函数。这个方法的酷之处在于,您可以对任何类型使用TryParse。如果创建自己的rational类或fraction类,则可以为类传递函数。
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);
}
}
}
这很有效,但让我感到尴尬。糟糕的是,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!");
}
}
使用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;
}
使用泛型和一些扩展方法&反射是一个例子:
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
允许我们在任何类型的结构上调用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");