> YMMV as you say, but I think that your needs are very specific if that's your base principle.

Not really. This is for a very large web-based medical practice-management system and tertiary services. It mostly sits on top of stripped-back ASP.NET, but yes it's a framework I developed myself because 9 years ago when this project started ASP.NET was awful.

So yeah, whilst it's non-standard, it's not rocket science, or some bizarre parallel C# universe. I still need to get data from the server to the client in an efficient way, I still have controllers, server pages, database CRUD, etc.

> Objects in C# are mutable by design

Objects are mutable by default, but there also exists a keyword called readonly which has been there since v1.0 of C#, so I would argue that it's just as much of a language feature. It not being the default doesn't make it any less of a valid approach. One of the most used library types is immutable: String.

> It sounds like your approach is closer to functional programming (but again, I don't know the context)

I try to follow that route, yes. Clearly it's not always possible because of the limitations of the language or the .NET framework, and that's fine, I'm not going to be dogmatic over it. I think however that immutability where possible helps code quality overall.

> Fields an properties are incompatible? How?
> See http://csharpindepth.com/articles/chapter8/propertiesmatter..... - "Compatibility issues".

That's very interesting, but none of those are really issues for me, and I'd argue they'd be minor issues for most people too:

> You lose binary compatibility

We always compile from source

> You can use a field for ref parameters, whereas you can't (in C# at least) use a property in the same way.

Ref fields are nasty, I wouldn't want to see anyone on my team using them. obviously passing a readonly field to a ref is pretty pointless. So non-issue for me.

> Involving a mutable structs

Don't use mutable structs.

> You lose reflection compatibility

Call GetFields instead of GetProperties. Non-issue internally. I guess if a 3rd party lib didn't support fields then it might be a problem, so far it hasn't been.

> Achievable with properties (with private setter), so I wouldn't count it as a benefit.

No it isn't, because the method you called could call a method on the object you passed, affecting the underlying state of the object. If you work on small code-bases and you understand the implications of every function you call then great, but the added peace of mind knowing that this structure you passed to a method isn't going to be changed (now or by a programmer in the future) is very powerful.

It's also makes method signatures tell you explicitly the behaviour of the code within, which makes it easier to look at the surface of a library to know what it does, i.e.:

MutableState state = new MutableState(...);
MutableLib.DoSomething(state);
// ... any code run after DoSomething is now flying-blind, has state changed?

public class MutableLib
{
public static void DoSomething(MutableState state)
{
// What happens here? Does MutableState get changed? How can you know when the
// method returns 'void' and takes a mutable object? You have to look at the code
// to know for sure.
}
}

Then the immutable version. Notice how the signature to DoSomething is explicit in its purpose.

ImmutableState state = new ImmutableState(...);
var newState = ImmutableLib.DoSomething(state);
// ... any code run after DoSomething is entirely aware that state has changed

public static class ImmutableLib
{
public static ImmutableState DoSomething(ImmutableState state)
{
// What happens here? Well it doesn't matter to the caller, they know
// they get a new ImmutableState back, and if they chose to ignore it
// then the original state object they passed in will be unaltered.
}
}

It also allows for free transactional behaviour with rollbacks, which can be super useful:

ImmutableState state = new ImmutableState(...);
try
{
var newState = ImmutableLib.DoSomething(state);
newState = ImmutableLib.DoSomethingElse(newState);
newState = ImmutableLib.DoAnotherThing(newState);

// Commit
state = newState;
}
catch
{
// If an exception fires then state won't have changed.
}

> I see where you're coming from, but to me you are pointing out the advantages of immutability, not choosing fields over properties.

You're right that I'm primarily arguing for immutability, but I would also argue that properties can't achieve immutability because the object can always change itself. A private property can always be changed by a member function. Clearly you can make classes that are immutable for all intents and purposes by using properties; I just prefer the explicit nature of 'readonly' - it's a language feature to be used in my humble opinion.

There's also the argument that properties are an extra unnecessary abstraction for this case. With a readonly field/property it is only set once, so having a layer of getter/setter logic is unnecessary. You only need that logic once at construction.