3

A couple months ago, Microsoft updated their C# Naming Conventions (https://docs.microsoft.com/en-us/dotnet/csharp/fundamentals/coding-style/coding-conventions). As the developers of C#, I consider Microsoft to be the standard for coding conventions.

enter image description here

They want private and internal fields to be named as _myField. So calling an internal field from another class would look like this:

internal class MyClass1
{
    internal int _myInt;
}

internal class MyMainClass
{
    private MyClass1 _myClass1 = new MyClass1();

    internal void DoStuff()
    {
        _myClass1._myInt = 5;
    }
}

_myClass1._myInt = 5; just doesn't feel right to me. Maybe its because I am used to doing it other ways.

Am I understanding this convention right? If so, what are the objective benefits to doing it this way opposed to using the common PascalCase for internal fields? Are there any disadvantages?


Related question from Microsoft's convention in 2008, which goes against this new standard: C# - Why are prefixes on fields discouraged?

15
  • 10
    Rule number 1: don't use internal fields. Now the problem goes away. Commented Sep 27, 2021 at 15:25
  • 2
    I understand the logic behind internal fields, but I would still be reluctant to use them. If I did use them, I would follow the underscore convention. PascalCase should be reserved for properties. Commented Sep 27, 2021 at 16:03
  • 4
    I definitely agree with @PhilipKendall. I've never created an internal field in 20 years of writing C# code. Fields are private; always in my view. If it needs to be internal, make it a property and ideally make it a get-only one at that.
    – David Arno
    Commented Sep 27, 2021 at 16:12
  • 3
    Am I completely lame for not like leading underscores, because it is a hard key to reach? I don't even like snake_case when it is a commonly accepted naming convention. My pinky just doesn't stretch that far. That whole top row of the keyboard is awkward anyways. Except the 2 and 3 keys. For some reason those aren't so bad. Commented Sep 27, 2021 at 17:47
  • 3
    @GregBurghardt: I fully agree with you and I refuse to use leading underscores (unless work's code style forces me). I find it a variation on Hungarian notation, one which denotes the access modifier instead of the type; but I dislike it for the same principle. Also, it seems Microsoft agrees with us. Reproduce: add string test to a constructor, press Alt+Enter, pick "Create and assign field 'test'". What does it generate? private readonly string test;. No underscore. I rest my case.
    – Flater
    Commented Sep 28, 2021 at 8:00

5 Answers 5

8

That's just your opinion, man.

Naming conventions are an inherently subjective convention. There is no technical reason for most naming conventions, other than which characters are allowed to be used in names. To that extent, it's really just a matter of what you prefer.

But then we get to team-based development, and we realize that it's quite annoying if we don't all use the same approach, yet have to share the code. This is why conventions start making their appearance.

I suspect Microsoft was thinking of internal fields as assembly-private fields, which they arguably are, and therefore logically concluding that the same naming convention would make sense. However, I agree with your question's claim that there's a difference between the two, because internal field usage syntax is indistinguishable from public field usage syntax, provided the consumer is located in the same assembly. Seeing a private naming convention there rubs me the wrong way.

The short answer here is that Microsoft is just one opinion in a room of many, many opinions. If you want to attach more weight to their opinion, that's perfectly fine, but there are plenty of others who don't and/or outright disagree.


Microsoft also contradicts itself. Its code generating tools in VS don't use an underscore prefix even for private fields. You can replicate this behavior:

  • Create a class and write a parameterless constructor for it.
  • Add a method parameter to the constructor (string test).
  • With your text cursor on test, press Alt+Enter
  • Choose "create and assign field 'test'".
  • What do you get?

enter image description here

No underscore. I rest my case.


This is just my opinion, man.

Personally, I don't even like underscore prefixes for private fields to begin with.

In case you've not heard of Hungarian notation:

Hungarian notation is an identifier naming convention in computer programming, in which the name of a variable or function indicates its intention or kind, and in some dialects its type. [..] As the Microsoft Windows division adopted the naming convention, they used the actual data type for naming, and this convention became widely spread through the Windows API; this is sometimes called Systems Hungarian notation.

This naming convention advocates for prepending certain characters to variable names to indicate their type. sFoo for strings, iFoo for integers, lFoo for longs, ...

To quote Douglas Adams, in the beginning Hungarian notation was created. This has made a lot of people very angry and has been widely regarded as a bad move. At the time of writing, Hungarian notation is no longer used.

The best explanation I could find as to why it's a bad solution for the problem it tries to solve can be found here. Some excerpts:

Hungarian notation only makes sense in languages without user-defined types. In a modern functional or OO-language, you would encode information about the "kind" of value into the datatype or class rather than into the variable name.

Hungarian notations just turns the programmer into a human type-checker, with is the kind of job that is typically better handled by software.

Hungarian notation was specifically invented in the sixties for use in BCPL, a pretty low-level language which didn't do any type checking at all. I dont think any language in general use today have this problem, but the notation lived on as a kind of cargo cult programming.

In any other language, hungarian is just ugly, redundant and fragile. It repeats information already known from the type system, and you should not repeat yourself.

I, and I think most developers today, agree with every point made here.

Back to underscore prefixes and why I don't like them. Just like how Hungarian notation denotes the type of a variable, which is pointless for all the reasons mentioned above, I see no reason why denoting the accessibility modifier using a prefix for the name makes any more sense than denoting its type.

The compiler already stops you from accessing something that the access modifier already said you shouldn't be able to access, so there's no added gain from making sure the developer explicitly acknowledges at every turn that he knows this is a private field.

25
  • 1
    In C#, interfaces are usually prefixed with I, exception types are suffixed with Exception, async methods are suffixed with Async, generic parameters are prefixed with T. In MVC, classes are invariably XxxController, XxxView etc. Hungarian notation is everywhere. You are therefore clutching at straws with your arguments about _ for fields. And it's worth pointing out it has nothing to do with accessibility. Fields are typically expected to be private; the _ denotes it's a field rather than a parameter or local variable.
    – David Arno
    Commented Sep 28, 2021 at 14:17
  • 3
    @DavidArno: I don't think it's clutching at straws to simply argue that not everything should be baked into the method/field/variable/prop name. It's not all or nothing. The I is due to the high likelihood that an interface and its implementation (in DI) often don't differ in name, and it's shorter than xxxInterface. Same argument goes for T, it's merely a shortening of something that actually contributes meaningfully. I personally think the Async suffix should only be used when both sync and async options are available, to keep the signatures equivalent barring Async as suffix.
    – Flater
    Commented Sep 28, 2021 at 14:32
  • 1
    @JimmyJames: "A one-to-one relationship between a class and an interface suggests that the interface may not be necessary." Therein lies the rub. In a DI context, interfaces are pretty much default, with often the only second implementation being a mocked implementation (which is named differently, usually MockedFoo : IFoo compared to Foo : IFoo) for the purpose of tests. In those "one real implementation" cases, the interface and its real implementation are nigh indistinguishable, and having to come up with two names for what is essentially the same thing detracts from readability.
    – Flater
    Commented Sep 30, 2021 at 15:10
  • 1
    @JimmyJames Arguments against the I prefix which lean on "If DI frameworks were different" or "if C# was different" actually do the opposite - they reinforce the need for it because DI frameworks and the C# language are in fact, the way they are. I agree that in the hypothetical scenario you described we wouldn't need this obvious Hungarian notation that carried over from the COM days, but we code in the real world, so we do need it. Commented Oct 3, 2021 at 7:05
  • 1
    @JimmyJames: FooImpl (implementation of Foo) and IFoo (interface of Foo) sound like they're alternate equal solutions (one of them has to give) and I don't quite see why one would be worse than the other. Interfaces cannot meaningfully exist without a concrete implementation as they are abstract, so giving the "real" name to the concrete thing makes sense to me, as interfaces are an addition and thus adjust their name based on what was there already.
    – Flater
    Commented Oct 3, 2021 at 14:03
2

The question of naming conventions is really opinion based. However, here are a couple of things closely related to your question that are worth discussing.


On a more general note, general "industry standard" naming conventions and coding styles (and tools such as various linters, etc.) should be secondary to the needs of you and your team, to the way you think about your problem domain, to your needs to express concepts in your design of actual code, and to the specific considerations you as a team have with respect to things like overall skill level, onboarding process, turnover rate, etc.

Following an "industry standard" naming convention (or project/folder structure) is not "more professional" (or less professional) then not doing so - it all depends on how much it actually benefits you. Everything is a tradeoff. You don't have to use Microsoft's recommendations as they are - sure, use them as a starting point, but you should adjust them as the need arises. Not doing so can even be detrimental. You are not Microsoft, you are not facing the same needs, challenges and constraints as they are.

For example, following an externally imposed set of rules too strictly might make important concepts in your code hidden and force you to do mental gymnastics, translating between the way you think about the problem, and the way you express it in your codebase. "The industry" is not going to read your code (even if you put it on GitHub), so don't write it for "the industry", that's not your audience. That's too broad to be useful. Write it to be understandable for your team, and people who might join your team. People who are steeped in the specific problem domain you're dealing with, or are prepared to learn about it. A group of people who have their specific way of working and thinking and tackling problems. If you're writing a library for others to use, write the external API to be understandable to the target audience, and write the internals to make sense (perhaps after reading some documentation) to people who already have some idea about this problem domain.

This gives you freedom both to express ideas and concepts in code more clearly, and to structure/design your code so that it's easier to work with and maintain. Following strictly a set of rules that's not necessarily well-suited for your needs is how, very systematically and very professionally, you get a codebase that's a tangled mess.

A project that's owned and developed by a team and a project that goes from one independent developer to another have different constraints in terms of how widely understandable / generic their code, coding style, folder structure, logical organization, etc. should be, at the expense of how far you can go beyond simple CRUD-like behavior before you run into a wall of complexity. Tradeoffs.


On a more specific note, regarding internal fields: sure, _privateField._internalField might look strange, but that just tells you that you're not used to it. You should train yourself to be able to switch to / adopt different conventions anyway. Don't pay that much attention to the specific naming convention; instead, focus more on how the specific language feature is used, on the role it plays in your code.

You've said that you've been "using the common PascalCase for internal fields" - which is fine, but it also suggests to me that you've been, perhaps, treating internal fields more or less as public.

The internal access modifier is really just a crude, coarse-grained mechanism that allows for creating a component that spans two or three related, collaborating classes. An internal field is accessible among these classes, but should be treated as encapsulated in the overall component. It's the same old principles, just at another organizational level. You might want to do this if the class-level mechanisms can't quite express what you're trying to do, or because of considerations like performance, etc.

However, when it comes to other classes in the same assembly (classes that do not belong to this small collaborating cluster), this encapsulation entirely depends on (1) programmers being able to infer its there, and (2) on programmer discipline. Having an _ as a prefix for both private and internal fields could serve as a crude workaround, a reminder that, when writing new code, you're potentially accessing a "component private" field, so that you can evaluate if such code should be refactored later on. Or it can serve as a prompt to check if there's perhaps a different way of doing the same thing that's more in line with the existing overall design.

My point is, if you adopt (or invent) a naming convention, it's a good idea to establish, as a team, some rationale behind it (or behind some of its aspects you deem relevant) that's based on the way you do work and on the needs of the project/team.

1

_myClass1._myInt = 5; just doesn't feel right to me. Maybe its because I am used to doing it other ways.

You are correct in that it doesn't feel right, because it should not. There are very few cases where internal fields are a good idea. Properties are usually a better design in general.

The argument for a _ prefix is to easily distinguish between class-fields and local variables. If this is a sufficient issue to warrant a prefix is arguable, and opinions will almost certainly differ.

The argument for static s_ or thread static t_ prefixes would have a similar reasoning. I would argue for avoiding any static mutable fields as much as possible, and that would render this style moot. But one might also argue that uncommon code should have uncommon code style to alert the reader that something special is going on.

In the end the Microsoft style guidelines are written by people, and people have opinions. These opinions might differ from that of you or your team, and you should probably listen to your team more than Microsoft. Just remember to re-evaluate your coding style guidelines as the team changes. But also consider the cost of updating the coding style of an existing code-base.

0

Pascal case has never been a recommendation for private fields, it has always been camel case. Pascal case is for properties, this already nicely prevents name clashes.

Adding _ or s_ serves no sensible purpose, it is a bad habit from the past that aligns with Hungarian notation which made a little sense in non-type-safe languages. Since C# is pretty type-safe, all that remains is ugly code.

So my guess is it was pushed by some really old C person who just could not kick the habit or by an unexperienced one who is unaware of the history.

Fortunately they do stress it is ultimately your choice to determine what makes sense:

The guidelines in this article are used by Microsoft to develop samples and documentation. They were adopted from the .NET Runtime, C# Coding Style guidelines. You can use them, or adapt them to your needs. The primary objectives are consistency and readability within your project, team, organization, or company source code.

7
  • Not just for type safety. Also for situations pre-IDE where you couldn't just hover over a variable and find out its access (or other attributes). It was a marker that a field was private, or static, which you might have wanted to know without going to find the decl. (It was used quite frequently in C++ which is pretty type-safe, and was even then (compared to the alternatives)).
    – davidbak
    Commented Sep 27, 2021 at 19:34
  • Thank you for your answer. I was moreso asking about internal fields, where I have always used PascalCase in the past, instead of _camelCase.
    – Evorlor
    Commented Sep 27, 2021 at 20:30
  • Sorry but I have to downvote this as it is factually incorrect. R# out of the box for example recommends PascalCase for static fields. It’s a very common standard as far as I was aware until now.
    – David Arno
    Commented Sep 28, 2021 at 6:10
  • @DavidArno How interesting. However, this is about C# exclusively, hence the label. Commented Sep 28, 2021 at 13:20
  • @MartinMaat, R# is ReSharper, a VS plugin that massively expands VS's C# capabilities. There's not many C# devs that I know of to be honest that haven't heard of ReSharper. So yes, this is absolutely about C# ;)
    – David Arno
    Commented Sep 28, 2021 at 14:04
0

As you already noticed, questions about naming conventions raising a lot of discussions - this answer is another prove ;)

You can approach all questions about naming by trying to understand what is the reason behind the one or another style and based on that reason decide do you want to follow or use different one.

Usage of _ prefix for private or internal members suggested to separate private member from local variable or input argument.

Notice that if you are using this. keyword to access all "internal" members, then you don't need to use _ prefix.
That why you don't feel right about usage of internal fields outside of the class object._field - same as this._field

My suggestion: do not follow naming guidelines "blindly", but use it as a template and change some conventions which not serving your or your team style of writing code.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.