Make value type behave as reference - c#

What is the best practice to be able to assign values to value type via "reference"? In my case I need this to give possibility to assign values to ints, floats etc through out the in-app console. I dont want to give a reference to an object containing the value type as this wont make my console manager generic, and adding new commands will be a nightmare. Also I cannot use pointers, as unsafe mode is impossible in my case.
Cause my little understanding of CLR, I tried something like this:
int i = 1;
object o = i;
o = (object) 5;
Console.WriteLine(i);// prints original value of i, 1. I expected 5;
So it didnt work, so I found this class:
using System.Collections.Generic;
using System.Collections;
using System;
public class Pointer < T >
{
private Func<T> getter;
private Action<T> setter;
public Pointer ( Func<T> getter, Action<T> setter )
{
this.getter = getter;
this.setter = setter;
}
public T Value
{
get { return getter(); }
set { setter(value); }
}
}
Thanks to it I can assign values to value types like to reference like this:
int i = 1;
Pointer ptr = new Pointer<int>(()=>i, x=>{i=x;})
ptr.Value = 5;
Console.WriteLine(i);// prints as expected 5;
Works, but as you can see it is quite not elegant way (at least I think it is not).
So the question remains. What is the best practice in cases like this?
Cheers

Official answer:
You should never expose direct access to your members. The values you want to be modifyable should be in a container object (the model). All modifications of this model should be done by one authority (the controller).
Inofficial answer:
Using reflection, you'll be able to access even value type fields and get or set their values.
If this does not help I need a clearer understanding of what you want to achieve.

It's not c# way. The simplest decision is create class with static fields and change it.

Related

Some of my class fields is required. How can i know it was initialized?

Ok guys. Im writing code and have one problem. Language is C# but it doesnot matter. For example:
I have class Point
Class Point
{
private _x;
private _y;
//getter and setters
}
So, if i want to use object of this class i need to totally know that all fields, like _x and _y was initialized. Default values is not solving. My solutions:
pass all required paramaters through constructor and initialize
Always check if my field is not null (i think this is the bad way)
But if i have 7 required fields.
Class Point
{
private _x; //required it must not be null
private _y; //required it must not be null
private _z; //required it must not be null
private _b; //required it must not be null
private _a; //required it must not be null
private _f; //required it must not be null
private _h; //required it must not be null
//getter and setters
}
How i can be sure that all of them was initialized? Passing this count of paramaters in constructor is really hard and ugly. If i will use builder pattern, it actually not make me sure.
Sorry for bad english.
As people have commented, you can ensure that the fields are initialized by either setting them to always have a default value
Class Point
{
private int j = 42;
}
or have your constructor always define a default value for each field
Class Point
{
private int j;
public Point (int jVal)
{
j = -1;
}
}
This will ensure that whenever a new instance of the class is created, the fields will always be initialized.
If you have references that need to point to objects, you can do it the same way, but just change the value (such as 42 in the previous example) to the language's equivalent of C#'s new Object().
For knowing if the field was initialised you are force to using a flag.
Make it explicit bool _xIsSet; or if _x is an int then make the type int? and check for the value being null.
The former does not throw any exception but if you are not careful you will work with non-initialised values.
The later way throws errors; possibly better but still at run time.
You could decide for properties instead and wrap the fields with checks for null but the result would be the same; any error would surface run time. (or not at all)
The method I prefer since 20? years is to have a constructor that takes all parameters and even make sure there is no default constructor.
var myPoint = new Point(
valueX,
valueY,
valueK
);
With later C# versions one can name the arguments so the code becomes quite easy to read.
var myPoint = new Point(
X = valueX,
Y = valueY,
L = valueK // <-- see here! it is quite easy to spot a possible error
);
My explanation for using this method, except for the one you state, is that "It is very seldom you want a Customer that is not set fully.". Then... if there are several ways to set a Customer fully I create more constructors.
I have taken this further and avoid null as much as I can, so in my code there is never a Customer that is only half set and only rarely a Customer that is null.
Lately I have started experimenting with using static constructors instead; the call is then var customer = Customer.Create(...). This has the taste of DDD as Create can express the intention, can express why a class is created. var customer = Customer.CreateFromEntranceScan(...) or var customer = Customer.CreateFromTaxDeduction(...).

How is a property without a set allowed (read-only property) is being set inside the class? What mechanism?

