Expose class attributes with accessor - c#

I don't know the correct technical terms to describe my question, so I'll give an example:
private Point _PrivateVect = new Point();
public Point Publicvect
{
get
{
return _PrivateVect;
}
set
{
_PrivateVect = value;
}
}
The problem is that if I wanted to access Publicvect.X I get the error Cannot modify the return value of 'Publicvect' because it is not a variable. Is there a way around this? Or do I just need to do Publicvect = new Point(NewX, Publicvect.Y); forever?

Yet another reason that mutable structs are evil. One workaround is to expose the dimensions as accessors for convenience:
public Point PublicX {
get {return _PrivateVect.X;}
set {_PrivateVect.X = value;}
}
public Point PublicY {
get {return _PrivateVect.Y;}
set {_PrivateVect.Y = value;}
}
But other that this; yes you would need to do the new Point(x,y) each time, since Point is a struct. When you access it via a property you get a copy of it, so if you mutate the copy and then discard the copy, you simply lose the change.

The problem you have here is that the Point type is a Value Type. So when you manipulate Pointvect.X you are really manipulating a temporary copy of the value type, which of course has no effect on the original instance.

Related

Accessing and changing structs as property vs as field

Ok, I'll start my question saying that I understand the evil behind mutable structs, but I'm working with SFML.net and using a lot of Vector2f and such structs.
What I don't get it is why I can have, and change the values of, a field in a class and can't do the same with a property, in the very same class.
Take a look at this code:
using System;
namespace Test
{
public struct TestStruct
{
public string Value;
}
class Program
{
TestStruct structA;
TestStruct structB { get; set; }
static void Main(string[] args)
{
Program program = new Program();
// This Works
program.structA.Value = "Test A";
// This fails with the following error:
// Cannot modify the return value of 'Test.Program.structB'
// because it is not a variable
//program.structB.Value = "Test B";
TestStruct copy = program.structB;
copy.Value = "Test B";
Console.WriteLine(program.structA.Value); // "Test A"
Console.WriteLine(program.structB.Value); // Empty, as expected
}
}
}
note: I'll build my own classes to cover the same functionality and keep with my mutability, but I can't see a technical reason why I can do one and can't do other.
When you access a field, you are accessing the actual struct. When you access it through property, you call a method that returns whatever is stored in the property. In the case of a struct, which is a value type, you will get back a copy of the struct. Apparently that copy is not a variable and cannot be changed.
Section "1.7 Structs" of the C# language specification 5.0 says:
With classes, it is possible for two variables to reference the same
object and thus possible for operations on one variable to affect the
object referenced by the other variable. With structs, the variables
each have their own copy of the data, and it is not possible for
operations on one to affect the other.
That explains that you will receive a copy of the struct and not be able to modify the original struct. However, it doesn't describe why it isn't allowed.
Section "11.3.3" of the specifcation:
When a property or indexer of a struct is the target of an assignment,
the instance expression associated with the property or indexer access
must be classified as a variable. If the instance expression is
classified as a value, a compile-time error occurs. This is described
in further detail in ยง7.17.1.
So the returned "thing" from the get accessor is a value and not a variable. That explains the wording in the error message.
The specification also contains an example in section 7.17.1 that is nearly identical to your code:
Given the declarations:
struct Point
{
int x, y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
public int X {
get { return x; }
set { x = value; }
}
public int Y {
get { return y; }
set { y = value; }
}
}
struct Rectangle
{
Point a, b;
public Rectangle(Point a, Point b) {
this.a = a;
this.b = b;
}
public Point A {
get { return a; }
set { a = value; }
}
public Point B {
get { return b; }
set { b = value; }
}
}
in the example
Point p = new Point();
p.X = 100;
p.Y = 100;
Rectangle r = new Rectangle();
r.A = new Point(10, 10);
r.B = p;
the assignments to p.X, p.Y, r.A, and r.B are permitted because p and r are variables. However, in the example
Rectangle r = new Rectangle();
r.A.X = 10;
r.A.Y = 10;
r.B.X = 100;
r.B.Y = 100;
the assignments are all invalid, since r.A and r.B are not variables.
Although properties look like variables, each property is really a combination of a get method and/or a set method. Typically a property get method will return a copy of what's in some variable or array slot, and a put method will copy its parameter into that variable or array slot. If one wants to do something like someVariable = someObject.someProeprty; or someobject.someProperty = someVariable;, it won't matter that those statements end up being executed as var temp=someObject.somePropertyBackingField; someVariable=temp; and var temp=someVariable; someObject.somePropertyBackingField=temp;, respectively. On the other hand, there are some operations which can be done with fields but cannot be done with properties.
If an object George exposes a field named Field1, then code may pass George.Field as a ref or out parameter to another method. Additionally, if the type of Field1 is a value type with exposed fields, then an attempt to access those fields will access the fields of the struct that is stored within George. If Field1 has exposed properties or methods, then accessing those will cause George.Field1 to be passed to those methods as though it were a ref parameter.
If George exposes a property named Property1, then an access of Property1 which is not the left side of an assignment operator will call the "get" method and store its result in a temporary variable. An attempt to read a field of Property1 will read that field from the temporary variable. An attempt to call a property getter or method on Property1 will pass that temporary variable as a ref parameter to that method and then discard it after the method returns. Within the method or property getter or method, this will refer to the temporary variable, and any changes the method makes to this will be discarded.
Because it would make no sense to write to fields of a temporary variable, attempts to write to fields of a property are forbidden. Additionally, present versions of the C# compiler will guess that property setters would be likely to modify this and will thus forbid any use of property setters even when they would in fact not modify the underlying structure [e.g. the reason ArraySegment includes an indexed get method and not an indexed set method is that if one were to try to say e.g. thing.theArraySegment[3] = 4; the compiler would think one was trying to trying to modify the structure returned by the theArraySegment property, rather than modify the array whose reference is encapsulated therein]. It would be extremely useful if one could specify that particular structure methods will modify this and should not be invokable on structure properties, but as yet no mechanism exists for that.
If one wants to write to a field contained within a property, the best pattern is usually:
var temp = myThing.myProperty; // Assume `temp` is a coordinate-point structure
temp.X += 5;
myThing.myProperty = temp;
If the type of myProperty is designed to encapsulate a fixed set of related but independent values (such as the coordinates of a point), it's best if it exposes those variables as fields. Although some people seem to prefer to design structs so as to require constructs like:
var temp = myThing.myProperty; // Assume `temp` is some kind of XNA Point structure
myThing.myProperty = new CoordinatePoint(temp.X+5, temp.Y);
I would regard such code as less readable, less efficient, and more error-prone than the previous style. Among other things, if CoordinatePoint happens to e.g. expose a constructor with parameters X,Y,Z as well as a constructor which takes parameters X,Y and assumes Z is zero, code like the second form would zero out Z without any indication that it was doing so (intentionally or unintentionally). By contrast, if X is an exposed field, it's much clearer that the first form would only modify X.
In some cases, it may be helpful for a class to expose an internal field or array slot via a method that passes it as a ref parameter to a user-defined routine, e.g. a List<T>-like class might expose:
delegate void ActByRef<T1>(ref T1 p1);
delegate void ActByRef<T1,T2>(ref T1 p1, ref T2 p2);
void ActOnItem(int index, ActByRef<T> proc)
{
proc(ref BackingArray[index]);
}
void ActOnItem<PT>(int index, ActByRef<T,PT> proc, ref PT extraParam)
{
proc(ref BackingArray[index], ref extraParam);
}
Code which had a FancyList<CoordinatePoint> and wanted to add some local variable dx to field X of item 5 in iit could then do:
myList.ActOnItem(5, (ref Point pt, ref int ddx) => pt.X += ddx, ref dx);
Note that this approach would allow in-place modification of data in the list, and even allow the use of such methods as Interlocked.CompareExchange). Unfortunately, there's no possible mechanism by which a type which derives from List<T> can support such a method, and no mechanism by which a type which does support such a method can be passed to code which expects a List<T>.

