Where to put Delegates in .Net Solution [closed]
Asked Answered
M

1

6

I have a C# .Net collection of solutions which started as a proof of concept, and has grown to almost 15 different projects. I am currently in the process of rewriting the whole product family, and trying to maintain best practices to the best of my abilities, with future-proof organisation.

I have done some research, and I am still unclear on the best place to keep delegates in a multi-project product to minimise the likelihood of a need for refactoring in the future.

I would assume the general consensus is that you place them anywhere that makes sense for the use case, but in general I feel there is a best way to structure everything in a solution to minimise problems, promote positive modularity, and ease maintenance.

In many cases it is recommended that they travel with where they are used; presumably declared in the namespace above the class file, which in my case would translate to my common library with the common interfaces which mandate the events. I currently have delegates in their own file, in a 'delegate' namespace. Is there an oversight I am making by doing so, or am I overcomplicating the use case for delegates - or is this inline with current usage expectations?

I have done the typical searches, but haven't found anything credible nor substantial; however this could be a consequence of poor keyword selection.

Monocot answered 2/6, 2015 at 5:2 Comment(2)
If the project is large, and you want SOLID-type decoupling I would give delegates the same handling as interfaces, viz in an independent assembly, such that both the publisher / implementation and subscriber / callback code are both coupled on the delegates assembly (and any types they use), and not directly to eachother. I have to admit nowadays it is more common to see naked Func or Actions with no explicit delegate type (Similar thinking to Generic IEnumerables and ILists<> etc).Gilbertegilbertian
Thanks StuartLC!. Func/Action/Predicate/Converter/Comparison are new to me. Thanks for bringing them to my attention!Swivet
S
2

I would assume the general consensus is that you place them anywhere that makes sense for the use case, but in general I feel there is a best way to structure everything in a solution to minimise problems, promote positive modularity, and ease maintenance.

Well yes, in the general case, you can just put everything wherever you please it. However, the problems start when you're working in a team. In a team, other people have to understand the structure of the program to be able to create code effectively. That implies consistency, which is the end goal.

So, it's not just a matter of intuition; in all the companies that I've worked in, I've started by writing a coding standard and aggressively enforcing it everywhere. In this coding standard, I usually put a ton of good/bad practices involving threading, static use, placement of variables / classes, etc.

Iirc this link http://se.inf.ethz.ch/old/teaching/ss2007/251-0290-00/project/CSharpCodingStandards.pdf and https://msdn.microsoft.com/en-us/library/ff926074.aspx will give you a head start, although the former is a bit outdated and both don't really answer your question. It might however help with what you're trying to achieve in the long run.

[...] I currently have delegates in their own file, in a 'delegate' namespace. Is there an oversight I am making by doing so, or am I overcomplicating the use case for delegates - or is this inline with current usage expectations?

A common library with interfaces makes sense. An interface is essentially a contract between 'client' and 'server', which is an important asset for decoupling a piece of software.

You have to realize at this point that the 'interface' part is a functional decomposition, not a technical one. In other words: the fact that you need an 'interface' library is a matter of contract, not of technical constructs. As such, I don't see why you would ever put classes in a 'classes' folder and why you would put delegates in a 'delegates' folder. In short, a 'delegates' folder doesn't make any sense to me. Put the stuff where it belongs.

At this point, you have a decision to make. (1) You can put a delegate in a single file, (2) you can put a delegate in the class file where it's used (I usually use delegates for a single purpose), (3) you can do both depending on single / multi purpose and (4) you can put single-purpose delegates nested within the class. This basically means you're treating a delegate as a function pointer description, and don't see it as a real 'class'.

Looking at functional decomposition, you can argue that a function pointer belongs to a class, just like methods.

So to concluse. Personally I usually go for option (2) or (3) because it's brief, clear and concise, and doesn't have an impact on the amount of 'typing work' like (4) . Picking (1) will probably bloat your application with small files that have little or no purpose, which will confuse other developers.

Siddur answered 2/6, 2015 at 6:25 Comment(3)
Thank you for the input Atlaste! I should probably add that my library which holds the interfaces, really holds all common components of the problem space. Within that, everything is more or less sorted by scope/function, and then for the larger scopes the interfaces/delegates/types/exceptions are currently in their own namespaces. I'm still chasing the 'ultimate solution' dragon and working towards the best implementation before I formalise the release - but there is still much to do. It sounds like I am currently leaning towards points 1 & 2 depending on use.Swivet
@Gui "Sorting" also sounds like you're having very big class/interface files. I usually try to make them small and with limited, well-defined, well-bound functionality. In practice this means that most of my classes have about 100 lines of code; constructor first, then fields, properties, then members (so you can easily spot what data a class holds). Still, the latter is mostly a matter of taste; the key points you should focus on are (1) functional decomposition and (2) relentless standardization.Siddur
@Siddur I do have some pretty monstrous classes/interfaces in my prototype, but in the re-write I am pretty happy with my class/interface sizes in general. I do have a few which are large, but like you, most are 100 lines or less, and well bounded. Thanks again for your answer, I am making good progress tonight!Swivet

© 2022 - 2024 — McMap. All rights reserved.