4 C# features that you (probably) shouldn't be using

preview_player
Показать описание

Hello everybody I'm Nick and in this video I will talk about the 4 C# features that either I am not using or I am very careful when I do so. I will explain why I am doing so and provide some context for potential traps that you may fall into.

Timestamps
Intro - 0:00
Labels & goto - 0:33
Lambda based getter only auto-properties (use but carefully) - 04:40
Default Implementation of Interface Members - 10:44
Regions - 16:33

Don't forget to comment, like and subscribe :)

Social Media:

#dotnet #csharp
Рекомендации по теме
Комментарии
Автор

Please watch the video and my points instead of reading chapter titles and drawing conclusions. This is more about being careful when you are using those features and what pitfalls you can fall in if you are not using it correctly, instead of blatantly telling you not to use something.
As people in the comments have already mentioned, the 2nd point is also true for the expanded version of the getter feature. I didn't include it because I have never seen it being misused in that way, mainly because it is easier to see what it's actually doing, since the extended getter feature would need to point to the field if it was to return it. Also just reading the title and drawing conclusions doesn't give you the full picture. For example for that feature from 8:30 - 8:43 I'm saying that this isn't about not using it, becaue it's an awesome feature and you should be using it, but you should know what you're doing. In almost every single one of those features I am explaing how you can use them in an appropriate way, but also explain why I'm not using them.

nickchapsas
Автор

I see no problem with lambda getters. The "surprising" behavior you describe is exactly how I always expected it to work.

I actually find regions useful when maintaining large projects developed by others. If they have used regions, I'm grateful for it.

paulkienitz
Автор

Region is really useful (at least for me) I always use them in my Xamarin .Forms to divide properties, commands, fields, dependencies, constructors, public methods, actions, private methods and disposable, that way it's easier for me to code and navigate

UzairAli
Автор

As for goto/labels; the only time I've used them properly in C# is when writing highly optimised, low level code. The C# "if" statement, and any form of loop, lowers down to a series of labels and gotos that repeat sections of code that need repeating, or skip branches of conditional logic. It maps nicely into the "jmp short" and "jmp long" calls in ASM. If you compile to AOT then gotos can create code that rivals C++ for performance. It's not pretty, but if you're used to writing ASM, it looks glorious. :D

ApacheGamingUK
Автор

TLDW: Don't use features you don't know how they work. Clickbait got me don't let it get you.

littlefreak
Автор

I disagree regarding regions. The collapsing is just some editor feature that has nothing to do with the actual code. And if you leave that away then a region is really just a comment with a scope, which I find very useful. One example use case would be when you're implementing multiple interfaces and you want to group the implementations that belong together. To me it sounds more like what you're actually unhappy with is collapsing regions, not with having them in the code but that's just a matter of personal preference since it doesn't change anything about the code. Just using regions instead of equivalent comments is a good thing imo.

bastianurbach
Автор

I like using expression-bodied properties to access a Lazy<T>.Value.

mahmutjomaa
Автор

The lambda property is great for "derived properties". For instance, say you have a Circle class that stores the radius. You could use lambda properties for diameter, circumference, and area.

CrapE_DM
Автор

There is a big difference between an extension method and a default implementation, both are valid to do, and both have their place.
The point of extension method is to provide some extending functionality composition functions like you did. However a default implementation allows the implementer to change the behavior completely. Forinstance in the project I work we also have a default implementation for LogException but our proper logger actually implements it by sending the exceptions to a specific function just for exception overview etc...

Gemasted
Автор

Point#2 is actually a really good option for derived properties. Imagine a Person class having FirstName & LastName properties. Then you can have something like this:-
public string FullName => $"{FirstName}, {LastName}";

Edit: For me, the => assign is quite explicit in telling that this is a function that will be invoked when called, as opposed to being pre-computed.

babri
Автор

Great video but respectfully disagree about #region. Although I can see why you say what you do, they're great for organising interface implementations. Some sort of compiler enforcement of that would be great though (just at warning / suggestion level).

