Roslyn: C# - Static and Instance members with the same signature should be valid.

Created on 26 Dec 2016  路  7Comments  路  Source: dotnet/roslyn

BACKGROUND:
I am working on a math library involving vectors. We want to have a method that creates vectors or creates a normalized vector. For example:

//Create's a standard vector
public static Vector CreateVector {...}

//Creates a vector normalized on the THIS vector.
public Vector CreateVector { ...}

However, I can't do this because C# does not allow me to have static and instance methods with the same signature.

Version Used:
Visual Studio 2015

Steps to Reproduce:
Put this code into the IDE:
````
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication3 {
class Program {
static void Main(string[] args) {
//This should work
var Method1 = Foo.DoSomething();

        var Method2 = (new Foo()).DoSomething();
    }
}

public class Foo {
    //Method 1
    public static object DoSomething() {
        return new object();
    }

    //Method 2
    public object DoSomething() {
        return new object();
    }

    public object ThisShouldNotWork() {
        //This call should be ambiguous because the static and non-static are in scope.
        //I should be able to disambiguate this by prefixing This or the TypeName.
        return DoSomething();
    }

    public static object ThisShouldWork() {
        //Only the static member is accessisble.  This should work.
        return DoSomething();
    }

}

}
````

Expected Behavior:
It should compile and work.

Actual Behavior:
I get the following errors:

Type 'Foo' already defines a member called 'DoSomething' with the same parameter types

The call is ambiguous between the following methods or properties: 'Foo.DoSomething()' and 'Foo.DoSomething()'

Area-Language Design Discussion Language-C#

Most helpful comment

The static method can be qualified by namespace (or global::) and the instance method qualified by this.:

c# var mFromStatic = global::Foo.M(); var mFromInstance = this.Foo.M();

Overload resolution could either leave this situation in error (requiring a qualifier) or prefer one approach.

All 7 comments

I believe that this limitation comes from IL/CLR and not C#. Trying to produce an assembly from IL containing an instance method and a static method with the same signature both fails to load as an invalid program and causes the verifying to crash with a stack overflow.

@HaloFour It's allowed because static/instance is part of the method signature.

What IL did you use to crash peverify? :)

@0xd4d

I went the lazy route starting with a simple C# program and adding a parameter. It's possible that I messed something up:

https://gist.github.com/HaloFour/9331a773977cea2feb6c906f49f85e1c

@HaloFour Looks like you forgot to update MaxStack from 2 to 3, see https://gist.github.com/HaloFour/9331a773977cea2feb6c906f49f85e1c#file-program-il-L67

@0xd4d Well that'll do it.

I'm not aware of any CLS guideline against overloading a method strictly based on whether its static or instance. However, I do know that languages like VB.NET do permit resolving static members through an instance.

Would this not just cause an ambiguity in other cases?

public class Foo
{
    public int M()
    {
        return 0;
    }

    public static int M()
    {
        return 1;
    }
}

public class C
{
    public Foo Foo { get; } //legal syntax

    void X()
    {
        var n = Foo.M(); //did I mean to invoke the static method, or the instance one with implicit `this.`?
    }
}

Better to catch this early and warn the developer writing that code than to pass the problem down to code that consumes it later.

The static method can be qualified by namespace (or global::) and the instance method qualified by this.:

c# var mFromStatic = global::Foo.M(); var mFromInstance = this.Foo.M();

Overload resolution could either leave this situation in error (requiring a qualifier) or prefer one approach.

Was this page helpful?
0 / 5 - 0 ratings