Why is this method Impure? - c#

I read this answer: https://stackoverflow.com/a/9928643/16241
But I obviously don't understand it because I can't figure out why my method is impure. (The method in question is ToExactLocation()).
public struct ScreenLocation
{
public ScreenLocation(int x, int y):this()
{
X = x;
Y = y;
}
public int X { get; set; }
public int Y { get; set; }
public ExactLocation ToExactLocation()
{
return new ExactLocation {X = this.X, Y = this.Y};
}
// Other stuff
}
Incase you need it here is the exact location struct:
public struct ExactLocation
{
public double X { get; set; }
public double Y { get; set; }
// Various Operator Overloads, but no constructor
}
And this is how I call it:
someScreenLocation = MethodThatGivesAScreenLocation();
if (DestinationLocation == someScreenLocation.ToExactLocation())
{
// Do stuff
}
When I do that, ReSharper flags it with "Impure Method is called for readonly field of value type."
Why is it saying that? And what can I do to make it go away?

It's not pure because it does not return a value dependent only on its input. When the value of X or Y changes so does the return value of ToExactLocation, i.e., its output depends on internal, mutable state.
Additionally, the setters for X or Y in ExactLocation may mutate the input. The getters of ScreenLocation may as well.
someScreenLocation is a readonly field and is a value type. You are calling ToExactLocation on a value, i.e., a readonly field. When you access a reaodnly value type a copy is created as to avoid mutating the value itself. However, your call may mutate that value, which, in many cases, is not what you want as you will be mutating a copy. This is why you get a warning.
In this case, you can ignore it, but I would avoid mutable value types in general.
EDIT:
Let me attempt to simplify...
struct Point
{
int X;
int Y;
bool Mutate() { X++; Y++; }
}
class Foo
{
public readonly Point P;
Foo()
{
P = new Point();
P.Mutate(); // impure function on readonly value type
}
}
When Mutate() is called, a copy of P is created and passed along with the method. Any mutation of P's internal state will be irrelevant as it mutates a copy.

One of the conditions of a Pure Method is that its output (return value) is wholly dependent on its input (arguments).
Your .ToExactLocation() method is not pure, because its output depends both on the input arguments and also on the current value of a mutable struct.
Resharper doesn't like this, because mutable structs are bad (don't use them). I expect the error would go away if you either changed your code to use a class instead of a struct or redesigned the struct so the the .X and .Y members could only be set by the constructor.

Reading the answer, I found out that pure functions are necessarily like functions in mathematics. f(x) = x^2 + 2x + 10 will always return 10 if x is 0.
So ToExactLocation() must return the same values each time it is called, regardless changes to object since initial creation, for it to be called "pure".

There are 2 meaning of "pure function": one theoretical (no side effects/no dependency on mutable state) and another is what ReSharper thinks about functions.
From theoretical point of view your function is not pure because it depends on mutable state. Sample:
var someScreenLocation = new ScreenLocation(1,1);
var locationOne = someScreenLocation.ToExactLocation();
var locationTwo = someScreenLocation.ToExactLocation();
someScreenLocation.X = 3;
var locationThree = someScreenLocation.ToExactLocation();
For method to be pure it can change its result only based on input (not at all as in this case since there is no arguments). But you can clearly observe that locationOne and locationTwo are the same (good sign so far), but unfortunately locationThree is different even if the input (arguments to the function) still the same.
You can make it theoretically pure by making X and Y readonly (and adding constructor).
Even after the change ReSharper will still think it is not pure - to convince it you can use Pure attribute to mark it as pure.
Note that ReSharper marks usage of "impure" functions even in constructor of the class with readonly field. Sample below shows ReSharper warnings:
struct Point
{
public int X;
public int Y;
public Point(int x, int y){X = x;Y = y;}
public void Mutate(){X++;}
public Point TheoreticallyPure(){return new Point(1, 1);}
[Pure] public Point MarkedPure(){ return new Point(1, 1);}
}
class WithReadonlyField
{
public readonly Point P;
public WithReadonlyField()
{
P = new Point();
P.TheoreticallyPure(); // impure function on readonly value type
P.MarkedPure(); // return value of pure not used
P.Mutate(); // impure function on readonly value type - modifies P.
P = new Point().MarkedPure(); // ok to modify P multiple times.
}
public void NormalMethod()
{
P.Mutate(); // impure function on readonly value type, no changes to P
}
}
C# allows modification of readonly fields up to the end of constructor, but ReSharper marks usages of all "impure" functions there too (Note that Mutate function in constructor actually changes value of readonly field P, unlike in NormalMethod where it has no effect).
"readonly... assignments to the fields introduced by the declaration can only occur as part of the declaration or in a constructor in the same class"
Most likely this behavior of ReSharper is for consistency and to avoid cases where moving perfectly valid code changes behavior completely.

