You already spotted most of the pros and cons. Using cs files as references is indeed more lightweight and often easier to manage. However, I recommend to use this approach exclusively when your cs
files are fully self-contained and do not have any special build requirements.
Using separate DLLs
will make dependencies to other utilities or libraries explicit (so as long as you do not have such dependencies, it will work fine)
will allow you to define specific build configurations (for example, if a class only works in x86 configuration, or needs at least .NET 4.0, the build configuration of the assembly makes this requirement explicit).
So especially if you have lots of single-class, self contained components, using reference to files is fine, but if you have components referencing other components, or specific build requirements, I would recommend to use DLLs.
To mitigate the problems with managing many separate DLLs, you can either create an installer package, or utilize ILMerge, which can embed a set of assemblies into a single executable. In our environment, we deal with the problem differently, by using a deploy script for each application. This script makes sure all needed DLLs are always delivered to production when a new application release is published.
Is putting conversion method inside (POCO?) object (like .ToPerson() method in Consumer class) considered breaking single responsibility pattern?
Yes, because conversion is another responsibility.
Is using converting constructors in (DTO-like) class considered breaking single responsibility pattern? Especially if such class can be converted from multiple source types, so multiple converting constructors would be required?
Yes, conversion is another responsibility. It makes no difference if you do it via constructors or via conversion methods (e.g. ToPerson
).
Is using extension methods while having access to original class source code considered bad practice?
Not necessarily. You can create extension methods even if you have the source code of the class that you want to extend. I think that whether you create an extension method or not should be determined by the nature of such method. For example, does it contain a lot of logic? Does it depend on anything other that the members of the object itself? I would say that you shouldn't have an extension method that requires dependencies to work or that contains complex logic. Only the simplest of logic should be contained in an extension method.
Can such behavior be used as viable pattern for separating logic or is it an anti-pattern?
If the logic is complex, then I think that you shouldn't use an extension method. As I noted earlier, you should use extension methods only for the simplest things. I wouldn't consider conversion simple.
I suggest that you create conversion services. You can have a single generic interface for it like this:
public interface IConverter<TSource,TDestination>
{
TDestination Convert(TSource source_object);
}
And you can have converters like this:
public class PersonToCustomerConverter : IConverter<Person,Customer>
{
public Customer Convert(Person source_object)
{
//Do the conversion here. Note that you can have dependencies injected to this class
}
}
And you can use Dependency Injection to inject a converter (e.g. IConverter<Person,Customer>
) to any class that requires the ability to convert between Person
and Customer
.
Best Answer
Extension methods are just syntactic sugar for ordinary static method calls.
Extension methods make possible the ability to "spot-weld" methods onto existing types, without requiring inheritance, composition, weaving or any other language mechanisms. But they're just a proxy for an ordinary method call; they don't participate in the design of the class, nor do they add any new functionality that the class doesn't already have.
What an extension method does is turn this:
into this:
And that's all it really does.
It's arguably prettier (which is no small thing), but really, is there any other compelling reason to use extension methods?
Yes: to enable Method Chaining.
This would be very tedious without extension methods.
The advice "use extension methods sparingly, and only when you have to" is not actionable. Entire libraries and frameworks have been built using extension methods, and you never "have to."
So is it a "best practice?" My answer to that is "does it most effectively meet your specific needs?"