Ayende @ Rahien

Hi!
My name is Oren Eini
Founder of Hibernating Rhinos LTD and RavenDB.
You can reach me by phone or email:

ayende@ayende.com

+972 52-548-6969

, @ Q c

Posts: 5,953 | Comments: 44,410

filter by tags archive

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

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

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

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

junior programmer

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

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

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

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

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

Can we make it call a service locator? :)

var x=new IFoo(); turns out to

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

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

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

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

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

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

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

Jason,

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

/Mats

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.

Comment preview

Comments have been closed on this topic.

FUTURE POSTS

No future posts left, oh my!

RECENT SERIES

  1. The RavenDB Comic Strip (3):
    28 May 2015 - Part III – High availability & sleeping soundly
  2. Special Offer (2):
    27 May 2015 - 29% discount for all our products
  3. RavenDB Sharding (3):
    22 May 2015 - Adding a new shard to an existing cluster, splitting the shard
  4. Challenge (45):
    28 Apr 2015 - What is the meaning of this change?
  5. Interview question (2):
    30 Mar 2015 - fix the index
View all series

Syndication

Main feed Feed Stats
Comments feed   Comments Feed Stats