ajonescouk
Автор

In Haskell, classes (which are essentially comparable to C# interfaces) can have default implementations for member functions and a "minimal complete definition" can be specified. This is useful because often there are multiple equivalent ways to implement the required functionality, so these default implementations can rely on the real implementation of other functions in the class, and the user gets to choose which one is easier for them to implement.

Sometimes you might want to implement more than the minimal complete definition in order to improve efficiency, but being able to omit definitions for members that are basically redundant is convenient and makes it easier to avoid incoherency in the class implementation.

joshuakb
Автор

6:58

The field value is only set once because you are doing field initialization (is that's how it's called? I don't remember) which will be assigned once when the object is being constructed. If you were to put the same GUID generation inside the getter itself, then it would behave identically to the lambda expression and method execution, because getter is always called and everything in it is executed.
But i guess the pitfall here is that someone can get confused when dealing with initialized properties... Which is possible, i guess

CristalCody
Автор

I agree with the first 3 things, but I personally probably couldn't live without regions. I hate having to scroll for miles when modifying large code files and regions help clean that issue up immensely. In some cases, for example if you're a newer programmer, or you plan on sharing your code, then it might not be a good idea to use them, but if you enjoy organized code thats easy to navigate, I think regions are great, and I even use then in C++(GNU GCC throws a warning, but doesn't cause any issues)

CasualGameDev
Автор

I disagree with default implementation of interface methods. I had a problem while trying to optimise wpf business application because WPF UserControls are weird in a way, since they can't inherit from a class and you can't make a class which inherits from UserControl. So, solution was to make an interface with implemented save, update, delete and get through extension methods for any UserControl which implements this interface. I would say in such cases, when you can't use normal inheritance there is a value in implementing interface default methods.

hilebile
Автор

I disagree about point 2. Not knowing that arrow syntax actually compiles to getter which calls some functions on each invocation only means that the developer should read docs more.
Also, it literally compiles to
public Guid UnitId
{
get
{
return Guid.NewGuid();
}
}
Old good C# 2 or whatever it was before introduction of shortened properties syntax.

OlegKosmakov
Автор

I think the idea behind the default interface implementation was to allow an interface to evolve without needing to create a new namespace or a new interface definition. Your example using extension methods doesn't actually extend the interface, it sort of tacks on another method to the interface. Meaning if you implement the interface, you can't override the implementation (as far as I'm aware) that the extension method provides, you can only replace it with a different extension method with a different name. So in your example, if you have deployed a domain model with a specific interface that is now used across multiple teams and multiple applications, you can extend the interface without breaking existing code bases, in this limited way.

I have not used this feature, but seems like a specialized, but useful option to have.

CuriouslyContent
Автор

10:25 If you do a "public Guid get_Id() { }" here, it will also give the same error, because it is still a property. It's giving you an error on "Id()" simply because you can't use the same identifier twice (for a property and a method). It's not that there is already an Id() method.

To be clear, all of these declarations are equivalent:

public Guid Id => Guid.NewGuid();

public Guid Id { get => Guid.NewGuid(); }

public Guid Id { get { return Guid.NewGuid(); } }

To me it's intuitive because it's consistent. Everywhere else, "=>" *always* means a function definition and "=" *always* means assignment, so I know which one I'm writing here too.


And for an actual Id *method* we would write this (note the "()"):

public Guid Id() => Guid.NewGuid();

Which is also consistent because "()" denotes the distinction between properties and methods in regular declarations as well.

TazG
Автор

People always say goto is bad but I've literally never seen a codebase where someone abuses it. It's a good statement that you only end up using when working at a low level of abstraction (usually with nested loops/switches)

pokefreak
Автор

About #2 (lamda AutoProps), a really interesting usecase is an on-demand init (.NET5.0) ....

For example:

private Nullable<Guid> _g = null;
public Guid Id => _g ?? (_g = new

mafiozos