It would be better to model this as a static method (on either class) and would get rid of the impure warning. Explanation omitted, as the other answers covers the why already.
Example:
public static ExactLocation ToExactLocation(ScreenLocation loc)
{
return new ExactLocation {X = loc.X, Y = loc.Y};
}
or use an extension method
public static ExactLocation ToExactLocation(this ScreenLocation loc)
{
return new ExactLocation {X = loc.X, Y = loc.Y};
}

Not really sure about the cause, and I'd put this as a comment if it would format correctly...
Wouldn't you want something like:
var someScreenLocation = MethodThatGivesAScreenLocation();
if (DestinationLocation.X == someScreenLocation.ToExactLocation().X &&
DestinationLocation.Y == someScreenLocation.ToExactLocation().Y)
{
// Do stuff
}

Related

Unable to assign value to a textbox property in c# [duplicate]

I'm using auto-implemented properties.
I guess the fastest way to fix following is to declare my own backing variable?
public Point Origin { get; set; }
Origin.X = 10; // fails with CS1612
Error Message: Cannot modify the return value of 'expression' because
it is not a variable
An attempt was made to modify a value type that was the result of an
intermediate expression. Because the value is not persisted, the value
will be unchanged.
To resolve this error, store the result of the expression in an
intermediate value, or use a reference type for the intermediate
expression.
This is because Point is a value type (struct).
Because of this, when you access the Origin property you're accessing a copy of the value held by the class, not the value itself as you would with a reference type (class), so if you set the X property on it then you're setting the property on the copy and then discarding it, leaving the original value unchanged. This probably isn't what you intended, which is why the compiler is warning you about it.
If you want to change just the X value, you need to do something like this:
Origin = new Point(10, Origin.Y);
Using a backing variable won't help. The Point type is a Value type.
You need to assign the whole Point value to the Origin property:-
Origin = new Point(10, Origin.Y);
The problem is that when you access the Origin property what is returned by the get is a copy of the Point structure in the Origin properties auto-created field. Hence your modification of the X field this copy would not affect the underlying field. The compiler detects this and gives you an error since this operation is entirely useless.
Even if you used your own backing variable your get would look like:-
get { return myOrigin; }
You'd still be returning a copy of the Point structure and you'd get the same error.
Hmm... having read your question more carefully perhaps you actually mean to modify the backing variable directly from within your class:-
myOrigin.X = 10;
Yes that would be what you would need.
By now you already know what the source of the error is. In case a constructor doesn't exist with an overload to take your property (in this case X), you can use the object initializer (which will do all the magic behind the scenes). Not that you need not make your structs immutable, but just giving additional info:
struct Point
{
public int X { get; set; }
public int Y { get; set; }
}
class MyClass
{
public Point Origin { get; set; }
}
MyClass c = new MyClass();
c.Origin.X = 23; //fails.
//but you could do:
c.Origin = new Point { X = 23, Y = c.Origin.Y }; //though you are invoking default constructor
//instead of
c.Origin = new Point(23, c.Origin.Y); //in case there is no constructor like this.
This is possible because behind the scenes this happens:
Point tmp = new Point();
tmp.X = 23;
tmp.Y = Origin.Y;
c.Origin = tmp;
This looks like a very odd thing to do, not at all recommended. Just listing an alternate way. The better way to do is make struct immutable and provide a proper constructor.
I think a lot of people are getting confused here, this particular issue is related to understanding that value type properties return a copy of the value type (as with methods and indexers), and value type fields are accessed directly. The following code does exactly what you are trying to achieve by accessing the property's backing field directly (note: expressing a property in its verbose form with a backing field is the equivalent of an auto property, but has the advantage that in our code we can access the backing field directly):
class Program
{
static void Main(string[] args)
{
var myClass = new MyClass();
myClass.SetOrigin();
Debug.Assert(myClass.Origin.X == 10); //succeeds
}
}
class MyClass
{
private Point _origin;
public Point Origin
{
get => _origin;
set => _origin = value;
}
public void SetOrigin()
{
_origin.X = 10; //this works
//Origin.X = 10; // fails with CS1612;
}
}
The error you are getting is an indirect consequence of not understanding that a property returns a copy of a value type. If you are returned a copy of a value type and you do not assign it to a local variable then any changes you make to that copy can never be read and therefore the compiler raises this as an error since this cannot be intentional. If we do assign the copy to a local variable then we can change the value of X, but it will only be changed on the local copy, which fixes the compile time error, but will not have the desired effect of modifiying the Origin property. The following code illustrates this, since the compilation error is gone, but the debug assertion will fail:
class Program
{
static void Main(string[] args)
{
var myClass = new MyClass();
myClass.SetOrigin();
Debug.Assert(myClass.Origin.X == 10); //throws error
}
}
class MyClass
{
private Point _origin;
public Point Origin
{
get => _origin;
set => _origin = value;
}
public void SetOrigin()
{
var origin = Origin;
origin.X = 10; //this is only changing the value of the local copy
}
}
Aside from debating the pros and cons of structs versus classes, I tend to look at the goal and approach the problem from that perspective.
That being said, if you don't need to write code behind the property get and set methods (as in your example), then would it not be easier to simply declare the Origin as a field of the class rather than a property? I should think this would allow you to accomplish your goal.
struct Point
{
public int X { get; set; }
public int Y { get; set; }
}
class MyClass
{
public Point Origin;
}
MyClass c = new MyClass();
c.Origin.X = 23; // No error. Sets X just fine
The problem is that you point to a value located on the stack and the value will not be relfected back to the orignal property so C# does not allow you to return a reference to a value type. I think you can solve this by removing the Origin property and instead use a public filed, yes I know it's not a nice solution. The other solution is to not use the Point, and instead create your own Point type as an object.
I guess the catch here is that you are trying to assign object's sub-values in the statement rather than assigning the object itself. You need to assign the entire Point object in this case as the property type is Point.
Point newOrigin = new Point(10, 10);
Origin = newOrigin;
Hope I made sense there
Just remove the property "get set" as follow, and then everything works as always.
In case of primitive types instread use the get;set;...
using Microsoft.Xna.Framework;
using System;
namespace DL
{
[Serializable()]
public class CameraProperty
{
#region [READONLY PROPERTIES]
public static readonly string CameraPropertyVersion = "v1.00";
#endregion [READONLY PROPERTIES]
/// <summary>
/// CONSTRUCTOR
/// </summary>
public CameraProperty() {
// INIT
Scrolling = 0f;
CameraPos = new Vector2(0f, 0f);
}
#region [PROPERTIES]
/// <summary>
/// Scrolling
/// </summary>
public float Scrolling { get; set; }
/// <summary>
/// Position of the camera
/// </summary>
public Vector2 CameraPos;
// instead of: public Vector2 CameraPos { get; set; }
#endregion [PROPERTIES]
}
}

