在C#中,我需要能够定义一个方法,但让它返回一个或两个返回类型。当我尝试这样做时,编译器给了我一个错误,但为什么不知道我需要调用哪种方法呢?
int x = FunctionReturnsIntOrString();
为什么编译器会阻止我使用不同返回类型的两个函数?
答案 0 :(得分:26)
来自C# 3.0 language specification的第1.6.6节的最后一段:
方法的签名在声明方法的类中必须是唯一的。方法的签名包括方法的名称,类型参数的数量以及数量,修饰符和参数类型。方法的签名不包括返回类型。
在IL中,两种方法可能因返回类型而异,但在反射之外,没有办法调用只有返回类型的方法。
答案 1 :(得分:22)
虽然在这种特殊情况下可能很明显,但在许多情况下,这实际上并不明显。让我们以下面的API为例
class Bar {
public static int Foo();
public static string Foo();
}
编译器根本不可能知道在以下场景中调用哪个Foo
void Ambiguous() {
Bar.Foo();
object o = Bar.Foo();
Dog d = (Dog)(Bar.Foo());
var x = Bar.Foo();
Console.WriteLine(Bar.Foo());
}
这些只是一些快速样本。肯定存在更多人为的和邪恶的问题。
答案 2 :(得分:10)
您是否考虑过使用泛型来返回正确的类型。
public T SomeFunction<T>()
{
return T
}
int x = SomeFunction<int>();
string y = SomeFunction<string>();
注意:此代码尚未经过测试
答案 3 :(得分:9)
仅与返回值不同的函数不符合重载条件。
int x = FunctionReturnsIntOrString();
double y = FunctionReturnsIntOrString();
在上面的例子中,编译器可以识别正确的函数,但考虑到未指定返回值的情况,它是不明确的。
FunctionReturnsIntOrString(); //int version
FunctionReturnsIntOrString(); //double version
编译器无法解决重载方法。
答案 4 :(得分:4)
可以获得你在问题中展示的语法,但是为了达到目的,你必须投入相当多的聪明才智。
让我们更具体地设置问题。我认为,关键在于语法。我们想要这个:
int intValue = GetData();
string stringValue = GetData();
DateTime[] dateTimeArrayValue = GetData();
但是,我们不希望这样做:
double doubleValue = GetData();
DateTime? nullableDateTimeValue = GetData();
为了实现这一点,我们必须在GetData()
的返回值中使用中间对象,其定义如下:
public class Data
{
public int IntData { get; set; }
public string StringData { get; set; }
public DateTime[] DataTimeArrayData { get; set; }
public MultiReturnValueHelper<int, string, DateTime[]> GetData()
{
return new MultiReturnValueHelper<int, string, DateTime[]>(
this.IntData,
this.StringData,
this.DataTimeArrayData);
}
}
你的实施当然会有很大不同,但这样做会有所不同。现在让我们定义MultiReturnValueHelper
。
public class MultiReturnValueHelper<T1, T2, T3> : Tuple<T1, T2, T3>
{
internal MultiReturnValueHelper(T1 item1, T2 item2, T3 item3)
: base(item1, item2, item3)
{
}
public static implicit operator T1(MultiReturnValueHelper<T1, T2, T3> source)
{
return source.Item1;
}
public static implicit operator T2(MultiReturnValueHelper<T1, T2, T3> source)
{
return source.Item2;
}
public static implicit operator T3(MultiReturnValueHelper<T1, T2, T3> source)
{
return source.Item3;
}
}
对于通用案例,对T1
,T2
,T3
等重复此定义。
您还可以将返回值助手非常接近地绑定到返回它的类或方法,从而使您可以为索引器创建相同类型的效果,您可以在其中获取和分配一组离散类型。这就是我发现它最有用的地方。
另一个应用程序是启用如下语法:
data["Hello"] = "World";
data["infamy"] = new DateTime(1941, 12, 7);
data[42] = "Life, the universe, and everything";
完成此语法的确切机制留给读者练习。
对于这个问题的更通用的解决方案(我认为,与歧视的联合问题相同),请参阅my answer to that question。
答案 5 :(得分:3)
我想你想认真地重新考虑你在做什么以及如何做,但你可以做到这一点:
int i = FunctionReturnsIntOrString<int>();
string j = FunctionReturnsIntOrString<string>();
通过这样实现:
private T FunctionReturnsIntOrString<T>()
{
int val = 1;
if (typeof(T) == typeof(string) || typeof(T) == typeof(int))
{
return (T)(object)val;
}
else
{
throw new ArgumentException("or some other exception type");
}
}
但是有很多理由不这样做。
答案 6 :(得分:2)
返回类型不是方法签名的一部分,只是名称和参数类型。因此,您不能有两种方法只有返回类型不同。解决这个问题的一种方法是让你的方法返回一个对象,然后调用代码必须将它强制转换为int或string。
但是,最好创建两个不同的方法,或者创建一个从可以包含int或字符串的方法返回的类。
答案 7 :(得分:2)
因为有时它真的无法分辨它应该使用哪一个(你的例子可以,但并非所有情况都是那么明确):
void SomeMethod(int x) { ... }
void SomeMethod(string x) { ... }
在这种情况下,如果你调用SomeMethod(FunctionReturnsIntOrString())
编译器应该做什么?
答案 8 :(得分:1)
在C#中没有overridin返回类型,IL支持那种覆盖,但C#还没有...。
答案 9 :(得分:1)
您也不需要为被调用的方法赋值。例如:
int FunctionReturnsIntOrString() {return 0;}
string FunctionReturnsIntOrString() {return "some string";}
//some code
//...
int integer = FunctionReturnsIntOrString(); //It probably could have figured this one out
FunctionReturnsIntOrString(); //this is valid, which method would it call?