Saturday, 15 August 2009

Who says you can’t instantiate an interface?

(update update: the question has been raised: "should we use this in our code?" - and in answer: heck no! this is just a fun diversion around the edges of the C# spec; leave well alone...)

(update: I just realised that Jon Skeet mentioned this in passing here, too; I'll keep this here, as I think it is intriguing enough to warrant a more targeted post)

If I said that the following is valid C# (all the way back to v1), you might think I’ve been overdoing things:

interface IFoo
{
string Message {get;}
}
...
IFoo obj = new IFoo("abc");
Console.WriteLine(obj.Message);

But the funny thing is… this is actually legal! Or at least, it compiles and runs ;-p As you might expect, I’ve missed out some magic in the above ;-p

It turns out that there is a subtlety relating to how COM imports work… and it is possible to define against the interface a default concrete type. The C# compiler then interprets “new {InterfaceType}” as “new {DesignatedConcreteType}”.

Here’s the missing magic (including a concrete type):

class Foo : IFoo
{
readonly string name;
public Foo(string name)
{
this.name = name;
}
string IFoo.Message
{
get
{
return "Hello from " + name;
}
}
}
// these attributes make it work
// (the guid is purely random)
[ComImport, CoClass(typeof(Foo))]
[Guid("d60908eb-fd5a-4d3c-9392-8646fcd1edce")]
interface IFoo
{
string Message {get;}
}

(see footnote) I'm struggling to find a mention of it in the C# specification (3.0), though... indeed §7.5.10.1 says:

"The type of an object-creation-expression must be a class-type, a value-type or a type-parameter. The type cannot be an abstract class-type.
The optional argument-list (§7.4.1) is permitted only if the type is a class-type or a struct-type."

So a non-legal feature? I'll let you be the judge...

Footnote: Mehrdad has clarified that the fact that it is omitted from the specification is OK because §17.5 allows any of of attributes in the System.Runtime.InteropServices namespace to break all the rules ;-p