With a struct that is a property, what is the standard for updating a value in the struct?

I'm new to C#, and I'm working with a class that has a Rectangle field. I've read that Properties are the most accepted way to declare public fields, so I tried something like this:
public class MyClass
{
public Rectangle MyBox { get; set; }
public UpdateBox(int x, int y)
{
MyBox.X = x;
MyBox.Y = y;
}
}
It won't let me do MyBox.X = x because (from what I've read), Rectangle is a struct, and the getter returns a copy of the Rectangle, so I would not be modifying the value I want.
What is the standard for updating fields like this? I've found two solutions so far:
Creating a new Rectangle to store in the variable:
public class MyClass
{
public Rectangle MyBox { get; set; }
public UpdateBox(int x, int y)
{
MyBox = new Rectangle(x, y, MyBox.Width, MyBox.Height);
}
}
but this seems like it would not be very memory efficient. Then there is just not making Rectangle a property:
public class MyClass
{
public Rectangle MyBox;
public UpdateBox(int x, int y)
{
MyBox.X = x;
MyBox.Y = y;
}
}
What is the standard for this kind of functionality?
By convention you can use a struct as a field and access its internal fields directly, if you want to use it as a property, then make a proper setter for it.
I, personally only use struct types as fields other than properties, maybe a read only property for public access (for encapsulation purposes), grants me safety and general organization of my code.
Your 3rd block of example code is the most correct form in my view, and no its not memory inefficient, Rectangle MyBox is already allocated in memory and already consuming its most by the time the constructor is called.
Also, let us keep in mind here, a property is a "shortcut" function to access some data, but if this data ought to be stored somewhere and wont likely change (default get/set accessors), then it's not any different from a normal field.
This is my favorite way of dealing with this:
public class MyClass
{
private Rectangle _MyBox; // or protected idk.
// This is public and read only.
public Rectangle MyBox { get { return _MyBox; } }
public UpdateBox(int x, int y)
{
_MyBox.X = x;
_MyBox.Y = y;
}
}
The clearest approach for non-speed-critical applications is to use the pattern:
var temp=myThing.TheProperty;
temp.X = whatever;
temp.Y = whatever;
myThing.TheProperty = temp;
If the structure behaves as a bunch of independent variables fastened together with duct tape, the above approach will avoid having to either have the client code know about all of its fields, or have the struct include lots of boilerplate WithX, WithY, etc. factory methods.
If speed is important, then one should either have structures exposed in fields or arrays [as opposed to other collection types], or--if one wants to retain encapsulation--include accessor methods:
delegate void ActionRR<T1,T2>(ref T1 p1, ref T2 p2);
void ActOnBounds<TExtra>(ref Rectangle bounds, ActionRR<Rectangle, TExtra>proc, ref TExtra extra)
{
proc(ref _bounds, ref extra);
}
Note that generating delegates to call ActOnBounds will make it slow, but it may be used efficiently by passing a static delegate and a ref valuetype. Unfortunately, while C# includes lots of nice syntactic sugar for closures, it does not provide such help with constructs like the above.

