C
C#13mo ago
cow

Is there a way to ensure a function can't modify a parameter?

I often want to pass objects or values into a function, and make sure the function cannot change it... is it possible? Example scenario:
public void UpdateUserAge() {
var user = _dbContext.Users.Find(4);
user.Age = 111;

// How to make sure WriteUserLog can not modify user?
WriteUserLog(user);

_dbContext.SaveChanges()
]


private void WriteUserLog(UserEntity user) //can this parameter be made readonly somehow?
{
user.Name = "Shouldnt be able to change this";
Console.WriteLine($"User {user.Age} was changed")
}
public void UpdateUserAge() {
var user = _dbContext.Users.Find(4);
user.Age = 111;

// How to make sure WriteUserLog can not modify user?
WriteUserLog(user);

_dbContext.SaveChanges()
]


private void WriteUserLog(UserEntity user) //can this parameter be made readonly somehow?
{
user.Name = "Shouldnt be able to change this";
Console.WriteLine($"User {user.Age} was changed")
}
14 Replies
Moods
Moods13mo ago
Indeeeed With the in keyword
Moods
Moods13mo ago
Unless I misread your question That post answers it
cow
cowOP13mo ago
I was reading this microsoft blog about the in keyword, and it seems to say it should only ever be used with readonly structs? https://devblogs.microsoft.com/premier-developer/the-in-modifier-and-the-readonly-structs-in-c/ if that still applied in later c#, kinda sounds a limited use-case?
Kiel
Kiel13mo ago
you could make your methods accept a base, readonly interface instead of a concrete implementation or make your concrete class have { get; init; } instead of { get; set; } on properties you don't want to be mutable
interface IUserEntity
{
int Age { get; }
}

class UserEntity : IUserEntity
{
public int Age { get; set; }
}

// elsewhere...
private void WriteUserLog(IUserEntity user)
{
user.Age = 111; // compile-time error!
Console.WriteLinte($"User {user.Age} was changed.");
}
interface IUserEntity
{
int Age { get; }
}

class UserEntity : IUserEntity
{
public int Age { get; set; }
}

// elsewhere...
private void WriteUserLog(IUserEntity user)
{
user.Age = 111; // compile-time error!
Console.WriteLinte($"User {user.Age} was changed.");
}
C# doesn't have a parameter keyword like const (C++) or final (Java) to say "hey, this parameter is immutable don't do anything with it but read its values"...yet
cow
cowOP13mo ago
Thanks yeah, I was hoping there was a parameter keyword, but thank you for confirming there isn't one yet because I thought I just wasn't searching for the right words i see c# 12 has ref readonly is that the same thing?
Kiel
Kiel13mo ago
i don't see any references to it other than primitives or structs, so it might not be applicable for reference types/classes
Kiel
Kiel13mo ago
https://dotnetfiddle.net/mYkm22 the user's age is still mutable even with ref readonly or in, so I think the readonly interface approach is your only option
UserTest | C# Online Compiler | .NET Fiddle
UserTest | Test your C# code online with .NET Fiddle code editor.
Kiel
Kiel13mo ago
it seems both in (and the new ref readonly) only accomplish your goal if the type is a struct or value type, unfortunately
jcotton42
jcotton4213mo ago
readonly params are planned iirc, but not in yet $languagefeaturestatus
MODiX
MODiX13mo ago
You can see the features the team is currently working on here: https://github.com/dotnet/roslyn/blob/main/docs/Language%20Feature%20Status.md
Aaron
Aaron13mo ago
they still wouldn't work for classes
cow
cowOP12mo ago
follow up question.... am i wrong for wanting this? Like... is it a sign I'm doing something wrong? Bad pattern perhaps?
Kiel
Kiel12mo ago
I personally find it unnecessary if you're the one writing the methods. If you were making a publicly consumable API or something and you wanted overridden members to ensure that state isn't changed for objects passed in, that's one thing....but if you're the one writing the methods, is your goal to just remind yourself (or your team) to not mutate state? I think there's no downside to a language feature that says "hey, this method is meant to read state, not change state" it's already a feature, but only for non-reference types lol
Want results from more Discord servers?
Add your server