C# 方法重载返回值

C# 方法重载返回值,c#,overloading,C#,Overloading,在C#中,我需要能够定义一个方法,但让它返回一个或两个返回类型。当我尝试这样做时,编译器会给我一个错误,但是为什么它不够聪明,不知道我需要调用哪个方法呢 int x = FunctionReturnsIntOrString(); 为什么编译器会阻止我使用两个具有不同返回类型的函数?返回类型不是方法签名的一部分,而是名称和参数类型。因此,不能有两个只因返回类型不同而不同的方法。解决这个问题的一种方法是方法返回一个对象,然后调用代码必须将其转换为int或string 但是,最好创建两个不同的方法,

在C#中,我需要能够定义一个方法,但让它返回一个或两个返回类型。当我尝试这样做时,编译器会给我一个错误,但是为什么它不够聪明,不知道我需要调用哪个方法呢

int x = FunctionReturnsIntOrString();

为什么编译器会阻止我使用两个具有不同返回类型的函数?

返回类型不是方法签名的一部分,而是名称和参数类型。因此,不能有两个只因返回类型不同而不同的方法。解决这个问题的一种方法是方法返回一个对象,然后调用代码必须将其转换为int或string


但是,最好创建两个不同的方法,或者创建一个类从方法返回,该方法可以包含int或字符串。

让您思考一下如何使用泛型返回正确的类型

public T SomeFunction<T>()
{
    return T
}

int x = SomeFunction<int>();
string y = SomeFunction<string>();
public T SomeFunction()
{
返回T
}
int x=SomeFunction();
字符串y=SomeFunction();

注意:这段代码还没有在C中测试过

,没有重写返回类型,IL支持这种重写,但C还没有…因为有时它确实无法判断应该使用哪一种(您的示例可以,但并非所有情况都如此明确):


在此上下文中,如果调用
SomeMethod(FunctionReturnsIntOrString())
编译器应该做什么?

虽然在这个特定场景中这可能很明显,但在许多场景中这实际上并不明显。让我们以下面的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());
}

这些只是一些简单的样品。更人为和邪恶的问题肯定存在

仅与返回值不同的函数不符合重载条件

int x = FunctionReturnsIntOrString();
double y = FunctionReturnsIntOrString();

在上述情况下,编译器可以识别正确的函数,但是考虑没有指定返回值的情况,它是不明确的。

FunctionReturnsIntOrString();   //int version
FunctionReturnsIntOrString();   //double version

编译器无法在此处解析重载方法。

我认为您需要认真重新考虑您正在做什么以及如何做,但您可以这样做:

int i = FunctionReturnsIntOrString<int>();
string j = FunctionReturnsIntOrString<string>();
int i=functionreturnsintoString();
字符串j=函数ReturnsInToString();
通过这样实施:

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");
    }
}
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);
    }
}
private T函数返回到字符串()
{
int-val=1;
if(typeof(T)=typeof(string)| | typeof(T)==typeof(int))
{
返回(T)(对象)val;
}
其他的
{
抛出新的ArgumentException(“或其他异常类型”);
}
}

但是有很多理由不这么做。

从第1.6.6节的最后一段:


方法的签名在声明该方法的类中必须是唯一的。方法的签名包括方法的名称、类型参数的数量及其参数的数量、修饰符和类型。方法的签名不包括返回类型


在IL中,两种方法可能仅因返回类型不同而不同,但在反射之外,无法调用仅因返回类型不同而不同的方法。

您也不需要为被调用的方法赋值。例如:

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?

可以得到你在问题中展示的语法,但是你必须非常聪明才能达到目的

让我们把问题说得更具体一点。我认为这里的关键点是语法。我们希望:

int intValue = GetData();
string stringValue = GetData();
DateTime[] dateTimeArrayValue = GetData();
但是,我们不希望这样做:

double doubleValue = GetData();
DateTime? nullableDateTimeValue = GetData();
为了实现这一点,我们必须在
GetData()
的返回值中使用中间对象,其定义如下:

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");
    }
}
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);
    }
}
对一般情况下的
T1
T2
T3
等重复此定义

您还可以将返回值帮助器非常紧密地绑定到返回它的类或方法,从而使您能够为索引器创建相同的效果,您可以在索引器中获取并分配一组离散的类型。那是我发现它最有用的地方

另一个应用程序是启用如下语法:

data["Hello"] = "World";
data["infamy"] = new DateTime(1941, 12, 7);
data[42] = "Life, the universe, and everything";
完成此语法的精确机制留给读者作为练习


有关此问题的更通用的解决方案(我认为,这与判别联合问题相同),请参阅。

但在IL中,返回类型用于识别方法。。。使用ildasm,您可以在指定callvirt指令时看到指定的retrn类型。IL中的内容无关紧要-重要的是C#规范,特别是第3.6节,其中指出“方法的签名特别不包括返回类型”。请看右边——记住,MSIL中没有“重载解析”这类东西。在IL中,您必须始终明确地声明您正在调用的方法。C#中的情况并非如此。重载参数可能会出现同样的问题,C#编译器会向您发出警告。关于返回类型的警告有什么问题?请用C#描述这样一个带有重载参数的示例。原则上,C#编译器将允许在遇到歧义时生成错误消息。它不会只选一个就给你一个错误。@charlieday,我不相信C#编译器给出警告的能力是问题所在。我猜问题更多的是成本问题。这是一个价值有限的特性,在很多情况下它会彻底失败(参见我的示例)。由于低效益和低成本,此类功能通常被削减。不过,我不在C#团队工作,也不知道这是否曾在设计会议上出现过。老实说,我甚至不确定它在IL级别上是否合法。在IL级别上是合法的,但在IL级别上没有“过载解决”这样的事情,所以这就容易多了。在IL级别,您总是明确地声明要调用的方法。@dustin:它主要与null有关。假设你有两种方法