Why should we initialize a struct before passing it to a function?

Consider this code:
MyStruct j;
j.I = 3;
Console.WriteLine(j.I);
Now see this method:
public static void StructMod(MyStruct ms)
{
ms.I += 100;
Console.WriteLine(ms.I);
}
When we pass MyStruct to the method, should we initialize it before passing it? I.e.:
MyStruct j = new MyStruct()
Unless struct is value type?
Yes, it is.
First line from MSDN:
A struct type is a value type...
As with individual variables, a struct must be fully initialized before it can be used. Consider:
struct Foo
{
public int Bar;
public int Pop;
}
class Program
{
static void Main(string[] args) {
Foo f;
f.Bar = 3;
test(f); // ERROR: Use of unassigned local variable 'f'
}
static void test(Foo f) {
Console.WriteLine("{0}", f.Bar);
}
}
The solution here is to either initialize .Bar, or simply call the Foo constructor f = new Foo() which initializes all members to their default values.
This is the same logic behind the "Field ... must be fully assigned before control is returned to the caller" error that you get when adding parameterized constructors to structs.
After a little testing, it seems that either way you declare it, it's being initialized.
One reason to call new ... would be to execute code in the constructor, if any.
Take this sample from MSDN, for example:
public struct CoOrds
{
public int x, y;
public CoOrds(int p1, int p2)
{
x = p1;
y = p2;
}
}
You could just do this, and use c, but then x and y will be 0.
CoOrds c;
Alternatively, you could do this, and then x and y start off with values.
CoOrds c = new CoOrds(5,3);
(This would be more useful if the ctor did something more interesting.)
If you want the struct to have a particular value, then initialize it to that value.
If you want the struct to be initialized to its default value, then you don't need to explicitly initialize it. However, it might still be best to do so for the sake of readability if the struct's default value is non-obvious.
As a side note: Mutable structs are really bad; the entire scenario you propose in your example is a code smell. See Why are mutable structs “evil”?
The same behavior could be achieved more safely with an immutable struct like so
struct MyStruct
{
public readonly int I;
public MyStruct(int i_initial)
{
I = i_initial;
}
}
MyStruct j = new MyStruct(3);
public static void StructMod(MyStruct ms)
{
Console.WriteLine(ms.I + 100);
}
In particular, note that from the caller's point of view this function's behavior will be exactly the same as the one in the question, because structs are passed by value the same way that primitives like int are. If the "Mod" in StructMod is there because you expect this function to modify the value, then that's a good concrete example of why it's generally better for mutable types to be objects and not structs.

Error: "Cannot modify the return value" c#