C# Public variables in a class

I have a class which has a 2D jagged array declared in it's constructor, and in that class I have two methods called GetXY and SetXY, that modify said array.
However, I am unsure whether I should use these methods or in fact declare the grid as public, meaning there would be 2 ways of setting and reading values in the array, like this:
ProceduralGrid pg = new ProceduralGrid(10, 10);
pg.grid[0][0] = 2;
pg.SetXY(0, 0, 2);
Which one shall I use, and why?
Why not use
public T this[int x, int y]
{
get
{
return grid[x][y];
}
set
{
grid[x][y] = value;
}
}
Naturally check for valid x and y etc...
Use methods to access the array. Either SetXY or an indexer as suggested be Alessandro. That way, you can later change the implementation without changing your class interface.
It is best to use methods to set variables that are used inernally.
This way you can protect your inner object and are free to implement extra validation or modify the object as required.
This allows you to easily change the behaviour of that object later on.

How can I get the default value of a field in a class in C#?

Say I have my class, and I have the non-static variable
int x = 5;
After the code runs x is changed to something else, how can I get the value x started with using reflection?
Short answer: you can't.
If you implement some kind of custom transactional system, than it is possible. Out of the box: no luck.
And yes, the custom transactional system can be very simple: add another field or property that you use to 'remember' the initial value.
if i understand you correctly you want the initial value of the x.
for that you need another member or parameter to keep the first initializing of x. for example in your class:
int FirstX = -1;// or any other value you know ain't gonna come
bool firstInitial = true;
public int X
{
set
{
if(firstInitial)
{
FirstX = value;
firstInitial = false;
}
x = value
}
}
Now if you mean default value that is set at class level, you already know as it is constant other way would be creating an instance of the class for which you need default value.
ClassName className= new ClassName();
className.MyProp//This will always give default value.
new ClassName().MyProp //would also do.
If you want list of transactional values you need to implement it, reflection is not meant for that.

