-1

This is a general design question. We often use interfaces to decouple components, write to an interface not an implementation etc. Sometimes interfaces are used w/ a basic injection technique, such as,

interface IMyInterface
{
    void DoSomething();
}

static class IMyInterfaceFactory
{
    public static IMyInterface GetInstance()
    {
        return new MyInterfaceInstance();
    }
}

class IMyInterfaceConsumer
{
    IMyInterface mInterface;

    public IMyInterfaceConsumer()
    {
        this.mInterface = IMyInterfaceFactory.GetInstance();
    }

    public void UseTheInterface()
    {
        this.mInterface.DoSomething();
    }
}

My question is about using the var keyword instead. Not even using a true C# interface, but still creating an 'interface', in the design sense,

static class IMyInterfaceFactory
{
    // of course, this doesnt need to be a single instance
    static MyInterfaceInstance mSingleInstance; 

    // no longer programming to the interface, just returning the instance
    public static MyInterfaceInstance GetInstance()
    {
        // null coalesce
        return mSingleInstance ?? (mSingleInstance = new MyInterfaceInstance());
    }
}

class IMyInterfaceConsumer
{
    public void UseTheInterface()
    {
        // shorthand way, could also omit var, too 
        var myInterface = IMyInterfaceFactory.GetInstance();
        myInterface.DoSomething();
    }
}

This way I still only need to change the factory once, and as long as whatever instance it returns supports the methods that need to be consumed, it will work. The advantage however is that the producing and consuming objects dont need to even know about any explicit interface, none exists. It could also cleanly support an interface with more than just a couple methods (prevent bloated interface declarations).

One obvious downside is that everytime you want to consume a method from the 'interface', the factory will potentially have to re-instantiate the class, unless there is a single instance cached (as above) or some memoization technique used.

Pros/cons of this approach? Is this a common practice?

Sean Thoman
  • 7,429
  • 6
  • 56
  • 103
  • Its not just about the var keyword, its the way its used in conjunction with the factory. – Sean Thoman Sep 19 '12 at 21:10
  • `// shorthand way, could also omit var, too ` -- how? – Austin Salonen Sep 19 '12 at 21:14
  • IMyInterfaceFactory.GetInstance().DoSomething(); – Sean Thoman Sep 19 '12 at 21:15
  • By "to be consumed, it will work", you mean: "it will compile", right? I get the impression there is a confusion between `var` and `dynamic` here. – Austin Salonen Sep 19 '12 at 21:50
  • Yes I mean it will compile, good point. But thats even true of a traditional C# interface -- it just ensures things will compile as long as types implement (note: syntactically) the methods of the interface they inherit. I've removed dynamic from the title to avoid this confusion. – Sean Thoman Sep 19 '12 at 21:53

2 Answers2

5

There is nothing dynamic or loose about the var keyword. It triggers static type inference at compile time.

Your second piece of code behaves identically to

public void UseTheInterface()
{
    // shorthand way, could also omit var, too 
    MyInterfaceInstance myInterface = IMyInterfaceFactory.GetInstance();
    myInterface.DoSomething();
}

The factory function is still strongly typed. In fact, by removing the interface, you've made consumer code much more tightly coupled.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • You understand that you could change MyInterfaceInstance to any other type, as long as it supports DoSomething(), right? That is the point, the point isnt for the factory to be loosely typed. – Sean Thoman Sep 19 '12 at 21:10
1

Var keyword is still technically strongly typed, so your code does know what class/interface it is. If you planned on dumping it into an object then we are saying that the rest of your code has no clue what is coming out of that factory. I wouldn't suggest that though since that causes you to cast that object to utilize anything in it.

I'm not sure where you are trying to go with the "prevent bloated interface declarations" but you could do polymorphism through extending a base class or an abstract class as well. That would make it so any code that is common between the child classes could be left alone and any specific code (methods or properties) for each child class could be overridden.

If you are looking to change out the interface all together you will need to implement an interface in the interface, see this post. So you will basically have interface A only have the method DoStuff() and other interfaces that inherit from this interface could be used polymorphically like you are describing.

interface A
{

DoStuff();
}

interface B : A
{
DoSomethingElse();
}

class C : B
{

DoStuff(){}
DoSomethingElse(){}
}

By the way, your "single instance cached" code above is close to something called a singleton pattern.

Community
  • 1
  • 1
iMortalitySX
  • 1,478
  • 1
  • 9
  • 23
  • You have to understand that this is a syntax/semantics thing -- using 'var' means that the consuming classes don't need to know the name of the type that supports DoSomething() -- yes they will infer the type, but it wont matter, as long as that type has the DoSomething() method. You could move that class anywhere where a factory provides a different implementation, or just change the factory if you want to change the behavior of all classes consuming it. – Sean Thoman Sep 19 '12 at 21:29
  • @SeanThoman Var does not allow for consuming classes to not know the name of the instance. When you declar var, you must instanciate something, with a name, so you are giving it a name, even if it is an instance somewhere else, you are still giving it a name. Additionally, you will still need some base type (interface/class) for polymorphism. If you are looking to get rid of all your code, then just call FactoryClass.GetInstance().SomeMethod();. Instead, I think you are looking for a wrapper class that instanciates objects from factorys, so you call Wrapper.DoSomething() and that is it. – iMortalitySX Sep 19 '12 at 21:35
  • @MortalitySX, polymorphism is a seperate issue, but yes, you're right I could use an interface or base class for that. But the point in this post wasn't to look at polymorphism yet. In this case, the only name the consumer knows about is "IMyInterfaceFactory.GetInstance()", and thats a static method name, not the name of a type. If I wanted to use polymorphism here, i'd opt for an interface though. But using var still affords the benefit of the consumer not even having to know the name of that interface. – Sean Thoman Sep 19 '12 at 21:40
  • The only knowledge requirement alleviated is that of the developer - the compiler's just going to replace `var` with the inferred type name. From the perspective of code written by different developers, this replaces an explicit contract (the interface type) with an implicit one (the type must expose method `DoSomething` or my code will crash). From the perspective of classes referencing each other, using `var` is indistinguishable from using `MyInterfaceInstance`. – Dan J Sep 19 '12 at 23:54
  • @DanJ, thats correct, its the knowledge of the developer, but would also come heavily into play anytime you want to gut a part of a project for another project, or drastically change the implementation of an assembly that a project is referencing. The major downside for me is that when you use var, a reference to the instance you retrieve from GetInstance() cannot be kept anywhere (not on the heap), since var only lives in function scope. – Sean Thoman Sep 20 '12 at 00:46