I'm doing a big refactor of a pile of code that used to use a bunch of multidimensional arrays that were constantly getting resized. I created a data object to replace the 2D array, and I'm now passing a list of these around.
I discovered something that worries me a little though. Let's say I have some code that looks like this:
List<NCPoint> basePoints = new List<NCPoint>();
// ... snip populating basePoints with starting data
List<NCPoint> newPoints = TransformPoints(basePoints, 1, 2, 3);
public List<NCPoint> TransformPoints(List<NCPoint> points, int foo, int bar, int baz){
foreach(NCPoint p in points){
points.X += foo
points.Y += bar
points.Z += baz
}
return points;
}
The idea is to keep a list of the original points (basePoints
) and a list of the updated points (newPoints
). But C# passes the list by reference, as with any object. This updates basePoints
in place, so now both basePoints
and newPoints
will have the same data.
At the moment, I'm trying to be careful about making a full copy of the passed-in List
before I muck with the data. Is that the only sensible way to make sure changes to an object within a function don't have side effects outside the function? Is there anything akin to passing an object with const
?
The collections returned by the convenience factory methods added in JDK 9 are conventionally immutable. Any attempt to add, set, or remove elements from these collections causes an UnsupportedOperationException to be thrown.
In Java 8 and earlier versions, we can use collection class utility methods like unmodifiableXXX to create immutable collection objects. If we need to create an immutable list then use the Collections. unmodifiableList() method.
A set is an ordered collection of objects.
util. Arrays. asList() , the list is immutable.
In short: no.
C# does not have the concept of a const
reference, per se. If you want to make an object immutable, you must code it explicitly so or take advantage of other "tricks".
You can make your collection immutable in many ways (ReadOnlyColelction
, return an iterator, return a shallow copy) but that only protects the sequence, not the data stored inside.
Thus, what you'd really need to do what you want is to return a deep copy or projection, possibly using LINQ:
public IEnumerable<NCPoint> TransformPoints(List<NCPoint> points, int foo, int bar, int baz)
{
// returning an iterator over the sequence so original list won't be changed
// and creating new NCPoint using old NCPoint + modifications so old points
// aren't altered.
return points.Select(p => new NCPoint
{
X = p.X + foo,
Y = p.Y + bar,
Z = p.Z + baz
});
}
Also, the beauty of returning an iterator (as opposed to just returning a List<T>
as an IEnumerable<T>
, etc.) is that it can't be cast back to the original collection type.
UPDATE: Or, in .NET 2.0 parlance:
public IEnumerable<NCPoint> TransformPoints(List<NCPoint> points, int foo, int bar, int baz)
{
// returning an iterator over the sequence so original list won't be changed
// and creating new NCPoint using old NCPoint + modifications so old points
// aren't altered.
NCPoint[] result = new NCPoint[points.Count];
for (int i=0; i<points.Count; ++i)
{
// if you have a "copy constructor", can use it here.
result[i] = new NCPoint();
result[i].X = points[i].X + foo;
result[i].Y = points[i].Y + bar;
result[i].Z = points[i].Z + baz;
}
return result;
}
The point is, there are many ways to treat something as immutable, but I wouldn't try to implement C++-style "const correctness" in C# or you will go mad. Implement it as needed when you want to avoid side-effects, etc.
You probabbly searching for ReadOnlyCollection
Provides the base class for a generic read-only collection.
Example:
public IEnumerable<..> GetReadonlyCollection(List<...> originalList)
{
return new ReadOnlyCollection<string>(originalList);
}
Just invite attention on one fact: that this is provides service for making readonly (immutable) a collection and not containing type. I can get an object frim that collection and change it, and if the object is reference type, those changes would have their reflection in the original collection too.
If you want to have readonly object, this becomes a little bit more tricky (depends how complex your object is). The basic idea is (suggested by Servy too) is making a wrapper over your original object with readonly public members (so for consumer of that type it becomes immutable).
Hope this helps.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With