Cant set control.Location.x to argumentEvent e.x

I am trying to set the location of the control after some event based on the location of EventArg pictureBox1.Location.X = e.X;.
However this does not work it Cannot Modify expression because it is not a variable. But i was under the impression that x coordinate is a property and can be set. What is going on here ?
Because System.Drawing.Point is a value type, when you call pictureBox1.Location, you are actually getting a copy of the Point. A whole new object is constructed and filled with the fields of pictureBox1.Location.
As such, the compiler is trying to protect you from doing something silly, as changing the value of the copy would not propagate to the value of Location.
As such, and as mentioned in the other answers, you should construct a new Point and assign it to the Location property.
Try this instead:
pictureBox1.Location = new Point(e.X, pictureBox.Location.Y);
or if you don't want to construct a new variable:
Point location = pictureBox1.Location;
location.X = e.X;
pictureBox1.Location = location;
This is because Point is a value type, and therefore you can't just edit one of its values, as it won't propagate. Its value is stored, not a reference to the value. You can't just edit it, you need to build the object again. This could compile, but it would do absolutely nothing, in no possible scenario, so the compiler makes sure you don't do this error.
Some people here talk about Point is a value type and you can't change its X and Y, that kind of explanation can confuse you much. I post this answer here to help you understand why you can't change it's Location. That's because Location is a Property which returns a Structure not a reference to an Object, if you have a field instead, you can change that way, like this:
public class YourControl : BaseControl {
public Point Location;
}
//Then you can change the Location your way:
yourControl.Location.X = ....
However, as I said, Location is a Property which returns a copy of a value type (structure), like this:
public class YourControl : BaseControl {
private Point location;
public Point Location {
get {
return location;//a copy
}
set {
location = value;
}
}
}
//So when you call this:
yourControl.Location
//you will get a copy of your Location, and any changes made on this copy won't affect
//the actual structure, the compiler needs to prevent doing so.
yourControl.Location.X = ... //Should not be executed...
This is not the only case for Location, you can find this issue in all other Properties which are value types.

How do I ensure the value of property for others that are dependent upon it?

I have a property like so:
private Decimal _payout;
public Decimal PayoutValue
{
get { return _payout; }
set
{
_payout = value;
//second part of following conditional is an enum
if (Math.Abs(value) > 1 && this.PayoutType == CutType.Percent)
{
_payout /= 100;
}
}
}
As you can see, it is dependent upon the value of PayoutType, which is just a simple enum property:
public CutType PayoutType { get; set; }
My problem is that PayoutType doesn't seem to get set before PayoutValue is set, so the conditional below is never true. How do I force the PayoutType to be set before PayoutValue is evaluated?
Thanks.
UPDATE Thanks for your answers guys. I guess I should have mentioned that most of the time this object is bound via DataContexts or from an Http.Post from my client side (MVC project), so I don't really have any constructors. Is there any other way, or should I start getting creative with my programming?
How do I force the PayoutType to be set before PayoutValue is evaluated?
Put it in the constructor. That's the only way to enforce this rule.
That being said, I would recommend against this, at least in your implementation above. Your current property implementation will be very, very confusing to users. People tend to expect that setting a property, then immediately fetching it will provide the same value.
In your case, though:
decimal value = 45.3;
myObject.PayoutValue = value; // Set this
if (myObject.PayoutValue != value)
{
// This would normally be a very unexpected case! In your example, it will always be true!
}
It would be much better to potentially use two properties, or a method (ie: SetPayoutValue(decimal value)) to clue the user into the fact that it's not acting like a simple property.
How about this ?
get
{
if (Math.Abs(value) > 1 && this.PayoutType == CutType.Percent)
{
return _payout /100;
}
return _payout;
}
set{_payout = value;}
So that you do not change the value that was set.
All "required" properties should be in the constructor of your class.

Categories