0

I have a class with a static method, like so:

public class Calculator
{
    public static decimal Calculate(decimal op1, decimal op2) => op1 * op2;
}

I add an instance method to that class which calls that static method:

public decimal Foo(decimal op1, decimal op2)
{
    return Calculate(op1, op2);
}

This compiles just fine. Now I add another instance method which calls that static method inside a local function:

public decimal Bar((decimal op1, decimal op2) pair)
{
    return Calculate();

    decimal Calculate()
    {
        return Calculate(pair.op1, pair.op2);
    }
}

This gives the compile error

CS1501 No overload for method 'Calculate' takes 2 arguments

If I change the call to return Calculator.Calculate(pair.op1, pair.op2) or give the local function a different name it compiles without error. Why?

  • 1
    Local methods (static or non-static) hide methods of the same name, hence the error. When you fully-qualify the name, it is no longer hidden because it doesn't have the same name (because it includes the class name). See https://stackoverflow.com/a/48579592/106159 – Matthew Watson Mar 13 '23 at 15:01
  • Also see https://github.com/dotnet/csharplang/discussions/2218 – Matthew Watson Mar 13 '23 at 15:07

2 Answers2

0

I believe that the problem is the nested Calculate() function having the same name as the static method Calculate(decimal, decimal). The compiler thinks that you want to recursively call the nested function and finds out that it does not accept two arguments.

I would suggest you use the class name anyway when calling a static method, as it belongs to the type itself rather than to a specific instance.

This question seems related: Static and Instance methods with the same name?

0

It's just because it's nested and loses reference to whether the intent is static or instance.

The moment you preface it with the class name you are telling it to call the static instance

Calculator.Calculate(pair.op1, pair.op2);

If you notice, even this works if you rename your enclosed Calculate method to anything else:

        public decimal Bar((decimal op1, decimal op2) pair)
    {
        return Calculate(pair.op1, pair.op2); 

        decimal aCalculate()
        {
            return Calculator.Calculate(pair.op1, pair.op2);
        } 
    }

It's actually kind of a matter of precedence of scope. In your Bar method, without the Calculate() method, it checks the inner most scope first. No method exists and so it expands scope. When you add a method of the same name in the local scope, the compiler puts more weight on the inner most reference first. So it then sees the Calculate method and tries to resolve the signature, but it can't.

Technically if we get right down to it, I think the compiler should actual realize or at least considering matching signatures in generational scope. There are probably complications that of which I'm not aware however.

    public class Calculator
{
    public static decimal Calculate(decimal op1, decimal op2) => op1 * op2;

    public decimal Foo(decimal op1, decimal op2)
    {
        return Calculate(op1, op2);
    }

    public decimal Bar((decimal op1, decimal op2) pair)
    {
        return Calculate();

        decimal Calculate()
        {
            return Calculator.Calculate(pair.op1, pair.op2);
        } 
    }
}
jrandomuser
  • 1,510
  • 19
  • 50