First of all, I'm NOT really familiar with C#, but I am with C++. I didn't find any info about this. Through what mechanism is a C# property is being set when it only have a get implemented and the set is hidden. It's a read-only property that is being set continuously, inside a loop.
My hunch is that the get returns a reference which C# uses to set the value in this case. Is that correct?
(I've come across a code which I'm trying to understand)
For example:
public Series<double> Avg
{
get { return Values[1]; }
}
public Series<double> Default
{
get { return Values[0]; }
}
(Series is just an array of doubles, but accessing them from the end of the array, by index)
The code in RSI does write the items of the array:
Default[0] = value0;
Avg[0] = constant1 * value0 + constant2 * Avg[1];
So what is happening up there? Just to understand, it is something like the below C++ code?
double& Avg(int index)
{
return Values[index+1];
}
Certainly, in C++ you would use Avg(1) instead of Avg[1] since it is a function, I'm just curious what the logic actually does in #RSI.cs. Is the get in this case is like a reference so it can also write values via the get or is the set is auto-implemented so writing and reading the above properties is accessing a completely different index or even variable?
Are the above C# samples even a valid C# code?
That means you can only read the value of the property but not write it from the outside.
Take a file class for example. It would have a property FileSize that you could read from the outside. It would make no sense to have a Setter since setting the file size should not be possible (you have to modify the content of the file in order for the file size to change).
You would then implement a read only property in the form of the following:
public long FileSize { get { return Content.Length; } }
You can compare a C# property to a set of C++ methods.
A get would be a getProperty() method in your C++ class and a set would be a setProperty(value).
A C# property is actually not very different from having a field and two methods. The whole get and set is just a nice way to let the compiler generate this for you.
This means that this is a property that you want it to be read from outside the object without modifying it, for example you can do this:
public class MyObject
{
private string _currentState;//This will be changed only from inside class
public string MyCurrentState
{
get
{
return _currentState;
}
}
}
Since you are more familiar with c++, let me try to translate it somehow. Forgive me any detail errors because it's been some time since I used C++ on a regular basis.
template<class T> class Series
{
// some template class definition
// the index operator in c++
T& operator [](int idx)
{
return somePrivateTArray[idx];
}
}
class UserOfSeries
{
Series<double> Values[]; // = ... somewhere
public:
Series<double>& Avg()
{
return Values[1];
}
Series<double>& Default()
{
return Values[0];
}
}
When you use it, you will probably write
UserOfSeries* aUserOfSeries = getUserOfSeriesFromTheSystem();
Series<double>& theAvg = aUserOfSeries->Avg();
theAvg[4] = 12000.000;
You can set a property without a set. It only means you cannot access it from outside the class (visibility). Inside the class, the get acts as a reference as I write the values, so setting happens throughout the get if you will.
It means that my original C++ example is correct but a more accurate one is (by Rotem)
std::vector& GetAvg() { return Values[0]; }
so writing happens like this:
GetAvg()[0] = ...;
Thank you Oliver and Rotem for your effort in trying understanding my answer. I feel like this is a good and supporting community. The ones who misunderstood my question as a visibility question were downvoting this though :-)

Storing an object by reference or workarounds

