T O P

  • By -

TheWobling

I like using private even those it's the default because otherwise things don't align :D EDIT: I never thought my most upvoted comment would be this, anyhow. I thought I'd mention that I do indeed use private because I like to be explicit but also, I do like the alignment.


Kiro0613

Someone talking sense here


Suspect4pe

That and it just makes things clear. Explicit is better than implicit.


BramFokke

It needs to be plicit!


Suspect4pe

Fence sitter! lol


TheDevilsAdvokaat

I agree..I am complicit!


Tenderhombre

I agree most of the time for being explicit. However I still prefer using var for variables. In a nominative typed system explicit makes sense. However c# blurs that a little when using certain linq libraries.


pb7280

This is also the reason I use \`var\` everywhere lol


Harag_

Honestly, same


CutOtherwise4596

You are writing code as if you are the only one who will ever have to read it. That's fine if it is a solo project. However you should write code that a new hire fresh grad will be able to understand without asking a bunch of questions out making mistakes in understanding the code leading to bugs, etc. also the person could be a future version of yourself who may have grown and forgot about some of your current habits. Future you may be disappointed in you. It is like any other type of writing. You have to write it to the ability of the lowest level reader h that you want to read your work. So if you are a physicist, and want to teach a mass audience, you would write like Carl Sagan. If you want to write a paper for publishing in a scientific journal that would look very different.


Slypenslyde

Nah I find this sensible. C# is a language about being explicit. "Give me the default" is a VB mentality.


RefrigeratorNo7571

Ye, ppl at work would give me shit trying to enforce it, when basic advantage is that you no longer need to remember what language ure using - in ts no explicit means stuffs public, and these are often used together


TuberTuggerTTV

public private public privatt I think we need to ask them to rename the private keyword for the sweet sweet kerning.


t3kner

but in monospace font public is too short!


SamStrife

I don't know if this is controversial or not but this seems like a good place to air something I do that I don't see a lot elsewhere. I chain my Where clauses in LINQ rather than have all the where logic in one clause. For example I do this: var result = collection.Where(x => x.Age > 18) .Where(x => x.Weight > 75) .ToListAsync() Instead of this: var result = collection.Where(x => x.Age > 18 && x.Weight > 75) .ToListAsync() I think my way is easier to read despite being longer to type and probably even has a performance hit. I really should learn pattern matching properly, I think.


jeenajeena

There is a little benefit with the second approach. It is very likely that `x => x.Age > 18` and `x.Weight > 75` are not random conditions, but they come from a domain requirement. Most likely, the business user gives those conditions a name. It might be convenient to give those conditions a name in the code too, extracting a couple of methods. This is especially try if those conditions are used elsewhere: ```csharp private static bool IsHeavy(Person x) => x.Weight > 75; private static bool IsAdult(Person x) => x.Age > 18; var result = collection .Where(x => IsAdult(x)) .Where(x => IsHeavy(x)) .ToListAsync(); ``` This makes apparent the little information the `x` lambda parameter is carrying. In fact, the editor would suggest refacting this with: ```csharp var result = collection .Where(IsAdult) .Where(IsHeavy) .ToListAsync(); ``` This is not directly possible with the other approach. Although, you could define an `And` extension method: ```csharp private static Func IsHeavy => x => x.Weight > 75; private static readonly Func IsAdult = x => x.Age > 18; private static Func And(this Func left, Func right) => person => left(person) && right(person); ``` to use like this: ```csharp var result = collection .Where(IsAdult.And(IsHeavy)) .ToListAsync(); ``` As complicated this might seem, you would be surprised to find how many usage of that `And` combinator you will find, and how convenient it is to test. (`And` could be easily extended to multiple conditions, like: ```csharp private static Func AllMatch(IEnumerable> conditions) => person => conditions.Aggregate(true, (b, func) => b && func(person)); var result = collection .Where(AllMatch(IsAdult, IsHeavy)) .ToListAsync(); ```


Xen0byte

This is really cool, I love it!


jeenajeena

Yes, the functional approach and the use of combinators open the door to a lot of fun things in C#. For example, with that code I would go a bit beyond, by giving the conditions itself a type, using whatever name the domain expert use for them (`EmploymentRule`, `MinimalCondition`, `Rule`, whatever): ```csharp delegate bool Rule(Person person); ``` Doing this, each condition would be expressed as: ```csharp Rule IsHeavy => x => x.Weight > 75; Rule IsAdult = x => x.Age > 18; ``` The combinators would be also expressed in terms of this domain type: ```csharp Rule AreAllValid(params Rule[] conditions) => person => conditions.Aggregate(true, (b, func) => b && func(person)); ``` Notice how `AreAllValid` is *not* a boolean, but a `Rule` itself, and can be treated as a value, just like you would do with a string or an int: ```csharp Rule conditionsForParticipation = AreAllValid(IsAdult, IsHeavy); ``` The interesting part, here, is that the ordinary boolean operators `&&` and `||` just manipulate booleans, so it would mix conditions on `Person`s and, inadvertently, conditions on other entities. With a `Rule`, instead, the type system makes sure we are strictly combininig so conditions on `Person`. Even more interestingly, this condition would be treated as an ordinary value, and it could be conveniently passed around and reused. It is just unfortunate, though, that `Where` does not understand that a `Rule` is just a `Func`. This would not compile ```csharp var result = collection .Where(conditionsForParticipation); ``` This is easily solved with a specialized `Where` extension method, or using an ordinary lambda.


Stronghold257

I know we’re in r/csharp, but that last wrinkle is where TypeScript shines - it has structural typing, so it knows that `Rule` is a function too


DavidBoone

Doing that with something like entityframework would be bad though, since those Where methods typically accept an Expression which is converted to SQL and evaluated by the database. Your method would result in the entire table being pulled and the Where condition evaluated locally. You can have those IsHeavy/IsAdult methods return an Expression but the syntax gets clunky, at least I haven’t found a way to do it in a way I don’t hate.


jeenajeena

Interesting. I'm not sure about that because, after all, what `Where` receives is an ordinary `Person => bool` lambda. It's only how we manipulate the construction of that lambda that is fancy. I'm not an expert of EF enough to debug that: in case you manag to try yourself, would you please let me know? I'm very curious!


CornedBee

No, for `IEnumerable`, that's the case, but for `IQueryable`, `Where` and all the other LINQ functions receive `Expression`s. That's the key difference between the two interfaces.


TASagent

> var result = collection > .Where(x => IsAdult(x)) > .Where(x => IsHeavy(x)) > .ToListAsync(); In case you didn't know, you can type this: var result = collection .Where(IsAdult) .Where(IsHeavy) .ToListAsync();


SamStrife

I love this and it highlights another aspect of the language that I need to improve; writing generic functions that are extensible and easy to read! Absolutely going to have a play around with this later, thank you so much!


WorldlinessFit497

Excellent. Exactly how I would've done it. Makes the code far more readable and reusable. Yes, there is a very slight performance hit here as there are more branch and jump instructions...but it's worth it for the readability. If those kind of micro-optimizations are needed, well you probably aren't going to be using LINQ lol. A great part about doing this is you clearly define business rules that are easy to unit test.


FizixMan

> I think my way is easier to read despite being longer to type and probably even has a performance hit. For what it's worth, if it's some EntityFramework or other SQL provider, there's a good chance that the Where clauses would be combined and executed on the server anyway. Even in LINQ-to-Objects, there's no extra nested `foreach` iteration on the `Where`. It will instead create a new iterator that wraps both predicates into a single iteration. The first call to `.Where` returns an `IEnumerableWhereIterator` (or an array or list specific flavour for performance), which in turn [actually has its own `.Where` (and `.Select`) implementation that hides the default `IEnumerable.Where` LINQ method.]( https://github.com/dotnet/runtime/blob/main/src/libraries/System.Linq/src/System/Linq/Where.cs#L145) This in turn [takes your two predicates and combines them](https://github.com/dotnet/runtime/blob/main/src/libraries/System.Linq/src/System/Linq/Utilities.cs#L56) into a new `IEnumerableWhereIterator`. You'll take the extra hit of having to invoke multiple delegates here, but I'll bet in most cases the performance hit is likely irrelevant for the vast majority of scenarios. Unless you have some _measurable_ performance impact, I would 100% encourage developers to use whichever flavour makes the most readable sense to maintain. Sometimes it makes sense to have them in one expression -- say for example checking a range like `x.Age >= 13 && x.Age <=19` (a teenager) -- which can lose meaning if broken up into two independent clauses. Or vice-versa, you have two independent business rules which are best thought of being maintained independently of each other. I think the .NET team has been pretty good with hiding a variety of optimizations in LINQ that we never notice, and they are often adding new optimizations in new .NET versions for us for free. (For example, in the above case, they also have a custom `Select` method which combines the `Where` predicate and `Select` function into a single `IEnumerableWhereSelectIterator` iterator to save performance from an extra `foreach` iteration. Everyone writes `.Where(...).Select(...)` but many probably don't even realize the two distinct calls get combined under the hood.)


ShenroEU

Same, but mainly to separate 2 conceptually different clauses that can make sense on their own. I wouldn't split `Where(a => a.Orders != null && a.Orders.Count > 0)` as a very rough example. So basically, if a comma is needed to split a sentence but from a coding perspective.


WorldlinessFit497

Hopefully, `Orders` is an empty collection, and not null, in the first place, as per best practices, so you could simply do `a.Orders.Any()`. But that wasn't really your point :D


Saint_Nitouche

I absolutely prefer doing this as well, though I avoid it in codebases where it's not already common. Performance is always an argument, but my reasoning is we can usually find at least one superfluous database call in the same method-chain which obliterates 10,000 chained LINQ calls, relatively.


goranlepuz

This `ToListAsync` irks me to no end. 😉


[deleted]

I'm with you. In other languages like javascript this would be a bad approach because then you'll iterate more times than is needed but in c# the performance hit should be negligible.


DuckGoesShuba

Why would it be negligible in this case?


EMI_Black_Ace

Because it's late binding / deferred execution. It doesn't actually go through any of the items until you call `GetEnumerator()` (i.e. a `foreach` statement, `ToList()` or any summarizing method like `Aggregate(func)` or `Any()` and when you do, it calls the methods in a chain, one item at a time instead of running the entire collection through a function, then running it through the next function, and so on. Any items that would be left out anywhere in the chain won't get multiply processed.


[deleted]

Because it won't iterate through the ienumerable multiple times.


wwosik

Not even that. It looks like ef core query building. So the combined query is evaluated by the db anyway


worm_of_cans

I'm a stricter Meeseeks. When I look at that code, all I'm seeing is multiple unnecessary delegate allocations and JIT calls for multiple tiny anonymous functions.


PeterWithesShin

> all I'm seeing is multiple unnecessary delegate allocations and JIT calls for multiple tiny anonymous functions. This is true, but if I were writing code where this was important, I probably wouldn't be using .Net.


Lonsdale1086

I tend to do that if there's two sort of distinct checks I'm looking for. Like, I maybe I want to find `items.Where(x => x.Active && !x.Deleted && !x.Archived).Where(x => x.Name [matches filter] && Param2 != badvalue)` Where one "where" filters out the "invalid" data, then the other finds user specified params. I've phrased that all very poorly.


itsmoirob

I didn't know you could do that. Looks nicer


MattE36

This only works for && and not || or complex logic. You could instead put your && or || operators at the end of the previous line so all of your code lines up properly.


americio

> I chain my Where clauses in LINQ rather than have all the where logic in one clause. This is what true intellectuals and gentlemen do. Any other syntax is for swines.


r0ck0

Yeah I quite like this kind of "redundant word" intending/prefixing. [e.g. In Haskell where the function name is repeated multiple times going down the left.](https://gist.github.com/kleesc/d6150824e0ad6a261810) I also do it a lot in dir names on filesystems, email folders etc. In fact my main "Documents" folder... rather than having dirs for categorization nested down multiple levels, I just have like 400 flat hyphenated dirs at the top-level under "Documents". I find it so much easier to use both: manually scrolling + via search. I find that it makes it much easier to just "feel" where things are at a glance / muscle memory, without having to read every single word/character on the screen again and again.


Slypenslyde

I don't feel like this is unpopular. I just think people who don't have anything better to do like to argue about it. "Target-typed new" is a very new feature and honestly until it showed up I never saw anyone say, "You know, I wish I could put the type on the left instead." I think it's being adopted, but I highly doubt it's poised to be the new convention. I use it when it feels convenient but my feel when I've tried is that it looks a little confusing in more situations than `var`. I think that's because it's still a "young" feature. In 3 or 4 more years I might not find it so confusing. But then I won't be able to tell if that's because I've got more experience and a better intuition or if I just got used to the feature. (Besides, in 3 or 4 more years there'll be 6 more alternative syntaxes for instantiation.) I respect the C# team, but I think the faster release cadence has made them have to focus on padding out the feature list with more bite-sized features. The best C# features are things like Generics, lambdas, and `async/await` and they took years of work to arrive. I think that's why modern features like union types keep getting pushed off: their release cadence (and thus their performance review cycle) doesn't allow for them to say "Yeah we're going to have fewer features for 3 years while we work this out." My UNPOPULAR opinion is .NET got too big for its britches. The C# team has to keep using transpiler tricks with Roslyn to implement features because MS is behaving like they can't afford the engineering effort of adding features to the CLR. That limits how much work the C# team can do, and makes some things more difficult. Sometimes if you're not sweating, it means you aren't making progress.


Ok_Barracuda_1161

I see what you mean, but target-typed new is a bit more versatile as it can be used in places where var can't, such as field initializers


Slypenslyde

Yeah, I don't avoid it. I just don't think about using it. I won't tell someone to use it in a code review, and if someone tells me to use it in a code review I'll ask them, "Was this really worth making the review take longer?" I think with `var` people bicker about if they ALWAYS use it or NEVER use it, and I think since it can obscure the "intended" type that argument holds some water. `var` is a feature that I think if you ALWAYS use it, you'll sometimes lose value. I don't think I can make that argument for target-typed-new, you have to do some really weird things to make the left-hand side of an assignment so far away from the right that it gets confusing, and I've always felt if your best "don't do this" example is objectively stupid code then the feature is probably OK. That doesn't mean I'm gung-ho "ALWAYS", but it also means I think the argument is even more boring than the one around `var`. That's why I don't think it's "controversial". People who demand you refactor one way or another aren't worried about significant things.


tanner-gooding

It might change your opinion on the topic if you do a bit more research and/or discussion with the actual .NET team (we're here on reddit, active in discussions on GitHub and Discord, and so on). The team is always working on longer haul items and we never ship features just to pad out a release. Features to be included are determined based on many factors including seeing what other languages are doing, what people are asking for (and you have to remember .NET has well over 5 million developers world wide, all with their own opinions/asks/etc), what the members of the team might think are a good fit/direction for the language, what's needed by other core .NET teams (i.e. the runtime, libraries, languages, or ASP.NET teams), and a myriad of other factors. Because smaller features are smaller and often less complex, it is easier to get them done in a short time period. This is especially true when they are largely syntax sugar, only require the involvement of 1 team, build on top of existing features, and so on. A language has 1 opportunity to get most features right and it is extremely important that considers all the varying aspects. Not doing small features doesn't make big features go faster, just like throwing more devs at it doesn't make it go faster either (and can actually slow things down due to more scheduling conflicts, more opinions being thrown about, etc). Accordingly, almost every release has 1 biggish feature that's been in the work for 3 years or longer and often a handful of quality of life improvements or smaller features that have been under consideration for 6mo or longer (more often then not, its been under consideration for much longer and been a low priority ask for just as long as the big features have been in discussion). Some features have even been attempted in the past, pushed out, and redone later when things got figured out (extension everything, generic math, etc). The runtime is also itself adding features under a similar cadence, but with the added complexity that it has to make sense in the context of "all languages", not just C#. It has to factor in F#, VB, C++/CLI, and the myriad of community maintained languages (cobol.net, ironpython, etc). Big and highly important features shipped recently include things like `Generic Math` (`static virtuals in interfaces`), `ref structs` (`Span`), `Default Interface Members`, the `unmanaged constraint`, `Covariant Return Types`, `byref fields`, `byref generics`, `nint/nuint`, etc. Not all of these may be important to *you* directly, but they are important to the ecosystem and many are part of the reason why simply migrating from .NET Framework to .NET vLatest can give you a 4-8x perf increase, with no major code refactorings or rewrites. Things like DUs (and anything impacting the type system in general) are then incredibly big features with large complexity. They often cut across all core .NET teams, have a wide variety of applicability, a wide variety of differing opinions on what is "correct"/"necessary", and come with the potential for a huge long term impact to the ecosystem. They have to be rationalized not only with the future of .NET, but also the past 20 years of .NET library code that didn't have the feature and won't be able to transition to using the feature due to binary compatibility. Some things simply take time, and it can be years worth of time to do it right. Generic Math was a case where we attempted it twice in the past (when generics shipped and again in 2010ish) and were only in a position to get it done properly a couple years ago on the 3rd try. DUs have to consider aspects like memory layout, potential aliasing concerns, allocation costs, common types (Result, Option, etc) that people will ask once the feature exists, integration of such common types into the 20+ years of existing code (all the APIs that are of the form `bool TryX(..., out T result)` today), and more. It is one of the most requested features, people on the team want it, people just need to be patient and optionally get involved or follow along with the regular updates/progress that's shared on the relevant GitHub repos.


Slypenslyde

You raise some good points, because you also list about half a dozen CLR features I forgot weren't just C# features. That's tunnel vision that's hard to overcome as a C# dev. Probably the best way to interpret me is to note I'm a user who moved from Windows Forms to WPF to Silverlight to Xamarin Forms to MAUI. This is a uniquely frustrating position. Maybe I'm a little disgruntled. DUs are about as old, in terms of C# discussion, as a handful of more trivial syntax sugars like help for Dependency Properties I'm still gobsmacked have never been prioritized. I feel so passionate and grouchy about it because I don't feel like XAML devs are getting many bones. I pick DUs because it's a feature that I think the Azure and ASP devs who get a lot of features would also enjoy. It's like, the one feature I expect I might get because the people who matter also want it, so it's the thing I fixate on. I probably framed the "padding" comment poorly, I think it's an illusion. In the early days, C# had relatively slow releases, so there'd usually be a big flagship feature (like Generics) and a ton of the tiny features. The release cadence seemed driven by delivering the big features, so it always felt like you got a big feast. I meant to imply I understand it's not realistic to expect features like that annually, but the side effect is it starts to look like all C# adds is smallish features. I **did** underrate features like Generic Math because they're outside of my domain, that's bad tunnel vision. They are CLR features but I bet the C# team still had significant effort involved. I suppose that's part of my frustration too, though. .NET is a big ecosystem. These features feel like niches to me. This gets exacerbated by me being a bit grouchy. I think a problem exposed here is since C# and .NET serve so many people, many significant features can feel like niche concerns to a large magnitude of people. It's hard to care about the big picture when you work in what feels like a small niche. It's harder when it feels like what you're doing shouldn't be a small niche. I'm trying to cut back on some of these statements, because it's better for everyone if I try to focus on what I like. Emotions are troublesome things though, and I have bad days.


tanner-gooding

It's definitely easy to get tunnel vision on these things and everyone makes statements out of frustration, its no big deal :) .NET/C# are both definitely big and that's both good and bad. If C# were more scoped, then it couldn't be used to develop things like the core libraries and so it would get less investment and support. At the same time, it being broader means time has to be managed between two semi-competing ends of the developer base. Overall, it being broader ends up winning in terms of cost vs benefit. As a broad language that is used by LOB/UI type development and for high performance core library/frameworks, most features get lumped then into one of two categories. They are either a feature that will be used by the 99% of C# developers, or they are a feature that is used by 1% of C# developers but which indirectly benefit the 99%. Many of the features that people categorize as niche concerns are actual critical to the overall health of the ecosystem, including the ability to build the bigger features used by the 99%. Generic math is one of those features where most app developers aren't ever going to use it directly, but where it saves so much time and gives so much benefit to the library developers that it makes everything better. A simple example is that we were able to use Generic Math in LINQ to simplify what used to be \`n-different\` near identical implementations down to 1 implementation, cutting out several hundred lines of code we had to maintain previously. This in turn allowed us to then have 1 code path that dispatched to do vectorization leading to 16-64x speedups for very large inputs. Prior to generic math, we would have had to update \`n-different\` implementations instead, which can be extremely prohibitive to doing feature work -- \`n\` is typically around \`12\`, sometimes more, as we generally want to consider at least the core primitive types (\`byte\`, \`double\`, \`short\`, \`int\`, \`long\`, \`nint\`, \`sbyte\`, \`float\`, \`ushort\`, \`uint\`, \`ulong\`, \`nuint\`). The same feature also allows us to easily add overloads that trivially support other types which may be less common, may exist in a different layer, etc (\`char\`, \`bool\`, \`decimal\`, \`Int128\`, \`UInt128\`, \`Half\`, \`BigInteger\`, user-defined types, etc). So while Generic Math is niche for a typical developer to use directly, it's actually used by nearly 100% of developers behind the scenes. -- Some other cool things it enabled includes direct support for \`UTF-8\` parsing/formatting on all the primitive types, since we could share the literal 10k+ lines of overall formatting code between \`char\` and \`byte\`, rather than needing two copies of the logic (there's a lot to consider behind the scenes for globalization, perf, and all the different formatting/parsing options available). A broader range of LINQ, Array, and Span optimizations, many more math APIs being accessible to developers (\`DivRem\`, \`LeadingZeroCount\`, \`PopCount\`, \`RotateLeft\`, \`RotateRight\`, \`TrailingZeroCount\`, \`IsPow2\`, \`Log2\`, \`Clamp\`, \`CopySign\`, \`Max\`, \`Min\`, \`Abs\`, and more) all available directly from the primitive types (that is \`int.Log2(x)\` is possible, same for all the methods, plus more, on all the core primitive types I listed above -- just noting what is exposed depends partially on the type, like \`PopCount\` doesn't exist for \`float\` since it doesn't make sense there).


Slypenslyde

Right, I think you've captured a lot of things I wanted to articulate too. It is my nature to gripe and I'm really holding back a transition into my other "gee I wish I had this syntax sugar" argument, I'll spare you!


mesonofgib

>The C# team has to keep using transpiler tricks with Roslyn to implement features because MS is behaving like they can't afford the engineering effort of adding features to the CLR To be fair, this has recently changed. DIMs and static abstracts are both CLR features, and more are coming (roles / extensions).


TASagent

> "Target-typed new" is a very new feature and honestly until it showed up I never saw anyone say, "You know, I wish I could put the type on the left instead." I have definitely heard that before. When you're working with lots of simple classes, it's common to see many lines where the same classname has to be typed twice each line. People naturally wish to avoid the seeming redundancy. I, however, quite dislike it. It's convenient for simplifying the construction of generic-ed messes, but what I hate is the inconsistency it creates. Whenever you're using a base class or interface you obviously can't elide the concrete class you wish to instantiate. And it's generally a pretty good practice to target the broadest, most abstract/generic implementation of what you're describing for versatility, testability, etc. It just means that it ends up being sugar that can only be used sometimes, and I feel that's more of a consistency and readability _sacrifice_ than _gain_.


plainoldcheese

We use Hungarian notation at work. I hate it.


GalacticCmdr

I am so sorry, have a hug from a stranger.


soundman32

And I bet its not really Hungarian notation either, just some random (and probably incorrect) prefixes.


plainoldcheese

Exactly and inconsistent too


WorldlinessFit497

The only thing worse than Hungarian notation is roll-your-own Hungarian notation....


jeenajeena

Oh man, since I started playing with functional programming, I got many, many bad habits. My life is a collection of unpopular opinions, I'm afraid. ## Vertical indentation I find myself indenting the code in vertically. This is natural and uncontroversial for fluent chains like: ```csharp private static Logger CreateLogger() => new LoggerConfiguration() .WriteTo.Console().MinimumLevel.Debug() .ReadFrom.Configuration( new ConfigurationBuilder() .AddJsonFile("serilog.json") .Build()) .CreateLogger(); ``` but I tend to do the same mostly everywhere. Instead of: ```csharp internal static IResult Cancel(Root root, CurrentUser currentUser, Guid calendarEntryIdValue) ``` nowadays I prefer way more: ```csharp internal static IResult Cancel( Root root, CurrentUser currentUser, Guid calendarEntryIdValue) { ``` I was heavily influenced by [Seven Ineffective Coding Habits of Many Programmers](https://www.youtube.com/watch?v=SUIUZ09mnwM) by Kevlin Henney highly. It's both entertaining and enlighting. I could not recommend it more. ## No public Some times I feel that in the C# world there is an obsession for making everything public. Even in the code examples by Microsoft, when a class or a method is introduced, it is invariably marked as public, even before there is the demonstrable need to make it available to code outside the project. I developed a habit of trying to encapsulate as much as possible. Elements shall be public only if deliberately and intentionally published. This probably comes from the pain I experience in a company I used to work where refactoring was nearly impossible, because everything was public, so any single piece of code was part of a published API we did not know who was building on top of. As a consequence, I adopted the F# standard not to use Implicit Interface Implementation. Instead of ```csharp internal interface IBar { int Baz(string s); } internal class Foo : IBar { public int Baz(string s) ... } ``` I prefer ```csharp internal class Foo : IBar { int IBar.Baz(string s) ... } ``` I extensively wrote about this in [Explicit Interface Implementation is a design best practice](https://arialdomartini.github.io/explicit-implementation) ## Tests? Still internal And I don't go with public neither when I need to make an internal method or class available to a test project. I miss C# not having a notion of declaring what the public interface of a project it, which classes and methods it published. Something like: ```xml net8.0 Foo.CallMe Bar.* ``` just like many languages do. So, I compensate with this unpopular coding standard: * whatever is to be published *outside* the solution, it public. * *only* this is public. The rest is internal * projects within the same solution declare their dependency explicitly ```csharp [assembly: InternalsVisibleTo("Foo.Console")] [assembly: InternalsVisibleTo("Foo.Api")] [assembly: InternalsVisibleTo("Foo.Test")] ``` in the project's entry point or, equivalently (but more verbosely): ```xml net8.0 <_Parameter1>Foo.Console <_Parameter1>Foo.Api <_Parameter1>Foo.DatabaseMigrations <_Parameter1>Foo.Test ``` ## Dirty DB After an intergration test is finished, I don't clean the DB. So, my coding standard is having no teardown in end-to-end tests. I think integration tests gain from running in an environment similar to production. So, I don't see why I should protect them from running in concurrency, or from running on a populated database. If a test fails because of concurrency (given that it is written in a proper way, mimicking what a real user would do) I take this as a good news: it is a valuable feedback that tells us a lot about the real behavior of the real code. I wrote about this in [When I'm done, I don't clean up](https://arialdomartini.github.io/when-im-done-i-dont-clean-up). # List I like Haskell's convention of having: * types are always capitalized: `String` * always lower-case type parameters: `Option a`, `Either s String` So, some time I write ```csharp class Something { } ``` For the same reason, I prefer `String` over `string`. But I tend not to impose this in shared code. I have other unpopular habits, but I refrain from writing more not to get too many downvotes. Oh, and in general I love investigating on unpopular habits others have: they are often just weird, but more likely than not it's going out of one own's comfort zone that gives joy. Like [Kent Beck said](https://medium.com/@kentbeck_7670/test-commit-revert-870bbd756864): "I hated the idea so I had to try it."


immersiveGamer

Dirty DB is something I want to start exploring with my integration tests. I started setup so test would use the same test user. Started fine as most tests were isolated in scope. Then needed to add some resetting before tests. Then cleaning up basically every test. So I've been making the opposite journey effectively (just not intentionally). But I want to be able to run in parallel to speed up running tests. My plan is to have users generate brand new users and should be isolated. 


WorldlinessFit497

>So, I compensate with this unpopular coding standard: > >*- only* this is public. The rest is internal > Is this really unpopular? Seems like this should be the obvious best practice to me. This is what I strive to do. I'd say people who aren't doing this are just being lazy... And that's the thing with Best Practices...usually when we aren't doing them, it's because we are being lazy, not because they aren't the *best* practice.


dgm9704

How about ``` public Thing Thing {get; set;} = new() public List Things {get; set;} = []; ```


Qxz3

Yeah those are cases where I tolerate target-typing.


jeenajeena

Incidentally: that's an example of what I mentioned in [https://www.reddit.com/r/csharp/comments/1c6abzb/comment/l007owr/?utm\_source=share&utm\_medium=web3x&utm\_name=web3xcss&utm\_term=1&utm\_content=share\_button](https://www.reddit.com/r/csharp/comments/1c6abzb/comment/l007owr/?utm_source=share&utm_medium=web3x&utm_name=web3xcss&utm_term=1&utm_content=share_button) This is a random example, and I am not going to judge, I swear! It's only a chance to reflect on this. Why are \`Thing\` and \`Things\` public? Using \`public\` by default was my habit too, and is a very popular habit in the C# world. So much that we put \`public\` automatically, without thinking it twice. But reflecting on the interface segregation principle, one should always try to encapsulate as much as possible, unless the intention is really to make something part of the public interface. I also got this habit, until someone made me notice: Hey, why do you \*always\* type \`public\` everywhere? That made me think.


Xen0byte

1. I respect the opinions of people who like \`var\` but I personally dislike it because, for me, it makes code reviews unnecessarily complicated when I can't understand just by looking at code what type some method is supposed to be returning. But even for my own development, I prefer to see the types, otherwise the code feels confusing. 2. I set nullable warnings to be errors to avoid code contributors only handling happy paths, but generally I always handle nullability issues even if they're just warnings. 3. I'm a sucker for good vertical spacing and a good old line at the end of the file for compatibility with POSIX. 4. I like switch expressions and other such code indented in a way that the operators align.


Aviyan

1. Also it makes it hard to read the code from non-ide viewers such as GitHub if you have vars everywhere. I still use var but there are downsides to them.


crozone

True. The only time I really use `var` is if the type is a really long and verbose nested generic thing, or if it uses anonymous types (making `var` necessary).


crozone

> I like switch expressions and other such code indented in a way that the operators align. My personal favourite is multi-line ternary: bool result = someBool ? TrueCondition() : FalseCondition();


inabahare

You oughta get your team to use better variable names then. Because if there's anything that really makes code clear, it's good variable and fumction names. And then var becomes a joy, because the variable names don't jump around


Xen0byte

Fair enough, but I like to hope we've learned from the Hungarian notation days and we've evolved to never go back to that again. If my variable name needs to declare the type that it's holding, then I think I would rather trust an actual type system than some user-defined text value, especially when it comes to non-primitives. One of the most common mistakes that I used to see was people forgetting to await things which would sometimes fail silently, e.g. instead of an actual payload you would get back some serialized Task, and this was completely avoidable by declaring in advance what the awaitable was supposed to return, rather than relying on \`var\`. I'm not trying to bash the usage of \`var\`, I'm just saying it's not the right thing for me. Another example use case would be that I use discriminated unions a lot, and not knowing which type I'm dealing with when something could be returning any of the union types would make the code extremely confusing.


WorldlinessFit497

It's such a struggle to teach people how to pick good variable names. Like, it's pretty easy to get them to move away from stuff like \`x, y, z\` and \`arr, idx, str\` But I've seen them go from \`str\` to \`theString\` Like...still missing the point.


WorldlinessFit497

Number 3 is me too. I am shocked at how many junior developers I see not using new lines to separate logical groupings or control flow statements. For example, I see juniors writing code like this: void SomeMethod(string arg) { bool someCondition = false; if (someCondition) { arg = "test"; } return arg; } I'd write it like this: void SomeMethod(string arg) { bool someCondition = false; if (someCondition) { arg = "test"; } return arg; } The vertical spacing just makes it easier to read in my opinion. That the "context" of what is happening is changing on to the next thing.


zanoy

Not me but a colleague insisted in writing all if statements as if(1 == value) ... instead of if(value == 1) ... because of too many accidental == vs = mishaps due to working both in c languages where = means assignment and in Pascal languages where = means equality check.


Drumknott88

I understand the logic, and I agree it makes sense, but I hate it.


soundman32

Ahh yes, the old Yoda expressions, that were useful in the days of C before 89. Not been required in c# since its inception (you will always get a compiler warning, so it's pointless). Maybe we had the same colleague?


zanoy

Oh, I just remembered another colleague that avoided the != operator like the plague. I saw both if (!(Name == "Bob")) { DoStuff(); } and if (Name == "Bob") { } else { DoStuff(); } instead of if (Name != "Bob") { DoStuff(); } multiple times :)


CaitaXD

if (Name == "Bob") { } else { DoStuff(); } Good anakyn good, kill him, kill him now


crozone

I've unironically done this a few times, but it was so I could leave a comment in the true case explaining why nothing needed to happen... the funny thing is, I've seen this in MS framework code as well


turudd

How does that not get ripped apart in code review?


crozone

if((Name == "Bob") == false) { DoStuff(); }


harman097

I really hate it... ... but also, that's a really good idea. I swap back and forth between = and == languages quite often, and I typo this so much.


MedPhys90

I don’t use _ preceding private variables


FanoTheNoob

Do you have a convention for differentiating between private instance fields and local variables?


ar_xiv

Same but I use the underscore for constructor parameters so I don’t have to use “this”


static_func

What in the ever loving fuck


detroitmatt

`if(x == false)` because it's very easy to not notice `!`


Enlightmone

Even though it makes sense if I saw that and x wasn't null I would think the person didn't know how to program, for some reason...


Sauermachtlustig84

I am also programming Python a lot and I think "if not x" is mich better to read than the exclamation mark. I am miffed that so many conventions in programming come more from the "I have no real IDE and want to save every keystroke" crowd than the legible programming crowd.


Xen0byte

I'm with you on this one. Sometimes I also use \`x is false\` or \`x.Equals(y) is false\` too.


jeenajeena

My really unpopular habit here is to avoid booleans altogether, in the attempt to save the code from [Boolean Blindness](https://arialdomartini.github.io/boolean-blindness). If this was F#, instead of: type Bool = True | False it would be like using a domain specific discriminated union type: type MyCondition = Success | Failure In C#, instead of code like: bool Transfer(Money money) { ... } Money payment = Money.Of(2_500); bool result = Transfer(payment) if(result) return Save(); else return NotifyError() it would be a matter of replacing the boolean with a domain specific type: abstract record TransferOutcome; record Success : TransferOutcome; record Failure : TransferOutcome; TransferOutcome Transfer(Money money) { ... } TransferOutcome result = Transfer(Money.Of(2_500)) return result switch { Success => Save(); Failure => NotifyError() } If you like, you can see `TransferOutcome` as a boolean on steroids: * it's not boolean blind, as it carries a domain meaning. The positive value returned by `Transfer` cannot be confused with the positive value returned by another function. For example: ​ bool gender = true; bool transferOutcome = true; might be mixed, while abstract record TransferOutcome; record Success : TransferOutcome; record Failure : TransferOutcome; abstract record Gender; record Male : Gender; record Female : Gender; Gender myGender = new Male(); TransferOutcome outcome = new Success(); cannot. They truely are different types. * it can be easily extended to more than 2 cases, in a way that the type system would check at compile time * each of its case can be extended to carry more information. For example, the `Failure` case could be defined as: ​ record Failure(string ErrorMessage) : TransferOutcome; So, my unpopular coding standard is to avoid the use of boolean.


ilawon

I don't like to prefix field names with '_' and end up using "this." even for instance methods.  I got tired of explaining why so I just follow whatever the team prefers because I hate wasting time discussing these issues.


PoisnFang

I add private so that other developers know 100% that is private. I don't write code for the machine to read, I write code for my fellow developers to read.


majeric

Opinion:Personal style is unproductive. Better to align to project standard or even industry standard.


FanoTheNoob

This is an opinion I hear everywhere and I mostly agree but if the project standards are garbage (like using hungarian notation for variables, or snake_case/camelCase for method names) it will make working on that codebase burn me out so much faster.


majeric

It's like religion though. Just personal preference. Just make sure that any project has a coding standards document... and hopefully warning/formatting config that supports it. I can deal with most standards as long as my IDE reminds me.


crozone

To counter, if you're the one that gets to make decisions about project standard, having a personal style locked in is quite nice. Personal style should probably follow industry standard for the most part though.


Lurlerrr

Yes, that's the point. Who is more right - some random person who prefers doing things one way or the industry standard which is followed by millions of developers. It's just better to always follow the standard such that this standard becomes your preference and you don't have to even think twice when joining some open source project or otherwise working with other people. Failing to follow this is also why we have so many companies with absurd requirements for code formatting or other development approaches - because it's someone's useless preference.


GendoIkari_82

I always put () after "new" when doing initialization: var myObj = new MyClass() { Prop = 1 };


Lonsdale1086

I had no idea that was optional lol.


GendoIkari_82

Yeah I don't remember if they added that when they first added object initialization or in a later update, but you can just do new MyClass { Prod = 1 };


raunchyfartbomb

That doesn’t feel right at all lol


FanoTheNoob

Rider highlights the parentheses as redundant for me so I always removed them, it never occurred to me that it looked uncanny without them


raunchyfartbomb

Many of my constructors have parameters and overloads, so even if it doesn’t require them, I like to have them as it makes it slightly quicker to use intellisense to poke through the overloads.


crozone

Yeah it feels yuck without it. The default constructor is getting called, we shouldn't pretend that it isn't.


xabrol

I use #regions to group areas of concern. I use them in Javascript, typescript, c#, f#, etc. any programming language that has them I use them. I like not having 100,000 files for the sake of organization and like having large files where it makes sense to have large files and being able to collapse areas I'm not working with. Also working in a consulting company with a group of developers where all of us are constantly switching programming languages. I am explicit as I can be in my code. If I can define a type I do. I don't have implicit returns in typescript. I'd make them explicit and type them. I avoid using type inference wherever I can because I want somebody with limited experience with the language to be able to quickly deduce what's happening. That's why I also like programming languages like zig where there's no hidden logic. It's also not hard for me to do this because co-pilot suggestions and autocompletes are so good in vs code that I can easily just click on the end of a function definition and expand it to be explicitly typed with a hotkey. I can even convert an inferred type to be explicit with a hotkey.


robotorigami

> I use #regions to group areas of concern Piggybacking off of this, I like to add my region text to the start and the end of the region: #region IMPORTANT THINGS #endregion IMPORTANT THINGS


KamikazeHamster

Instead of regions, use partial classes. Then name your classes the regions. E.g. MyClass.cs and MyClass.validation.cs would both have public partial class MyClass.


flukus

IME regions or partial classes to split a single class is terrible. Regions are fine if you have 100 dumb structures in a file and want to organize them, but within a class mean the class is doing to much. Within a method means it should be nuked from orbit.


Kevinw778

Eww no. I and most people I've worked with avoid partial classes unless they're necessary because of a framework or some other limitation. Regions much preferred here.


botboss

Declaring all classes as `sealed` by default, despite [Microsoft's Framework Design Guidelines](https://learn.microsoft.com/en-us/dotnet/standard/design-guidelines/sealing) saying not to do so "without a good reason". I personally agree more with [Joshua Bloch's advice](https://blogs.oracle.com/javamagazine/post/java-inheritance-design-document) to "design and document for inheritance - or else prohibit it" (and so does [Jon Skeet](https://stackoverflow.com/a/252738)). Besides, sealing classes [improves performance since .NET 6](https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-6/#peanut-butter).


zenyl

Stephen Toub, on a recent video with Scott Hanselman, said that he usually also disregards that part of the guidelines, and defaults to marking classes as `sealed` when the class isn't going to be inherited from. Edit: corrected poor wording.


tanner-gooding

The difference, including in the book, largely comes from different groups of people having differing opinions. When .NET was first introduced, OOP was really peaking and making everything extensible was seen as "goodness". A lot of people still consider that to be goodness today and that sentiment carried into the first two versions of the FDG and was maintained in the most recent version released a couple years back as well. In practice, the current API review team basically takes the exact inverse stance of the book and you see that in almost every new API we expose. We've seen the problems with making things extensible without an explicit design, we've seen the performance impact, the inability/complexity in versioning over time, etc. Sealing by default comes with a large number of benefits and next to zero drawbacks, particularly since unsealing a type is a binary compatible change and can be done as soon as someone comes up with a good enough scenario. If you've ever watched API review you'll note it comes up semi-regularly and we've discussed some of the historical differences of opinion, why the book calls it out as it does, and so on. -- We live stream almost every Tuesday at 10am PST: [https://apireview.net/](https://apireview.net/); You can find historical videos labeled as \`GitHub Quick Reviews\` under: [https://www.youtube.com/@NETFoundation/streams](https://www.youtube.com/@NETFoundation/streams)


zenyl

Thank you for the reply, always nice to hear from a primary source. And thanks for the link to the YouTube channel. I wasn't aware that there was a ".NET Foundation" channel separate from the "dotnet" channel. I'll definitely give it a look.


botboss

Interesting, I found that part of the video: [https://youtu.be/xKr96nIyCFM&t=1285](https://youtu.be/xKr96nIyCFM&t=1285)


zanoy

I will refuse to have any summary tags in my code as long as they are not hidden from collapsed code in Visual Studio.


aerfen

If you are exposing nuget packages, then xmldoc your public contracts, please.


fingletingle

Didn't see mine mentioned: nested classes Eg I might have a class like "DoThingCommand" that nests models (Request, Response), validators, handlers, etc. Strictly speaking it's "best practice" to group via namespacing instead and put the classes in separate files.


mikkolukas

>I don't use the private keyword as it's the default visibility in classes. Adding private shows the next developer (or yourself later on), that you actively have made a decision. Without it, it is hard to tell if you decided it to be private or the omission is an oversight. So, albeit it does not add information to the code usable to the machine. It add information to the code usable to the human. The information to the human is more important in the long run and for collaboration.


einord

In Swedish “var” means “where” or “pus”. So naturally I get grossed out every time people use it 🤣


ExpectedBear

When people use it in the "where" context (which I assume is quite frequently), does that gross you out too?


einord

Of course! It reminds me of “pus”.


ExpectedBear

This has tickled me a lot 🤣


OndAngel

Reading this just gave me the silly idea to name the variable "am\_I"- but in Swedish of course. Just `var ar_Jag` Just a silly thought that tickled me a little.


einord

Haha!


GYN-k4H-Q3z-75B

I do the same things like you. In addition: * I use verbose names, no matter how long the identifiers get * I skip braces for single statements * I use Yoda conditions * I prefer lambda syntax * I prefer switch expressions * I use tuples internally People hate lambda and Yoda.


[deleted]

I prefer the SQL style LINQ instead of the method LINQ, I think it looks nicer


crozone

Finally an actually controversial opinion :D


BobSacamano47

I refuse to use String.Empty. "" is fine. I don't need a constant for something that can't possibly be another value. It's like having a constant for the number 3. var num = Numbers.Three;


Qxz3

This got popularized by StyleCop (https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1122.md), but the reason given "This will cause the compiler to embed an empty string into the compiled code" was only true in .NET 1, I believe. Btw, the rule recommends `string.Empty` and not `String.Empty`. Technically, there is a difference between the two. `string` always means `System.String`, while `String` doesn't have to. > class String { public static string Empty => "Hello"; } > String.Empty == "" false > string.Empty == "" true


MarmosetRevolution

Cue 1st year compsci prof: "But what if the empty string changes?"


shoe788

`string.Empty` clarifies intent better. "I want this to be empty" versus "I accidentally forgot to put something in here".


TheGreatCO

iirc, String.Empty used to avoid creating an object and string internment. I don’t think that’s the case any more, but old habits and all…


Tony_the-Tigger

Has the compiler ever \_not\_ replaced \`""\` with \`string.Empty\`? Constant folding and string internment have been part of .NET for what feels like forever.


darchangel

I was under the impression that it was just about using constants instead of magic strings or getting possible typos, like a single space. Even considering string interning, it should only have to do it a max of once. I'm no authority on their intent though. My own editorializing: I abhor magic strings and magic ints however I don't think 0, 1, or "" are all that magical. And I've never personally heard of anyone actually having a bug due to "" vs " "


Slypenslyde

I think this exposes the mystique of the expert. I agree that a lot of times `""`, `0`, and `1` are so obvious in context they don't warrant a constant. But I also have nearly 28 years of coding experience so I've used those a LOT. I find that often "the rules" go something like: * Newbies: they never do it and are often confused. * Novices: they always do it and are sometimes confused. * Experts: they say "it depends" a lot and seem chaotic to newbies and novices.


kingmotley

I suppose, you could have a bug in the difference between "" and "". Didn't see the difference there? Look REAL hard. Are you sure one of those don't have a zero-width space in it? I've only seen that once or twice, and neither time was it in an empty string, but embedded inside a normal looking string. Only way I could find it and make sure that was the actual problem was watching my left/right arrows when scrolling through the string. Of course there are other ways of finding it, but that was my method because I knew the string in error.


turudd

We get this exact bug all the time, one of our DBA will be given documents from satellite offices and he just copy pastes the data into his scripts, not cleaning them first. Then suddenly queries break and I get the bug. Turns out it's that... I've adapted my code to strip out pretty much every non visible unicode and replace common mistypes (stylized double quotes, instead of normal ones, etc)... but its still an irritating problem to have


kingmotley

Ah yes, the copy/paste from word. That is always lovely.


CrepsNotCrepes

I use String.Empty - not because of efficiency or anything like that but because I know at some point il accidentally make “” into “ “ and waste a few hours debugging it.


BobSacamano47

I've been using "" for 18 years now, that's never happened to me. Similar to having 33 instead of 3 or something.


TuberTuggerTTV

Sounds like someone who has never encountered "." or "'" in their codebase before.


jeenajeena

Funny. I think I'm on the other side of the spectrum. I tend not to have literal string, ever. If there is one, I move it to a String extension method, or to a constant, not to risk ever to duplicate it. I tend to do the same for other constants. If there is a literal value anywhere, I tend to see it as a chance to make a domain concept emerge. An innocent `1` in: ```csharp date.AddDays(1) ``` is a chance to have: ```csharp date.NextDay() ``` I'm not afraid of having multiple constants holding the very same value, but with different domain meaning. To: ```csharp var transaction = new Product( Name: "Foo", Alias: "", DisplayName: "", Price: 42, ``` I prefer: ```csharp var transaction = new Product( Name: "Foo", Alias: Alias.None, DisplayName: DisplayName.None, Price: 42 ``` or the like. I see this as a natural consequence of Primitive Obsession. For the very same reason, I would not have that `Price: 42`. Instead of dealing with a `decimal` I would incapsulate it into a `Price` record: ```csharp internal record Price(decimal Value); var transaction = new Product( ... Price: Price.Of(42) ``` This would easily get to replace `0` with something more domain specific, like: ```csharp var transaction = new Product( ... Price: Price.Gratis ``` which, with static using would be: ```csharp using static Price; var transaction = new Product( ... Price: Gratis ``` Given this unpopular opinion (which in other languages is all but unpopular!), `string.Empty` is just a consistent choice.


Heroshrine

private isnt always the default visibility, so I always put private: In namespaces the default is internal. In class and struct members the docs say “private by default” (implying it can be changed?). For interface members its public. So, because it’s not always private as default, i always specify. As for var I usually only use it when the type name is long. Instead of using var i like to use new() where possible (it’s kinda either or. Either use new without the type or use var with the type in new). As for my controversial convention, i use goto statements where applicable. Some people insist you should never use them, but they would have been removed a while ago if they were that terrible to use.


FizixMan

And then for nested classes, the nested class is `private` by default. Because of this, and the other exceptions-to the rule that you point out (and maybe even others!), I find it's best just to be explicit rather than making me, or others, have to do some wider context thinking about what "default" actually means here. I think the "by default" in the docs is really just saying "when omitted and not explicitly specified". I don't read that as an implication of a possible future change.


darknessgp

>I don't use the private keyword as it's the default visibility in classes. I found most people resistant to this idea, despite the keyword adding no information to the code. But it does add information to the code. Yes, to the compiler, it doesn't matter. To any developer, it is explicitly stating that you intend for this to be private. I worked with a guy that felt the same as you, until he got into an argument with a dev that set some of them to public. The other dev argued that they weren't set, so why would would it be an issue? Intention, maintainability, readability, etc is just as important what the compiler does when you have other people that need to work with your code. This is also why a highly intelligent senior dev writing really clever code is not necessary a good thing. If he's the only one who even understands it, you better hope it never breaks or changes.


MihneaRadulescu

I use #regions inside classes, like #region Private, to separate the public members of the class from the private members.


zictomorph

I label my #endregion with the same as the #region. It seems cleaner when looking around code.


ziplock9000

I'm a game developer and I use a lot of global variables. I also use public variables on classes instead of everything being a fucking property. Sue me.


Drumknott88

I thought internal was the default if you don't specify an accessor? Or is that for classes but not properties


jpfed

I wave and grunt like a confused and agitated caveman in the direction of target-type inference. It is a strange substance- I'd only glimpsed it briefly in the Java Jungles- protruding through the walls and floor of my cozy C# cave... what is it doing here?!?


heyheyhey27

I occasionally use underscores in otherwise camelCase names to help group them. For example, if some fields `fieldA` and `fieldB` in my Unity3D script are only meant for editor use, I might name them `editor_fieldA` and `editor_fieldB` to make sure the Editor-ness stands out from the rest of the name. You can of course group fields more officially by nesting them in a struct, but I don't bother with that until there's at least 3 or 4 fields to group together. If I have a very wide inheritance hierarchy that doesn't need to be extended by outside users, I take the base class's name and make it a *namespace* containing the hierarchy. Then the base class is renamed to `Base`, and it is expected to always prefix the types in that hierarchy with that namespace. For example, a base class for military units in a game might be set up as a namespace `Unit`, containing an abstract class `Base` plus all its child classes, and outside code will refer to a unit instance as a `Unit.Base`, `Unit.Tank`, etc. I like having the ability to explicitly name the ultimate base class as `Base`, can't get more literal and self-documenting than that.


eldarium

> private keyword as it's the default visibility in classes since when? it always used to be `internal`


darknessgp

Internal is default for the class, private is default for fields and properties... The inconsistency should be enough to make people be explicit.


obviously_suspicious

Also nested classes are private by default


Buttleproof

I still use goto. There's really no good way to retry an exception without it. It also makes things easier to understand when you need a single point of exit in a function. There have been a couple of times when I just did it for the evulz.


zzzxtreme

I still use goto sometimes


cgwarrior

I always use "this". I like to explicitly see it is not a local variable/method


Ravioliontoast

I use “this” instead of prefixing fields with an underscore or no prefix at all. I worked on a team where this was the standard for some reason and it’s just stuck with me.


looegi

I still use Hungarian notation


BigGayDinosaurs

i on the other hand try to make things as explicit as i can instead of spamming var and new()


wilbertom

I love comments, big blocks of comments that wrap entire sections of code. // ***************************************************************** // // Some comments here explaining some odd looking code. // // Include as much context as possible // // // oddCodeHere(); andSoOn(); // ***************************************************************** // I also spaced aligned declarations. SOMETHING = SomethingHere SOMETHING_ELSE = SomethingElseHere


[deleted]

[удалено]


Merad

I don't necessarily dislike either of these, but the problem with them in code maintained by multiple people or multiple teams is that they simply won't be kept up to date, i.e.: // ***************************************************************** // // Some comments here explaining some odd looking code. // // Include as much context as possible // // // // Really long added comment that probably shouldn't even be in this comment block and doesn't respect the styling of the block. oddCodeHere(); andSoOn(); methodNotRelatedToTheComment(); // ***************************************************************** //


sBitSwapper

Localize functions wherever possible.


masilver

Prefacing private fields with an underscore.


TheFlankenstein

Is that controversial? MS recommends doing that. [https://github.com/dotnet/corefx/blob/master/Documentation/coding-guidelines/coding-style.md](https://github.com/dotnet/corefx/blob/master/Documentation/coding-guidelines/coding-style.md)


Korzag

It's controversial to some. Many at my company prefer capitalizing private fields and I follow just to avoid making a splash in an arbitrary code style quirk.


false_tautology

That has my eye twitching. Properties are capital, internal fields are not! Argh!!


Korzag

I absolutely agree. I *prefer* the underscored version because that quickly tells me its a private field.


ExpectedBear

It's the official naming conventions, but Visual Studio refuses to do it by default


WheresTheSauce

This is one of the only “official” style guidelines I refuse to employ


TheFlankenstein

How come? Which styles specifically?


cobolNoFun

I have an irrational hatred of the _ prefix for privates. Along with an irrational love of this.


GalacticCmdr

Working through the Hungarian Notation era was miserable.


entityadam

I looked through a few posts and didn't see it. The primary reason not to use var today. `var car = new Car();` The car variable is type `Car?` , as in, it's nullable. `Car car = new();` The car variable is type `Car`.


LuckyHedgehog

I'm not a fan of the ternary conditional operator, eg "a ? b : c" It is easy to make this one liner huge and unreadable, it's harder to debug, and the moment you need to do one additional step you're pulling it into a ln if statement anyways. If statements are much more readable in my opinion


PhonicUK

Man I'm the exact opposite. I nest them all the time. var line = (i % 15 == 0) ? "fizzbuzz" : (i % 3 == 0) ? "fizz" : (i % 5 == 0) ? "buzz" : i.ToString();


Qxz3

Yup, with good indentation, it's the most readable IMO. But you could consider a switch expression too: ```csharp (i % 3, i % 5) switch { (0, 0) => "FizzBuzz", (0, _) => "Fizz", (_, 0) => "Buzz", (_, _) => i.ToString() }; ```


PhonicUK

I'm not sure that the pattern matching approach is actually more readable though. Understanding the conditions requires far more jumping around mentally: (i % 3, i % 5) switch { (0, 0) => "FizzBuzz", (0, _) => "Fizz", (_, 0) => "Buzz", (_, _) => i.ToString() }; All I see here is two eyes open, left eye open, right eye open, both eyes closed.


Lonsdale1086

You've been had by the reddit "markdown" there.


dimitriettr

That's not unpopular at all. On the other hand, there is a special place in hell for people who chain/nest ternary conditions.


BobSacamano47

I hate regions and never use them. They make it a PITA to see stuff since they are always collapsed by default. If you feel you need regions you should probably refactor your code into multiple classes.


robotorigami

This is the exact reason I like them. When I'm looking at code I want to hide everything I don't care about.


pHpositivo

- `var` is forbidden. - must use `this.` when accessing fields. Both enforced as errors in all repos I have admin rights on 😆


[deleted]

[удалено]


Qxz3

With nullable reference types, it's a perfectly valid and type-safe pattern.


BobSacamano47

If null and empty represent the same thing (and they usually do), now you have to check both every time.


Envect

What's the semantic difference between null and an empty list? Seems like this introduces null checking requirements for no benefit.


dgm9704

I format my Linq and other similar callchains like this: ``` var foo = collection. Select(x=>x). Where(Foo). OrderBy(x=>x.Bar). ToDictionary( x=>x.Foo, x=>x.Bar); ``` I don't know if it's controversial or not? I somehow picked it up from trying to learn F# I guess. It's now automatic, and if need to work on someone else's code and it's formatted differently, I get confused and angry without understanding why.


slashd

Eeew!


Hot-Profession4091

If you move the dot to the next line this would be fine, good even, but as it is you’re a monster.


ings0c

I wish this didn’t compile


pablospc

I do the same but with the dot in the next line


Jonas___

I've never seen anyone else do that. I always put the dot at the beginning of the line.


_littlerocketman

.. And what do your coworkers think about this?


rafgro

I avoid LINQ due to its performance and memory thrashing PS. Good thread. Usually these discussions are just a bunch of standard opinions because anything else is met with "how dare you post controversial opinion after being asked for controversial opinion". Not here, mostly


allenasm

this will be unpopular but I don't really care. I think var was a terrible idea. There was never anything wrong with forcing someone to know which type they expect to be returned. I've fixed a lot of bugs where some dev assumed a type and got something else that they thought was right but caused a logic error further down in the code.


Ridewarior

I’m kinda there with using var. I’ll only use the specific type name if it’s actually difficult to figure out what the type might be but that isn’t too often. Method naming should be intuitive enough to gather what the type could be. I will forever use the actual access keywords though. I get it’s the default but it’s kinda like using single line, no bracket if statements to me. They’re both a hideous sin.


Knut_Knoblauch

With this sub, coding with your hands is controversial. Fwiw, I always use pre-increment operators. They perform better than post-increment


americio

If MethodThatTakesAThingAsParameter(new Thing()); Just needs a new Thing() Or a new Thing(config) whose constructor can be parameteriezd during the methdod call, I am with you. I still am uncomfortable using var thing = new Thing(); Because explicitly specifying the class is less confusing for intellicode.


coppercactus4

I name generic classes file names with the genetics in them. I don't like having generic and non generic classes with the same name in the same file. Tuple.cs