I'm using auto-implemented properties.
I guess the fastest way to fix following is to declare my own backing variable?
public Point Origin { get; set; }
Origin.X = 10; // fails with CS1612
Error Message: Cannot modify the return value of 'expression' because
it is not a variable
An attempt was made to modify a value type that was the result of an
intermediate expression. Because the value is not persisted, the value
will be unchanged.
To resolve this error, store the result of the expression in an
intermediate value, or use a reference type for the intermediate
expression.
This is because Point is a value type (struct).
Because of this, when you access the Origin property you're accessing a copy of the value held by the class, not the value itself as you would with a reference type (class), so if you set the X property on it then you're setting the property on the copy and then discarding it, leaving the original value unchanged. This probably isn't what you intended, which is why the compiler is warning you about it.
If you want to change just the X value, you need to do something like this:
Origin = new Point(10, Origin.Y);
Using a backing variable won't help. The Point type is a Value type.
You need to assign the whole Point value to the Origin property:-
Origin = new Point(10, Origin.Y);
The problem is that when you access the Origin property what is returned by the get is a copy of the Point structure in the Origin properties auto-created field. Hence your modification of the X field this copy would not affect the underlying field. The compiler detects this and gives you an error since this operation is entirely useless.
Even if you used your own backing variable your get would look like:-
get { return myOrigin; }
You'd still be returning a copy of the Point structure and you'd get the same error.
Hmm... having read your question more carefully perhaps you actually mean to modify the backing variable directly from within your class:-
myOrigin.X = 10;
Yes that would be what you would need.
By now you already know what the source of the error is. In case a constructor doesn't exist with an overload to take your property (in this case X), you can use the object initializer (which will do all the magic behind the scenes). Not that you need not make your structs immutable, but just giving additional info:
struct Point
{
public int X { get; set; }
public int Y { get; set; }
}
class MyClass
{
public Point Origin { get; set; }
}
MyClass c = new MyClass();
c.Origin.X = 23; //fails.
//but you could do:
c.Origin = new Point { X = 23, Y = c.Origin.Y }; //though you are invoking default constructor
//instead of
c.Origin = new Point(23, c.Origin.Y); //in case there is no constructor like this.
This is possible because behind the scenes this happens:
Point tmp = new Point();
tmp.X = 23;
tmp.Y = Origin.Y;
c.Origin = tmp;
This looks like a very odd thing to do, not at all recommended. Just listing an alternate way. The better way to do is make struct immutable and provide a proper constructor.
I think a lot of people are getting confused here, this particular issue is related to understanding that value type properties return a copy of the value type (as with methods and indexers), and value type fields are accessed directly. The following code does exactly what you are trying to achieve by accessing the property's backing field directly (note: expressing a property in its verbose form with a backing field is the equivalent of an auto property, but has the advantage that in our code we can access the backing field directly):
class Program
{
static void Main(string[] args)
{
var myClass = new MyClass();
myClass.SetOrigin();
Debug.Assert(myClass.Origin.X == 10); //succeeds
}
}
class MyClass
{
private Point _origin;
public Point Origin
{
get => _origin;
set => _origin = value;
}
public void SetOrigin()
{
_origin.X = 10; //this works
//Origin.X = 10; // fails with CS1612;
}
}
The error you are getting is an indirect consequence of not understanding that a property returns a copy of a value type. If you are returned a copy of a value type and you do not assign it to a local variable then any changes you make to that copy can never be read and therefore the compiler raises this as an error since this cannot be intentional. If we do assign the copy to a local variable then we can change the value of X, but it will only be changed on the local copy, which fixes the compile time error, but will not have the desired effect of modifiying the Origin property. The following code illustrates this, since the compilation error is gone, but the debug assertion will fail:
class Program
{
static void Main(string[] args)
{
var myClass = new MyClass();
myClass.SetOrigin();
Debug.Assert(myClass.Origin.X == 10); //throws error
}
}
class MyClass
{
private Point _origin;
public Point Origin
{
get => _origin;
set => _origin = value;
}
public void SetOrigin()
{
var origin = Origin;
origin.X = 10; //this is only changing the value of the local copy
}
}
Aside from debating the pros and cons of structs versus classes, I tend to look at the goal and approach the problem from that perspective.
That being said, if you don't need to write code behind the property get and set methods (as in your example), then would it not be easier to simply declare the Origin as a field of the class rather than a property? I should think this would allow you to accomplish your goal.
struct Point
{
public int X { get; set; }
public int Y { get; set; }
}
class MyClass
{
public Point Origin;
}
MyClass c = new MyClass();
c.Origin.X = 23; // No error. Sets X just fine
The problem is that you point to a value located on the stack and the value will not be relfected back to the orignal property so C# does not allow you to return a reference to a value type. I think you can solve this by removing the Origin property and instead use a public filed, yes I know it's not a nice solution. The other solution is to not use the Point, and instead create your own Point type as an object.
I guess the catch here is that you are trying to assign object's sub-values in the statement rather than assigning the object itself. You need to assign the entire Point object in this case as the property type is Point.
Point newOrigin = new Point(10, 10);
Origin = newOrigin;
Hope I made sense there
Just remove the property "get set" as follow, and then everything works as always.
In case of primitive types instread use the get;set;...
using Microsoft.Xna.Framework;
using System;
namespace DL
{
[Serializable()]
public class CameraProperty
{
#region [READONLY PROPERTIES]
public static readonly string CameraPropertyVersion = "v1.00";
#endregion [READONLY PROPERTIES]
/// <summary>
/// CONSTRUCTOR
/// </summary>
public CameraProperty() {
// INIT
Scrolling = 0f;
CameraPos = new Vector2(0f, 0f);
}
#region [PROPERTIES]
/// <summary>
/// Scrolling
/// </summary>
public float Scrolling { get; set; }
/// <summary>
/// Position of the camera
/// </summary>
public Vector2 CameraPos;
// instead of: public Vector2 CameraPos { get; set; }
#endregion [PROPERTIES]
}
}

