我在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!");
}
}
答案 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");