How can I guarantee that an interface and a class method parameters match without manually checking?

I recently noticed a bug due to a mismatched parameter order in the class to its interface parameter order. I felt that this should have been a compile error. I found out that Interfaces do not constrain the parameter names. So if you see my example below I have firstParameter and secondParameter reversed, I also have parameterOne and parameterTwo, both as valid builds. This may build just fine, but you will likely run into runtime errors.

On the other hand, it does require the order of the types of the parameters to match. So I thought perhaps I do not need to place the parameter names in the interface and just the value types, but that does not work and the interface would still need to provide a description of what the types are in terms of what a consumer would place there.

My Question Is there a way to guarantee at build time that a class matches the interface parameter names? I would prefer not to do this manually.

The reason this is important is even though the method variables cannot be setup to be used by the interface, someone consuming a service reference or other use of an interface would see the Interface parameters at the time of setup and that is the expected use of the parameters. If I cannot rely on a contract to be exact, what is the point of a contract in the first place?

interface IParameterTest
{
    void TwoStringParameters(string firstParameter, string secondParameter);

    void TwoStringParametersAndAnInt(string firstParameter, string secondParameter, int thirdParameter);
}

public class ParameterTest : IParameterTest
{
    //Builds and matches interface
    //public void TwoStringParameters(string firstParameter, string secondParameter)
    //{
    //  throw new NotImplementedException();
    //}

    //Builds and does not match interface
    //public void TwoStringParameters(string secondParameter, string firstParameter)
    //{
    //  throw new NotImplementedException();
    //}

    //Builds and does not match interface
    public void TwoStringParameters(string parameterOne, string parameterTwo)
    {
        throw new NotImplementedException();
    }

    //Builds and matches interface
    public void TwoStringParametersAndAnInt(string firstParameter, string secondParameter, int thirdParameter)
    {
        throw new NotImplementedException();
    }

    //Does not build or match interface
    //public void TwoStringParametersAndAnInt(int firstParameter, string secondParameter, string thirdParameter)
    //{
    //  throw new NotImplementedException();
    //}
}
Jon Skeet
people
quotationmark

Is there a way to guarantee at build time that a class matches the interface parameter names? I would prefer not to do this manually.

Not within the C# language. However:

  • You could write a unit test to check, reasonably easily. Not quite build time, but still early enough to catch errors before they're big problems.
  • You could write a Roslyn code diagnostic to flag it as an error (and even provide a code fix for it).

Of course, the unit test could be written via Roslyn as well, but you could do it fairly easily just using plain reflection.

It's not entirely clear from your question whether you've spotted the really nasty problem with parameter names being wrong, by the way - it's not just in terms of human readability, but it can significantly affect behaviour if you use named arguments. For example, suppose you have code like this:

public interface IFoo 
{
    void Foo(int x, int y);
}

public class FooImpl : IFoo
{
    public void Foo(int y, int x) { ... }
}

...
IFoo foo = new FooImpl();
foo.Foo(x: 10, y: 20); // Equivalent to foo.Foo(10, 20)

Now if someone decides to use var instead, the compile-time type of foo is changed, so suddenly the named arguments map to different parameters.

var foo = new FooImpl();
foo.Foo(x: 10, y: 20); // Equivalent to foo.Foo(20, 10)

Perfectly valid code... but with a different meaning to the previous code. There are other times that changing the compile-time type of a variable can affect things, but that's usually around overloading etc... this is in the simple case where there really is just one method.

people

See more on this question at Stackoverflow