Meaning of "this" for a struct (C#)

According to MSDN (Section 11.3.6 of the C# spec):
Within an instance constructor of a
struct, this corresponds to an out
parameter of the struct type, and
within an instance function member of
a struct, this corresponds to a ref
parameter of the struct type. In both
cases, this is classified as a
variable, and it is possible to modify
the entire struct for which the
function member was invoked by
assigning to this or by passing this
as a ref or out parameter.
I don't get it. How is this different for a struct than for a class? Code examples are appreciated
Eric Lippert had a fabulous post on mutating readonly structs a while back that will really help clarify the issue for you. There's even a code example, and a quiz!
The salient point is that structs obey value semantics and classes do not and so this must mean something different for the two. this is readonly for a class, but not for a struct. The following code is legal
struct Point {
public int x;
public int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
public void DoGoTime() {
GoTime(ref this);
}
public static void GoTime(ref Point p) {
p.x = 100;
p.y = 100;
}
}
but is not if "struct" is replaced by "class."
When you're dealing with structs, you're dealing with value types.
In a class, "this" is a reference to the current instance. This lets you mutate the class instance by setting properties/fields on the class.
However, if you're in a struct, things act differently. When you're in a struct's method, "this" lets you mutate the struct. However, if you're using this in a method, you're almost always dealing with a copy of the "original" struct.
For example:
struct Test
{
int i;
void Mutate() {
this.i += 1;
}
}
When you use this:
void MutateTest(Test instance)
{
instance.Mutate();
}
{
Test test = new Test();
test.i = 3;
Console.WriteLine(test.i); // Writes 3
test.Mutate(); // test.i is now 4
Console.WriteLine(test.i); // Writes 4
MutateTest(test); // MutateTest works on a copy.. "this" is only part of the copy itself
Console.WriteLine(test.i); // Writes 4 still
}
Now, the stranger part - this is valid, and what that quote was saying:
struct Test
{
public Test(int value)
{
this.i = value;
}
int i;
void Mutate(int newValue) {
this = new Test(newValue); // This wouldn't work with classes
}
}
///
{
Test test = new Test();
test.i = 3;
Console.WriteLine(test.i); // Writes 3
test.Mutate(4);
Console.WriteLine(test.i); // Writes 4
Jason's answer and Eric's post show one aspect of this which is interesting... but there's another which is even more alarming:
You can reassign this within a method, even if the type is otherwise immutable.
To demonstrate it, we'll use a struct which is stored in a non-readonly variable, but which contains a readonly field:
using System;
public struct LooksImmutable
{
private readonly int value;
public int Value { get { return value; } }
public LooksImmutable(int value)
{
this.value = value;
}
public void GoCrazy()
{
this = new LooksImmutable(value + 1);
}
}
public class Test
{
static void Main()
{
LooksImmutable x = new LooksImmutable(5);
Console.WriteLine(x.Value);
x.GoCrazy();
Console.WriteLine(x.Value);
}
}

Categories

Resources