C# Static interfaces
By Jérémie Chassaing on Wednesday, October 21, 2009, 14:46 - .Net Framework - Permalink
Read the latest post on the subject:
No DDD today, let’s talk a bit about our favorite language after a short night (I should really tell my neighbors that 3am is not the good time to move their furniture all around the flat).
You can find requests for static methods in interfaces all over the internet..
But there are good reasons not to.
According to Eric Lippert, the main reasons is the difference in inheritance between static methods and instance method du to the absence of shared slots between static methods.
Mixing both static methods and instance methods in interfaces would lead to a real nightmare when you try to understand what really happens.
But why does this question arise so often then ? What’s really needed ?
Static classes as type instances
Let’s take a simple class with both static and instance members :
class Sample
{
// static part
private static int count;
public static int Count { get { return count; } }
// instance part
private readonly string name;
public Sample(string name) { this.name = name; }
public void Method()
{
count++;
Console.WriteLine("Total count {0} incremented by {1}", count, name);
}
}
Here, Count is a static Property. Static part is different from instance part in that static part exist only once per type.
But we could see static part as being an object with reference is type name.
Why would these object not have interfaces ?
Let refactor this a bit :
public class Sample2
{
public sealed class Sample2Class
{
internal int count;
public int Count { get { return count; } }
}
public static readonly Sample2Class Class = new Sample2Class();
private readonly string name;
public Sample2(string name)
{
this.name = name;
}
public void Method()
{
Class.count++;
Console.WriteLine("Total count {0} incremented by {1}", Class.count, name);
}
}
Here, the only static member is Class, that acts as a singleton for the type. Note that I had to change the count modifier to internal. The behavior is not the same, but it’s conceptually equivalent.
We can make something less extreme :
public class Sample3
{
private static int count;
public static int Count { get { return count; } }
private readonly string name;
public static readonly Sample3Class Class = new Sample3Class();
public sealed class Sample3Class
{
public int Count { get { return Sample3.Count; } }
}
public Sample3(string name) { this.name = name; }
public void Method()
{
count++;
Console.WriteLine("Total count {0} incremented by {1}", count, name);
}
}
Here, we added only a proxy of public methods and properties on the singleton class.
We could define an interface that would be implemented by Sample3Class that would provide the missing slot concept that Eric Lipperts talk about.
We can also see here that there is no point mixing static and instance method in interface since inheritance rules differs.
Static Interface
Imagination at work. Let’s define static interface as we can define static classes :
public static interface ICountable
{
static int Count { get; }
}
and implement it on our sample :
public class Sample4 : ICountable
{
private static int count;
public static int Count { get { return count; } }
private readonly string name;
public Sample4(string name) { this.name = name; }
public void Method()
{
count++;
Console.WriteLine("Total count {0} incremented by {1}", count, name);
}
}
The C# compiler would be responsible for creating a singleton stub in the class. Since the goal is to provide a function table, this could also be handled at a lower level by the CLI.
Now, we can have interesting language extensions.
Static member access in generics
Let see it in action :
public static bool IsInstanciated<T>() where T: ICountable
{
return T.Count != 0;
}
There is no ambiguity when using this method since values of parameter T are known at compilation time. The C# compiler could replace the static call with a interface call on the proxy. On a CLI version, the JIT compiler could resolve it once and for all and emit a static call. Use of a child type whose parent type implements the interface should not be allowed, the compiler could report this.
This could be combined with an extension method syntax to provide extension methods on types :
public static bool IsInstanciated(static ICountable type)
{
return type.Count != 0;
}
This one is a bit twisted, and I would gracefully admit changes in the syntax, but the point is that it would enable on type/classes the same kind of thing that Linq offers with interfaces : put the minimum set of methods in interface, then add lots of features around interface with extension methods.
Back to reality
Ok, I should sleep at night, but who knows, it’s perhaps useful.
If anyone sees other applications… just drop a comment.
Comments
Maybe I totally missed the article point, but the whole thing still remains unclear to me :)
How can this work:
var count = ICountable.Count;
@romain>It would not work because there is no point to do it. You need a concrete Type to call Count on it. like Sample3.
But it gives a common contract (that defines slots) to static parts of classes for generic methods or extension methods. Of course the call on a static interface method would be resolved to a call on the corresponding static method on the concrete class.
@romain> For instance with the extension method, you could write Sample4.IsInstanciated() and IsInstanciated would be implemented in another static class. the extenstion method would appear on any type implementing the static interface ICountable (even classes from the BCL).
I tried this and it fails when I try to declare a static interface... apparently interfaces are not allowed to be static, or am I missing something?
@Tim> outch, I should have put a 'language evolution request' sign on top of post !
thank for information nice artical site
I tried solving this using a static class....
public static class IFilterable<T>
{
}
public abstract class BaseDataClass : IEditableObject
{
}
public partial class SomeDataClass : BaseDataClass, IFormattable
{
static Venue() { IFilterable<Venue>.Filter = Filter; }public static IQueryable Filter(IQueryable qt, string s) { // ... } public int Field1 { get; set; }; public string Field2 { get; set; }; //....}
The only downside of this is, that you have to create at least one object to get the static constructor called. But in this example, there wouldn't be anything to filter if there were no objects.
// Interface we need to make static
public interface IInterface
{
SomeContext Get { get; }
double CalcSum(double a, double b);
}
// static class that acts as "Static Interface"
public static class IStaticInterface
{
private static IInterface _context;
static IStaticInterface()
{
//binder - IoC. Or you could use Factory - doesn't matter
_context = binder.GetDefaultContext();
}
// But if you need to change behaviour you can easily change it with replacing your interface
public static void SetContext(IInterface context)
{
_context = context;
}
// Methods that provide behaviour of your interface
public static SomeContext Get
{
get
{
return _context.Get;
}
}
public static double CalcSum(double a, double b)
{
return _context.CalcSum(a, b);
}
}
I agree that a little code doubling, but i guess you could easy write T4 transformer that would create it.
Heh, why not just use the singleton pattern?
public interface IGlobalThing
{
string Name {get;set;}}
public class GlobalThing : IGlobalThing
{
private string _Name; public string Name { get { return Instance._Name; } set { Instance._Name = value; } }private GlobalThing{}}
Well, what about operators in static interfaces?
I mean
1) why static interfaces can be applicable for static members only?
2) it would be nice to declare a set of operators in a static interface and add a constraint to generic class.
E g. what about this:
public static interface INumericWraper<T1>
{
public static T1 operator+(T1 left, T1 right); public static T1 operator-(T1 left, T1 right); public static T1 operator*(T1 left, T1 right); public static T1 operator/(T1 left, T1 right); public static T1 Zero { get; }}
public static class EnumerableTools
{
public static T Sum<T>(this IEnumerable<T> items) where T: INumericWraper<T> { var r = T.Zero; foreach(var i in items) { r = r + i; } return r; }}
It would be nice to have things like that. And i guess it will be enough to process this syntax sugar at compile time.
@ferpootoo
Singleton, lol? It doesn't solve anything.
I give you type T. Try to give me T.Instance.
Interfaces are contracts for unknown types. You cannot define a singleton contract preciously because C# doesn't support statics in interfaces.
@Romain Verdier
>How can this work: var count = ICountable.Count;
Why is this stupid question always popping out?
Why don't you ask the same about regular interface members?
I.e. "How can this work: var count = IList.Count; ?" Isn't the question stupid?
@ferpootoo
Singleton, lol? It doesn't solve anything.
I give you type T. Try to give me T.Instance.
Interfaces are contracts for unknown types. You cannot define a singleton contract preciously because C# doesn't support statics in interfaces.
@Romain Verdier
>How can this work: var count = ICountable.Count;
Why is this stupid question always popping out?
Why don't you ask the same about regular interface members?
I.e. "How can this work: var count = IList.Count; ?" Isn't the question stupid?