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
Does it mean that you're going through COM interop just to do the instantiation? What makes that better than the alternatives?
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
Nice. Too bad you need the COM attribute goop. Interesting tip nevertheless.
does this mean we can use it for simple IoC/DI?
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
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 :)
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
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...
Can we make it call a service locator? :)
var x=new IFoo(); turns out to
var x=container.Resolve <ifoo() :)
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.
Tuna,
No, I checked
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
{
<ifoo();
}
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.
Of course I meant: ServiceLocator.Current.GetInstance<IFoo>();
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).
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.
RichB,
Yes, it should
Is there any reason not to have the following in the same module?:
interface IFoo {
}
class TypicalFoo {
}
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.
Jason,
That's what I think (and do) too, but apparently we're using the "bastard child" (of IoC) approach ;-)
/Mats
Now look what you did: stackoverflow.com/.../newing-up-interfaces
I just knew it was going to happen :/
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