I am building internal logic for a game in C# and coming from C++ this is something that might be lost in translation for me.
I have an object, Ability that calculates the bonus it provides and returns that as an integer value. The calculation is meant to be dynamic and can change depending on a variety of variables.
public class Ability: Buffable
{
public string abbr { get; private set; }
public Ability(string name, string abbr, uint score) : base(name, score)
{
this.abbr = abbr;
}
// Ability Modifier
// returns the ability modifier for the class.
public int Ability_modifier()
{
const double ARBITARY_MINUS_TEN = -10;
const double HALVE = 2;
double value = (double)this.Evaluate();
double result = (value + ARBITARY_MINUS_TEN) / HALVE;
// Round down in case of odd negative modifier
if (result < 0 && ((value % 2) != 0))
{
result--;
}
return (int)result;
}
I then have another object, Skill which should be aware of that bonus and add it into it's calculation. I wanted to pass an Ability into the constructor of Skill by reference and then store that reference so that if the Ability changed the calculation would as well. The obvious problem with this being that apparently storing references is taboo in C#.
Is there either a work around way to do this or an alternate way to approach this problem that my pointer infested mind isn't considering? I would greatly prefer not to have to pass the ability to the function that evaluates Skill every time, since the one referenced never changes after construction.
The obvious problem with this being that apparently storing references is taboo in C#.
Absolutely not. References are stored all over the place. You're doing it here, for example:
this.abbr = abbr;
System.String is a class, and therefore a reference type. And so the value of abbr is a reference.
I strongly suspect you've misunderstood how reference types work in C#. If you remember a reference to an object, then changes to the object will be visible via the reference. However, changes to the original expression you copied won't be.
For example, using StringBuilder as a handy mutable reference type:
StringBuilder x = new StringBuilder("abc");
// Copy the reference...
StringBuilder y = x;
// This changes data within the object that x's value refers to
x.Append("def");
// This changes the value of x to refer to a different StringBuilder
x = new StringBuilder("ghi");
Console.WriteLine(y); // abcdef
See my articles on references and values, and parameter passing in C# for much more detail.
I am not quite seing enough of your code to give a concrete example, but the way to do this is to pass in a lambda delegate such as () => object.property instead of this: object.property.
In C#, there are reference types and value types. All non-value-type objects are passed by reference, so there should be no issue with references. Just pass it, and it will be passed by reference.

A property or indexer may not be passed as an out or ref parameter

I'm getting the above error and unable to resolve it.
I googled a bit but can't get rid of it.
Scenario:
I have class BudgetAllocate whose property is budget which is of double type.
In my dataAccessLayer,
In one of my classes I am trying to do this:
double.TryParse(objReader[i].ToString(), out bd.Budget);
Which is throwing this error:
Property or indexer may not be passed as an out or ref parameter at
compile time.
I even tried this:
double.TryParse(objReader[i].ToString().Equals(DBNull.Value) ? "" : objReader[i].ToString(), out bd.Budget);
Everything else is working fine and references between layers are present.
Others have given you the solution, but as to why this is necessary: a property is just syntactic sugar for a method.
For example, when you declare a property called Name with a getter and setter, under the hood the compiler actually generates methods called get_Name() and set_Name(value). Then, when you read from and write to this property, the compiler translates these operations into calls to those generated methods.
When you consider this, it becomes obvious why you can't pass a property as an output parameter - you would actually be passing a reference to a method, rather than a reference to an object a variable, which is what an output parameter expects.
A similar case exists for indexers.
This is a case of a leaky abstraction. A property is actually a method, the get and set accessors for an indexer get compiled to get_Index() and set_Index methods. The compiler does a terrific job hiding that fact, it automatically translates an assignment to a property to the corresponding set_Xxx() method for example.
But this goes belly up when you pass a method parameter by reference. That requires the JIT compiler to pass a pointer to the memory location of the passed argument. Problem is, there isn't one, assigning the value of a property requires calling the setter method. The called method cannot tell the difference between a passed variable vs a passed property and can thus not know whether a method call is required.
Notable is that this actually works in VB.NET. For example:
Class Example
Public Property Prop As Integer
Public Sub Test(ByRef arg As Integer)
arg = 42
End Sub
Public Sub Run()
Test(Prop) '' No problem
End Sub
End Class
The VB.NET compiler solves this by automatically generating this code for the Run method, expressed in C#:
int temp = Prop;
Test(ref temp);
Prop = temp;
Which is the workaround you can use as well. Not quite sure why the C# team didn't use the same approach. Possibly because they didn't want to hide the potentially expensive getter and setter calls. Or the completely undiagnosable behavior you'll get when the setter has side-effects that change the property value, they'll disappear after the assignment. Classic difference between C# and VB.NET, C# is "no surprises", VB.NET is "make it work if you can".
you cannot use
double.TryParse(objReader[i].ToString(), out bd.Budget);
replace bd.Budget with some variable.
double k;
double.TryParse(objReader[i].ToString(), out k);
Possibly of interest - you could write your own:
//double.TryParse(, out bd.Budget);
bool result = TryParse(s, value => bd.Budget = value);
}
public bool TryParse(string s, Action<double> setValue)
{
double value;
var result = double.TryParse(s, out value);
if (result) setValue(value);
return result;
}
Place the out parameter into a local variable and then set the variable into bd.Budget:
double tempVar = 0.0;
if (double.TryParse(objReader[i].ToString(), out tempVar))
{
bd.Budget = tempVar;
}
Update: Straight from MSDN:
Properties are not variables and
therefore cannot be passed as out
parameters.
This is a very old post, but I'm ammending the accepted, because there is an even more convienient way of doing this which I didn't know.
It's called inline declaration and might have always been available (as in using statements) or it might have been added with C#6.0 or C#7.0 for such cases, not sure, but works like a charm anyway:
Inetad of this
double temp;
double.TryParse(objReader[i].ToString(), out temp);
bd.Budget = temp;
use this:
double.TryParse(objReader[i].ToString(), out double temp);
bd.Budget = temp;
So Budget is a property, correct?
Rather first set it to a local variable, and then set the property value to that.
double t = 0;
double.TryParse(objReader[i].ToString(), out t);
bd.Budget = t;
Usually when I'm trying to do this it's because I want to set my property or leave it at the default value. With the help of this answer and dynamic types we can easily create a string extension method to keep it one lined and simple.
public static dynamic ParseAny(this string text, Type type)
{
var converter = TypeDescriptor.GetConverter(type);
if (converter != null && converter.IsValid(text))
return converter.ConvertFromString(text);
else
return Activator.CreateInstance(type);
}
Use like so;
bd.Budget = objReader[i].ToString().ParseAny(typeof(double));
// Examples
int intTest = "1234".ParseAny(typeof(int)); // Result: 1234
double doubleTest = "12.34".ParseAny(typeof(double)); // Result: 12.34
decimal pass = "12.34".ParseAny(typeof(decimal)); // Result: 12.34
decimal fail = "abc".ParseAny(typeof(decimal)); // Result: 0
string nullStr = null;
decimal failedNull = nullStr.ParseAny(typeof(decimal)); // Result: 0
Optional
On a side note, if that's an SQLDataReader you may also make use of GetSafeString extension(s) to avoid null exceptions from the reader.
public static string GetSafeString(this SqlDataReader reader, int colIndex)
{
if (!reader.IsDBNull(colIndex))
return reader.GetString(colIndex);
return string.Empty;
}
public static string GetSafeString(this SqlDataReader reader, string colName)
{
int colIndex = reader.GetOrdinal(colName);
if (!reader.IsDBNull(colIndex))
return reader.GetString(colIndex);
return string.Empty;
}
Use like so;
bd.Budget = objReader.GetSafeString(i).ParseAny(typeof(double));
bd.Budget = objReader.GetSafeString("ColumnName").ParseAny(typeof(double));
I had the same problem (5 minutes ago) and I solved it using old style properties with getter and setter, whose use variables.
My code:
public List<int> bigField = new List<int>();
public List<int> BigField { get { return bigField; } set { bigField = value; } }
So, I just used bigField variable. I'm not the programmer, if I misunderstood the question, I'm really sorry.

