Ayende @ Rahien

It's a girl

Instantiating interfaces

How do you make this code legal?

var foo = new IFoo(1);

And yes, IFoo is an interfacae.

The answer is quite simple, actually. It was there since C# 1.0, I am told, and I just stumbled upon it. Take a look at this code:

class Program
{
	static void Main(string[] args)
	{
		var foo = new IFoo(1);
		foo.Do();
	}
}

[
	ComImport, 
	Guid("C906C002-B214-40d7-8941-F223868B39A5"), 
	CoClass(typeof(FooImpl))
]
public interface IFoo
{
	void Do();
}

public class FooImpl : IFoo
{
	private readonly int i;

	public FooImpl(int i)
	{
		this.i = i;
	}

	public void Do()
	{
		Console.WriteLine(i);	
	}
}

We have an interface, and we specify the co class that implements it and is the default implementation. The rest is just required to make the compiler happy about it.

What it means, in turn, is that you can instantiate an interface and have a default implementation selected. You can even use constructor parameters. It has quite a lot of implications, if you think about it right.

Not sure it is a wise feature to use, but it is certainly an interesting tidbit.

Comments

Bertrand Le Roy
08/15/2009 12:39 AM by
Bertrand Le Roy

Does it mean that you're going through COM interop just to do the instantiation? What makes that better than the alternatives?

Ayende Rahien
08/15/2009 01:28 AM by
Ayende Rahien

Bertrand,

The generated IL is:

var foo = new FooImpl(1);

In other words, this is purely compiler magic and does nothing at all with COM

Bertrand Le Roy
08/15/2009 05:52 AM by
Bertrand Le Roy

Nice. Too bad you need the COM attribute goop. Interesting tip nevertheless.

junior programmer
08/15/2009 06:56 AM by
junior programmer

does this mean we can use it for simple IoC/DI?

Ayende Rahien
08/15/2009 07:07 AM by
Ayende Rahien

Nope, because it is a one to one association and it happen at compilation time.

You can create the abstraction line, but you can't do much with it except replace the destination class on compilation

Mark Seemann
08/15/2009 07:27 AM by
Mark Seemann

It's interesting that this can be done, but as far as I can see, this is conceptually similar to people doing DI and overloading their constructors with default dependencies.

You recently wrote about that here: ayende.com/.../reviewing-nerddinner.aspx
calling it a 'bastard child', and I can only agree.

In other words: Nothing to see here, please move along :)

Eugene Burmako
08/15/2009 07:45 AM by
Eugene Burmako

I remember Eric Lippert posted similar stuff: "how is it that Foo foo = new Foo(); can cause a runtime conversion failure? And how is it that Bar bar = (Bar)(new Baz()); can succeed even if there is no user-defined conversion or built-in implicit conversion between Baz and Bar?"

So the second question is answered by Ayende, but the first one is still open. Don't immediately go to the link I provide below if you don't know the answer. Think a bit - it's almost on the surface in the context of this discussion =)

The promised link to Eric Lippert's post: blogs.msdn.com/.../...ersions-in-c-part-three.aspx

liviu
08/15/2009 08:08 AM by
liviu

What if Foo would be just a wrapper class araound an IFoo that is resolved using an DI container.

The advantage would be that i don't have to say:

XXXFactory.Create <ifoo() which is ugly...

but simply:

new IFoo() which is nicer, even if it hides the DI stuff...

Tuna Toksoz
08/15/2009 08:19 AM by
Tuna Toksoz

Can we make it call a service locator? :)

var x=new IFoo(); turns out to

var x=container.Resolve <ifoo() :)

Thomas Eyde
08/15/2009 09:04 AM by
Thomas Eyde

My guess is it's in there because of VB.NET. Or to make COM libraries easier to use. Classic VB hid all COM nastiness from us. When we declared a class CPerson, we also had an interface CPerson. Or so we thought. Our C++ friends using our VB made libraries could tell otherwise.

Bruce Boughton
08/15/2009 04:33 PM by
Bruce Boughton

I wonder if this it is possible to define a co-class FooImpl that loads an IFoo using dependency injection and then passes all IFoo calls through to it:

public class FooImpl : IFoo

{

  private readonly IFoo foo;


  public FooImpl()

  {

       this.foo = ServiceLocator.Current.GetInstance

<ifoo();

  }


 public void Do() { this.foo.Do(); }

}

Not sure what the use of this is, but it's interesting nonetheless. You'd have to define a co-class with each interface, but then you can do new IFoo() and use DI to load the instance at run time.

Bruce Boughton
08/15/2009 04:34 PM by
Bruce Boughton

Of course I meant: ServiceLocator.Current.GetInstance();

Stephen
08/15/2009 05:12 PM by
Stephen

I read this the other day, I don't think theres anything really interesting you can do with it, its purely there to make certain com interop neater (as the example was office I think).

RichB
08/16/2009 08:18 AM by
RichB

Do you know if this still works if the assembly is assembly:ComVisible(false)?

I suspect that as you say it's a compiler feature, you don't need the types to be registered anywhere for it to work.

Jason Y
08/18/2009 12:33 PM by
Jason Y

Is there any reason not to have the following in the same module?:

interface IFoo {

AMethod();

}

class TypicalFoo {

AMethod() {...}

}

Though you don't get a truly default Foo, you can document it as the one to fall back on "by default" so that it can be used as the default.

Is this a common pattern? I find myself doing it all the time.

Mats Helander
08/18/2009 12:47 PM by
Mats Helander

Jason,

That's what I think (and do) too, but apparently we're using the "bastard child" (of IoC) approach ;-)

/Mats

Justin Chase
08/29/2009 05:07 PM by
Justin Chase

We use this a little at work for instantiating certain COM objects. It's useful when you have a guid of a type but not a type library. You create the interface to match the signature of the type (or just the parts you care about) and then you can access that object strongly typed. I believe this is what the interop assemblies do when you add a reference to a COM assembly also.

Comments have been closed on this topic.