Alternatives to the "using" directive keyword in C#?
Asked Answered
P

5

5

I just finished watching an episode of Bob Martin at NDC where he said "using" directives in C# at the top of a page are bad because of the tight coupling they create/imply between components.

What way are there to use external .dlls without adding a project reference and a using statement?

I remember V6 used to let you create an object by the string of the ProgId--I'm not sure that's the technique I'm looking for, but it's an example of a language that didn't need a project reference to use a dll.

EDIT: Here is a link to the conference. Sorry I don't have the exact quote or minute in the presenation, I'm going by memory.

Palisade answered 10/9, 2009 at 11:39 Comment(3)
Did he really say that, or that's what you understood of what he said?Inexorable
A link to this would be helpful. I'd like to hear what he actually said.Epigynous
Just to avoid confusion, Microsoft refer to it as the using "directive". The using statement (keyword) would normally refer to the one used inside methods to automatically call Dispose on resources.Gq
B
6

It's not the using statement itself that is bad - it's if you get too many of them.

A statement such as using System; is rarely a problem in itself, but if you have lots (I'd say more than 3-6, depending on which ones) in the same code file, it could be an indication of tight coupling.

You could just as well apply a similar rule of thumb to the number of references in a project itself.

The solution to tight coupling is programming to interfaces and Dependency Injection (DI).

The ProgId way of doing things that you can remember from VB was simply COM in action. In essence, you used that ProgId to get a reference to an instance that implemented the desired interface. The downside was that this only worked when the COM object was universally registered. Remember dll hell?

You can still apply the same principle using certain flavors of DI, only that now the interface is a .NET type and not defined in IDL, and you need some sort of DI Container to supply the concrete implementation.

Boiardo answered 10/9, 2009 at 11:53 Comment(4)
I'd write this "it could be an indication of tight coupling" instead of "if could be an indication of tight coupling"Inexorable
@Vinko Vrsalovic: No, I don't agree: If you have twenty using statements, it's definitely an indication of tight coupling.Boiardo
Then say so: "it is an indication of tight coupling"Inexorable
@Vinko Vrsalovic: Oh, but I also wanted to highlight the term tight coupliing since I believe that is actually the crux of the matter.Boiardo
G
7

I believe Bob Martin is actually referring to early versus late binding.

In .NET late binding is possible through reflection and more specifically the Activator class that allows creation of a type in an external assembly using a filename or assembly name.

Normally, using directives (not the using statement) go hand in hand with directly referencing an external assembly. ie. You add a reference to an assembly and then add using directives to avoid needing to type the full namespace hierarchy when you use the external types.

So if you find your code has a large number of using directives at the top, it is possible that you are referencing many other types directly and so increasing the coupling/dependency of your code on these types.

I would guess this is why Bob is referring to them as bad. The answer to the question "is this actually bad?" is a very subjective and context dependent one.

In general though, de-coupling of components is almost always a good goal to aim for in designing software. This is because it allows you to change parts of your system with minimal impact on the rest of the system. Having read one or two of Bob Martins books, I would expect this is what he is getting at.

Gq answered 10/9, 2009 at 11:46 Comment(0)
S
6

using is just a shortcut to namespaces, they are not references to external files. Therefore, this is just not really making sense.

Anyways, what one can do is have an interface DLL (a DLL with only interfaces), so that you dynamically load and use different assemblies and create types (through reflection) which you can cast to the well-known interfaces. This is the proper way of loosening external references while keeping the benefits of the strongly typed language and early binding.

Have a look at the Assembly and AppDomain classes to load assemblies, and Activator to create type instances by name.

Sideslip answered 10/9, 2009 at 11:42 Comment(3)
Agreed. This guy who says using statements are bad clearly does not know what he's talking about.Tavarez
@Noldorin: Robert C. Martin doesn't know what he's talking about?!Boiardo
Or he was misunderstood. Who was or is wrong doesn't matter much, because the "message received" is not making sense.Sideslip
B
6

It's not the using statement itself that is bad - it's if you get too many of them.

A statement such as using System; is rarely a problem in itself, but if you have lots (I'd say more than 3-6, depending on which ones) in the same code file, it could be an indication of tight coupling.

You could just as well apply a similar rule of thumb to the number of references in a project itself.

The solution to tight coupling is programming to interfaces and Dependency Injection (DI).

The ProgId way of doing things that you can remember from VB was simply COM in action. In essence, you used that ProgId to get a reference to an instance that implemented the desired interface. The downside was that this only worked when the COM object was universally registered. Remember dll hell?

You can still apply the same principle using certain flavors of DI, only that now the interface is a .NET type and not defined in IDL, and you need some sort of DI Container to supply the concrete implementation.

Boiardo answered 10/9, 2009 at 11:53 Comment(4)
I'd write this "it could be an indication of tight coupling" instead of "if could be an indication of tight coupling"Inexorable
@Vinko Vrsalovic: No, I don't agree: If you have twenty using statements, it's definitely an indication of tight coupling.Boiardo
Then say so: "it is an indication of tight coupling"Inexorable
@Vinko Vrsalovic: Oh, but I also wanted to highlight the term tight coupliing since I believe that is actually the crux of the matter.Boiardo
H
2

You could use reflection:

// Load the assembly
Assembly assembly = Assembly.LoadFrom(@"c:\path\Tools.dll");
// Select a type
Type type = assembly.GetType("Tools.Utility");
// invoke a method on this type
type.InvokeMember("SomeMethod", BindingFlags.Static, null, null, new object[0]);
Handbarrow answered 10/9, 2009 at 11:47 Comment(2)
This invocation kind is called late-binding and it is not only slow and quite error-prone, but also quite cumbersome in languages such as C# which are not designed to support late binding out of the box (e.g. via compiler magic). If possible, I'd avoid this approach.Sideslip
Better to use a DI framework for this kind of thing, honestly. Better for the noobish as well.Zigmund
D
1

You can do what you are referring to through reflection. You can load the assembly at runtime, and reflect through it to get the classes etc. and call them dynamically.

Personally, I wouldn't do this though to avoid coupling. To me that is a bad use of reflection, and I would much rather add it to the project and reference it, unless there is a specific reason why not to do so. Reflection adds overhead to the system, and you don't get the advantage of compile time safety.

Dynameter answered 10/9, 2009 at 11:46 Comment(3)
Moreover, this "technique" wouldn't avoid coupling. Your code isn't any less coupled to an external DLL because you're calling it dynamically - if the DLL isn't there, your code won't work.Cypsela
It does reduce coupling if you have an interface assembly and load dynamically objects that have interfaces. Dependency injection is a good approach too.Seigneury
@Kenny: you're totally right in that case. I was more making the point that if you just remove a reference and instead load it dynamically, you're not improving the situation.Cypsela

© 2022 - 2024 — McMap. All rights reserved.