Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries (2nd Edition)
All
Stack Overflow 104
This Year
Stack Overflow 3
This Month
Stack Overflow 1
https://www.amazon.com/dp/0321545613/ref=cm_sw_r_cp_apa_i_wn...
Yes because you're potentially introducing unexpected behaviors. Objects should be constructed and free from exceptions and unexpected behavior. If the async actions are still happening after the object is constructed and the user is trying to use it...
Also, what if the async method is still running and the user decides to destroy the object?
A good read: http://www.amazon.com/Framework-Design-Guidelines-Conventions-Libraries/dp/0321545613/ref=sr_1_1?s=books&ie=UTF8&qid=1314813265&sr=1-1
If your async method has to be async because it's a long running process then it needs to be moved to it's own method that gets called by the user, not when the object is instatiated.
You also have the potential issue of keeping a reference to the object if the user decides to destroy it before async method is done which means you could have a memory leak.
If this HAS to be done to initialize the object should be created using a factory or a builder.
First, if you're developing an API for use by others, I'd recommend reading a book like: http://www.amazon.com/Framework-Design-Guidelines-Conventions-Development/dp/0321545613
Following those rules will avoid a large number of usability issues with your interface before any review is necessary.
Second, run a usability study with a few target developers, those who're likely to make use of this API, but haven't ever seen it before. Put them in front of the system and give them a few tasks, then watch how they go about figuring out how to do it. Their pain points will tell you where you need to make improvements.
Organize your project cleanly into namespaces. Namespaces should not be too big, not too small. Make each namespace have a public "interface" (i.e. a set of public classes) and don't access internal implementation details of the namespace from other namespaces. Different namespaces usually address different parts of an application, e.g. you'll have namespaces related to UI, business logic, helper functionality, etc. The Framework Design Guidelines have some good suggestions how to design namespaces.
When you feel that your project grows too large, simply identify sets of namespaces that are clearly related to each other and move them to separate projects. Since other namespaces already just use the public interface of the moved namespaces, refactoring the namespaces into new projects is merely a file-move-operation.
There are two common conventions.
the first is "User underscore as field marker" the second is "Use s_ for static fields and m_ for intance fields"
imo this is a religious question and onnly important thing is to not mix up both styles.
This book contains many good ideas about convention and design guidelines
http://www.amazon.de/Framework-Design-Guidelines-Conventions-Development/dp/0321545613/ref=sr_1_1?ie=UTF8&qid=1320395003&sr=8-1
According to this book, which explains the problems they had when writting the first versions of the framework; at the beggining of the .Net framework lifecycle there were lots of discussions about guidelines (naming conventions, interfaces vs abstract classes, etc).
That is why "old namespaces" such as the Interop services contain implementations that are against the rules that you can find today, basically those rules where learned and implemented while implementing the code itself!
The .Net framework still has old legacy code that cannot be changed because of the implications it would have in old applications.
I believe there was some more info in this book as well, but not too sure now.
The almost-canonical one is "Design Guidelines for Developing Class Libraries", which is pretty much the online version of this book. There's a lot of good information in there.
It is considered a best practice to NEVER return null when returning a collection or enumerable. "ALWAYS" return an empty enumerable/collection. It prevents the aforementioned nonsense, and prevents your car getting egged by co-workers and users of your classes.
In general that's correct, but there are cases when returning null isn't wrong. so the "ALWAYS" has to be omitted.
Also, a great source is the Framework Design Guidelines 2nd Edition (pg. 256):
Simple Injector does not contain an
IContainer
abstraction, because that would be useless:It would be useless for Simple Injector to define it, because your code would in that case still depend on the library (since Simple Injector defines that abstraction), and this causes a vendor lock-in, which Simple Injector tries to prevent.
Any code you write, apart from the application's Composition Root, should not depend on the container, nor on an abstraction over the container. Both are implementations of the Service Locator anti-pattern.
You should NOT use a DI library when unit testing. When unit testing, you should manually inject all fake or mock objects in the class under test. Using a container only complicates things. Perhaps you are using a container, because manually creating those classes is too cumbersome for you. This might indicate problems with your code (you might be violating the Single Responsibility Principle) or your tests (you might be missing a factory method to create the class under test).
You might use the container for your integration tests, but you shouldn't have that many integration tests in the first place. The focus should be on unit tests and this should be easy when applying the dependency injection pattern. On top of that, there are better ways of hiding the container from your integration tests, compared to depending on a very wide library-defined interface.
It is trivial to define such interface (plus an adapter) yourself, which justifies not having it in the library. It is your job as application developer to define the right abstractions for your application as stated by the Dependency Inversion Principle. Libraries and frameworks that tend to do this will fail most of the time in providing an abstraction that works for everyone.
The library itself does not use that abstraction and a library should, according to the Framework Design Guidelines, in that case not define such abstraction for you. As stated in the previous point, Simple Injector would get the abstraction wrong anyway.
Last but not least, the Simple Injector container does actually implement System.IServiceProvider which is defined in mscorlib.dll and can be used for retrieving service objects.
From the Framework Design Guidelines 2nd Edition (pg. 256):
Here's another interesting article on the benefits of not returning nulls (I was trying to find something on Brad Abram's blog, and he linked to the article).
Edit- as Eric Lippert has now commented to the original question, I'd also like to link to his excellent article.
After spending 10 minutes editing the question for formatting, I'm still going to downvote it. There's no way I'm going to read all that.
Go pick up a copy of
Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries (2nd Edition)
You don't need a list of 'bad' exceptions, you should treat everything as bad by default. Only catch what you can handle and recover from. CLR can notify you of unhandled exceptions so that you can log them appropriately. Swallowing everything but a black listed exceptions is not a proper way to fix your bugs. That would just mask them. Read this and this.
Few other rules:
Eric Lippert classifies all exceptions into 4 groups: Fatal, 'Boneheaded', Vexing, Exogenous. Following is my interpretation of Eric's advice:
This is roughly equivalent to Microsoft's categorization: Usage, Program error and System failure. You can also use static analysis tools like FxCop to enforce some of these rules.
Generally, the rule goes something like this:
To put this in somewhat more concrete terms, let's look at an example. The
System.Drawing.Bitmap
class is-an image (and as such, it inherits from theImage
class), but it also can-do disposing, so it implements theIDisposable
interface. It also can-do serialization, so it implements from theISerializable
interface.But more practically, interfaces are often used to simulate multiple inheritance in C#. If your
Processor
class needs to inherit from something likeSystem.ComponentModel.Component
, then you have little choice but to implement anIProcessor
interface.The fact is that both interfaces and abstract base class provide a contract specifying what a particular class can do. It's a common myth that interfaces are necessary to declare this contract, but that's not correct. The biggest advantage to my mind is that abstract base classes allow you provide default functionality for the subclasses. But if there is no default functionality that makes sense, there's nothing keeping you from marking the method itself as
abstract
, requiring that derived classes implement it themselves, just like if they were to implement an interface.For answers to questions like this, I often turn to the .NET Framework Design Guidelines, which have this to say about choosing between classes and interfaces:
Their general recommendations are as follows:
Chris Anderson expresses particular agreement with this last tenet, arguing that:
The difference between VBA and VB.NET is just because VB.NET compiles continuously in the background. You'll get an error when you compile the VBA.
Like Jonathan says, when programming you can think of VB.NET as case-insensitive apart from string-comparisons, XML, and a few other situations...
I think you're interested in what's under the hood. Well, the .NET Common Language Runtime is case-sensitive, and VB.NET code relies on the runtime, so you can see it must be case-sensitive at runtime, e.g. when it's looking up variables and methods.
The VB.NET compiler and editor let you ignore that - because they correct the case in your code.
If you play around with dynamic features or late-binding (Option Strict Off) you can prove that the underlying run-time is case-sensitive. Another way to see that is to realise that case-sensitive languages like C# use the same runtime, so the runtime obviously supports case-sensitivity.
EDIT If you want to take the IDE out of the equation, you can always compile from the command-line. Edit your code in Notepad so it has
ss
andSS
and see what the compiler does.EDIT Quote from Jeffrey Richter in the .NET Framework Design Guidelines page 45.
I prefer to name my virtual or abstract methods with the suffix
Core
, to indicate, that the method should contain the core logic to do something.All argument checks and raising possible events I do in the method, that calls the Core-Methods.
I think there is no offical naming guideline for this, and it´s up to you. But it should be consistent for all classes and virtual/abstract methods you define.
The "Framework Design Guidelines" suggest to use the Core suffix if you follow the Template Method and want to provide extensibility points.
As you figured out yourself, the article you were originally looking for is called Design Guidelines for Developing Class Libraries on the MSDN.
Note that it also exists a great complete book on the very same topic, named Framework Design Guidelines. Actually, the MSDN page encourages you to have a look at this book if you want to go deeper:
alt text http://davesbox.com/images/books/FrameworkDesignGuidelines2ndEditionLarge.jpg
The recommendation comes from the Framework Design Guidelines. This recommendation of Microsoft exists specially for reusable class libraries. In other words: frameworks like the .NET framework itself. If you are creating a line of business application, this guideline does not apply. It does not apply because it is unlikely that you will have versioning problems in a line of business application, because you have control over all the client code that talks to your classes / interfaces. This is of course not the case for reusable libraries.
Even the article of Phil Haack, where Will references to describes this:
Removing versioning problems is therefore probably not a good argument for using base classes. Keeping code DRY however could be. However, using base classes and interfaces aren't mutually exclusive; you can let your
abstract class ProductRepository
implementIProductRepository
. If you do this however, exposing anything else thanIProductRepository
would be a bad idea.