C# – Interface extension method returning the interface type in C#

cextension-methodinterfaces

Programming against interfaces is an often-heard good practice in software development. Together with extension methods, this provides a great functionality. However, in C#, there are limitations to that. Let's declare a simple interface for a 3D-Point:

public interface IPoint3D
{
  double X { get; }
  double Y { get; }
  double Z { get; }
}

I can add extension methods for this point in a static class, for example:

public static class Point3DExtensions
{
  public static double SumOfCoordinates(this IPoint3D point)
  {
    return point.X + point.Y + point.Z;
  }
}

However, what I can not code is functionality which returns an instance of the interface itself, like for example:

public static class Point3DExtensions
{
  public static IPoint3D Add(this IPoint3D point1, IPoint3D point2)
  {
    return new IPoint3D(point1.X + point2.X, point1.Y + point2.Y, point1.Z + point2.Z);
  }
}

The problem here is the part new IPoint3D, because I can't create an instance of an interface (it's just a contract, not an implementation).

As a workaround, I'd see two possibilites:

In the same assembly as the interface, create an internal class implementing the interface, for example:

internal class SimplePoint : IPoint3D
{
  public double X { get; }
  public double Y { get; }
  public double Z { get; }

  public SimplePoint(double x, double y, double z)
  {
    this.X = x;
    this.Y = y;
    this.Z = z;
  }
}

This class won't be seen from outside the assembly, but now, my extension method Add can still have IPoint3D as return type, but actually return an instance of SimplePoint. Noone from outside of the assembly will be able to cast the returned instance to SimplePoint, and doesn't need to.

The second option would be to add something like a Create-Method to the interface:

IPoint3D Create(double x, double y, double z);

However, this method is not static, so I would have to invoke it from any instance of IPoint3D, which is kind of weird, and I don't always have such an instance. The problem here is that static methods are not allowed for interfaces in C#. If they were, one could simply add static IPoint3D Create(double x, double y, double z); or even something like new(double x, double y, double z); (for a constructor) to the interface, and use that for object creation.

Now, the actual questions:

  • Am I trying to misuse interfaces here?
  • Did I miss any possibility to get the desired behaviour?
  • Which languages would offer this desired functionality?

Side Note: What I would like to have is e.g. an extension method for classes implementing an interface ICircle3D, which can calculate a number of points IPoint3D on those circles.

Best Answer

I doubt that an interface like IPoint3D brings you more benefits than trouble, so here my suggestion: create a concrete, immutable (so also sealed) class Point3D instead. When using interfaces, the geometric point/vector operations can only be implemented in a fashion where the underlying type information gets lost, but that is not a problem of the programming language, but a problem of the domain.

The reason for this becomes clearer when you try to make two different implementations of that interface, lets say an AutocadPoint3D (representing a point in an autocad CAD model, with lots of additional data like tags, color, layer etc.) and a GoogleEarthPoint3D (representing a coordinate in an KML model). Now try to add points of those two classes by a method like

   IPoint3D Add(IPoint3D point1, IPoint3D point2)

So what should be the underlying type of the result be? A new AutocadPoint3D, a GoogleEarthPoint3D, or something different (like your SimplePoint)? The only thing which probably makes sense would probably be the SimplePoint, because it is something like the "smallest common denominator" of all 3D points. Moreover, IPoint3D cannot be used to force sealed implementations, so code which relies on IPoint3D cannot be sure the underlying type is always immutable. This might suffer from unexpected side effects when the implementer of the interface is not very careful.

Think about the reason for what purpose you typically use interfaces. The most frequent purpose is probably dependency injection, especially for unit testing. But it seldom makes sense to mock out a value object like Point3D. Imagine you need to test a class which needs an IPoint3D, you would probably inject a SimplePoint object with some predefined values as test data - but then you could also use a SimplePoint directly and save the interface. So the interface only adds "noise" to your code, with no real benefit.