Not able to modify object of struct in loop

I have a List of structure.In the loop i am trying to modify the object's property,which is happening,but when i (Quick look in Visual studio)look into the list object ,the new value is not reflecting.Is it by virtue that the structure's object cannot be modified when in a collection?
I am using generics list with the struct as the type in the list
You mention "modify the object's property" in the context of a struct, but importantly a struct is not an object. Other people have answered as to the issue with structs being copied (and changes discarded), but to take that further the real problem here is that you have a mutable (changeable) struct at all. Unless you are on XNA (or similar) there is simply no need.
If you want to be able to change properties, make it a class:
public class Foo {
public string Bar {get;set;}
}
This is now a reference-type, and your changes (obj.Bar = "abc";) will be preserved through the foreach. If you really want/need a struct, make it immutable:
public struct Foo {
private readonly string bar;
public string Bar { get {return bar; }}
public Foo(string bar) {this.bar = bar;}
}
Now you can't make the mistake of changing the value of a copy; you would instead have to use the indexer to swap the value (list[i] = new Foo("abc");). More verbose (and you can't use foreach), but correct.
But IMO, use a class. Structs are pretty rare, to be honest. If you aren't sure: class.
If you are using a foreach loop you probably got
Compiler Error CS1654
Error Message Cannot modify members of
'variable' because it is a 'read-only
variable type'
This error occurs when you try to
modify members of a variable which is
read-only because it is in a special
construct.
One common area that this occurs is
within foreach loops. It is a
compile-time error to modify the value
of the collection elements. Therefore,
you cannot make any modifications to
elements that are value types,
including structs.
You could however try
struct MyStruct
{
public int i;
}
List<MyStruct> list = new List<MyStruct>
{ new MyStruct { i = 1 }, new MyStruct { i = 2 } };
for(int i = 0; i < list.Count; i++)
{
MyStruct val = list[i];
val.i++;
list[i] = val;
}
EDIT
See also Structs Tutorial
Structs vs. Classes
Structs may seem similar to classes,
but there are important differences
that you should be aware of. First of
all, classes are reference types and
structs are value types.
I THINK i know what the problem might be.
struct Astruct
{
int amember;
}
List < Astruct > listofStructs;
foreach(Astruct A in listofStructs)
{
A.amember = 1337;
}
if this is what you are doing...
when you use structs in c# they are not referenced but copied! so that means the contents of your list is being COPIED to A, so when you change A it doesn't change the value in the list!
to solve this problem (if this is your problem...) either use CLASSES rather than STRUCTS, that way A would be a reference, OR use a manual iterating for loop instead, ie:
for(int i=0;i < listofStructs.Count;i++)
{
listofStructs[i].amember = 1337;
}
alternatively, if you’re using a list, you maybe should use an iterator or something... but the above should definitely fix that problem.
Given the information in your post (although I'd have liked to see the code itself), let me put forth the most probable issue and its fix.
foreach(var s in listOfStructs)
{
s.Property = x;
}
s is assigned to a copy of the actual struct in the collection. s.set_Property is now modifying the copy which is thrown away at the end of the current iteration.
This is because 2 value type variables cannot point to the same instance.
struct1 = new MyStruct(100, 200);
struct2 = struct1; // struct2 is now a copy of struct1
Now to the problem of how do you modify the instances in a collection:
Get the object to modify in a local variable (copy created). Modify it. Now remove the original object and insert the copy. use listOfStructs[i] = modifiedInstance.

Categories

Resources