C# static interface or lack thereof

Started by
4 comments, last by jpetrie 9 years, 4 months ago

So I've found myself in a situation in which I either want to add a static member to an interface or create a static interface for my class to implement. Research has shown that this isn't a thing you can do in C# because it violates the concept of OOP. The problem I'm having is trying to find a replacement.

I have a generic data structure that I'm trying to turn into bytes to send/receive. The data structure is written and works with the generic type T, but now I am trying to add the construction/destruction from bytes. I looked into generic interfaces and came up with something like


public class HeirTree<T> where T : IEdible<T>
    { /*implementation*/ }


public interface IEdible<T>
    {
        byte[] GetBytes();
    }

public struct RobotPartPair : IEdible<RobotPartPair>
{ /*implements GetBytes*/}

This guarantees that whatever T is, I can call GetBytes on it. Now I want to create a FromBytes, but it only makes sense that it should be a constructor or a static method that returns the object. I see how this violates OOP because IEdible is not a concrete class and could be any inheriting class, but the fact that I'm using a generic T and that T will always be a concrete class should work around that. What would be the right solution here?

Ideally the entire HeirTree class has a method GetAsBytes() that returns the tree and all items inside it as an array of bytes, then has a static FromBytes or a constructor taking a byte array that can reverse an array of bytes into a tree.

Also every node in the tree is also a tree.

Advertisement

The only way that I've been able to work around this is with an abstract base class:


public abstract class EdibleBase<T>
where T : EdibleBase<T>, new()
{
    public abstract byte[] GetBytes();
    protected abstract void LoadFromBytes(byte[] bytes);

    public static T FromBytes(byte[] bytes)
    {
        var output = new T();
        output.LoadFromBytes(bytes);
        return output;
    }
}

Though honestly, since it's using an abstract base class it would probably be more efficient to have a protected (or public) constructor that takes a byte array and uses that in the call rather than an empty constructor and then calling a method. In the end, the constructor is really the easiest option; any reason you're avoiding using a constructor?


Now I want to create a FromBytes, but it only makes sense that it should be a constructor or a static method that returns the object.

What's wrong with making it a public method? If it's semantics, change the name.

any reason you're avoiding using a constructor?

I'm not avoiding a constructor, it just suffered the same fate as the static method in that you can't make one in the interface to force the inheriting classes to have one.

There are at least two solutions immediately available to you, the first one is the use abstract base classes as mentioned above, the other one is to use reflection to work around your problem. But perhaps we can better understand your problem if you give us an example of how the methods you describe would be used. Can you show how you would implement the hypothetical FromBytes() static method of your HeirTree, assuming classes implementing IEdible<T> did have a FromBytes() static method as well?

In any case, interface constructors and interface static methods make very little sense, for reasons that are already explained all over the internet. That is not to say that the underlying concept is meaningless, just that interfaces are not the right way to implement it. In fact, I think attributes would be an excellent place to document and enforce contracts such as (for instance) "should have a constructor that takes a byte array and instantiates the object from it" but unfortunately I don't think C# attributes can perform custom compile-time checks, which defeats the point (if you don't want compile-time checking then you can already do basically anything you want via reflection, but giving up compile-time safety is often far too high a price to pay).

“If I understand the standard right it is legal and safe to do this but the resulting value could be anything.”

Ideally the entire HeirTree class has a method GetAsBytes() that returns the tree and all items inside it as an array of bytes, then has a static FromBytes or a constructor taking a byte array that can reverse an array of bytes into a tree.

Often when you find yourself wanting to be able to enforce that implementation of some interface carry with it implementation of some static method, you can instead move the static methods to a complementary interface where that can be implemented as methods.
For example, in your case it sounds like you're dealing with serialization of your data. You can fairly easily move the "FromBytes" and "GetBytes" methods to a serializer interface. This can help increase the encapsulation of your primary interfaces, and also continue to hold your class's more firmly to the single-responsibility principle.
Incidentally, it's not that "static interfaces" violate any concept of OO design or engineering. It's that they don't make sense in languages that implement OO capability the way C# does. Calling methods on interfaces in C# means you have a reference to the object that implements the interface, which can be used to evaluate the runtime type of that object and select the appropriate interface implementation. If you don't have that instance, you don't have any way to evaluate the runtime type of a call like "ISomeInterface.SomeStaticMethod" without explicitly naming the implementation type in code (which means you could have just called it directly) or with introducing some other construct to the language that carries around a runtime type without actually be an instance of any object.

This topic is closed to new replies.

Advertisement