Storing an object by reference or workarounds - c#

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.

Related

I can't add to a value when i use parameter, but it works fine when not in the function

So when i try to += 1 in the function, the value doesent update, But i can update the value without paramter just fine.
Please help.
public void buystock(int amountofstocks, int stockvalue)
{
int stocksbuy = 400;
if (amountofstocks >= 40)
{
if (GetComponent<Money>().MoneyValue >= (stockvalue + stocksbuy))
{
GetComponent<Money>().MoneyValue -= stockvalue + 400;
amountofstocks += 1;
}
}
else
{
if (GetComponent<Money>().MoneyValue >= (stockvalue + 10))
{
GetComponent<Money>().MoneyValue -= stockvalue + 10;
}
}
}
and my other one which is:
public void buyoil1()
{
buystock(oil1amountofstocks, oil1value);
}
Thanks a lot!
Int is value type, so it's value is copied (opposite to it's reference) into function parameter and any modification on that parameter is local.
In order to pass reference of int, you should use ref keyword.
Try following
public void buystock(ref int amountofstocks,ref int stockvalue)
You are passing a struct to your method which is copying the value rather than passing a reference to the variable.
Consider using a return value, out or ref to achieve the desired result.
Here is the official documentation on passing arguments to methods in C# which helps explain the problem
Its amazing how many answers here are simply wrong. They all go on about int being a value type and that bit of information is completely irrelevant here.
int is an immutable type, you can’t mutate it which would be the only reason why value types could be relevant in the context of this question.
Somehow the answers seem to be mixing up amountofstocks =+ 1 with mutating a value type which is simply false! The only thing that is going on here is that the variable amountofstock is being assigned a new value and because the parameter is passed by value (default behavior in c#) the assignment has no effect whatsoever back at the call site (the assignment is made on a copy).
The exact same thing would happen if amountofstock were a reference type. If amountofstring were to be a string there would be no change at all in the behavior of your code.
To make a long story short, the behavior you are seeing is due to the fact that parameters in c# are, by default, passed by value, period. It has nothing to do, in this particular case, with amountofstock being a value type.
If you need to reassign the value of a parameter and have it persist back at the call site then you need to pass it by reference; in your case ref amountofstock although in some scenarios out is more appropriate.

How can I preserve members of my old class when using implicit conversion casting to set a new value to my object?

I know that some people will suggest other ways of performing this same function and I am only interested in specifically accomplishing my goal. I already have working code that performs said task and just would like to understand more about writing my own powerful objects - thank you.
My goal:
int x = 100;
Base b = new Base(0, 3);
b = x; // Preserves my baseNum of 3 for conversions
Code:
public class Base
{
public int count = 0; // represents the count of current numerical value in base ten digit count : 3 -> could be read NEVER user changed
public int baseNum = 10; // conversion base subscript -> """""
public int represented; // represented base ten value of conversion (used for output NOT mathmatically friendly) -> should be read BUT never change by user
public int numerical = 0;
public int[] basearray; // should NOT be modified read only
public Base()
{
//count = 0; // setting numerical will run digit count
baseNum = 10;
numerical = 0;
}
public Base(int i)
{
baseNum = 10;
numerical = i;
}
public Base(int n, int b)
{
baseNum = b;
numerical = n;
}
public static implicit operator Base(int i)
{
// Help needed
}
public static implicit operator int(Base b)
{
int i = b.numerical;
return i;
}
}
I have excluded much of the irrelevant code. This object holds a numerical value but provides a digit by digit reference to a converted format (as we count in base ten this object converts into other base forms)
What I wish is to preserve the current baseNum member and only update the numerical value of my object when using assignment.
As implicit conversion is a static function as far as I know there is no way to access the instance that will be used when assignments are performed after int is casted into my object.
Is there any way to perform this assignment operation in the way I wish?
Again - I already have many methods that allow me to modify the numerical member of the instance.
I also know that I can simply define the baseNum again after assignment.
I only wish to find out if there is a way to possibly utilize my object in the way I am imagining.
You simply can't do that.
When you write b = x, things happen under the hood are:
take the value if x
invoke implicit operator Base(int i) on the value of x, a Base object is returned
assign the returned object to b
There is no conventional way you can access the original value of b in step 2, where the conversion happens.
Is there any way to perform this assignment operation in the way I wish?
No, there is not. Conversion operators, implicit or explicit, always return a new object. And in the case of your reference type, the value returned is a reference, and the assignment is to variable holding that reference, which does not in any way modify the object that variable previously referred to.
Furthermore, I would suggest you should not want to do this anyway. An assignment that only modifies the target partially would be very confusing to anyone reading the code. At first, maybe just confusing to people unfamiliar with the design, but eventually, once the code's been sitting there for awhile without any need to work on it, even people who were theoretically well-versed in the design will have trouble remembering that it does this.
Stick with what you already have, where modification of individual components of an object are expressed explicitly. This will keep the code expressive, simple, and easy to understand.

Why does assignment to parameter not change object?

classes deal with the reference types and traditional data types deal with the value type just for example :
int i=5;
int j=i;
i=3 ; //then this will output i=3 and j=5 because they are in the different memory blocks .
Similarly if we talk about the object of a class say point class
class point
{
public int x,y;
void somefucnt(point p,int x)
{
Console.writeline("value of x is "+p.x);
x=22;
Console.writeline("value of x is "+p.x);
}
}
class someotherclass
{
static void Main(string [] args )
{
p1.x=10;
p1.somefunct(p1,p1.x);
}
}
Both console.write statements are printing 10 , despite ive changed x to some other value ? why is it so ?since p is just the reference to x so it should be updated by changing values of x . this thing is really confusing me alot .
The observed behavior has nothing to do with Value types vs Reference types - it has to do with the Evaluation of Strategy (or "calling conventions") when invoking a method.
Without ref/out, C# is always Call by Value1, which means re-assignments to parameters do not affect the caller bindings. As such, the re-assignment to the x parameter is independent of the argument value (or source of such value) - it doesn't matter if it's a Value type or a Reference type.
See Reference type still needs pass by ref? (on why caller does not see parameter re-assignment):
Everything is passed by value in C#. However, when you pass a reference type, the reference itself is being passed by value, i.e., a copy of the original reference is passed. So, you can change the state of object that the reference copy points to, but if you assign a new value to the reference [parameter] you are only changing what the [local variable] copy points to, not the original reference [in the argument expression].
And Passing reference type in C# (on why ref is not needed to mutate Reference types)
I.e. the address of the object is passed by value, but the address to the object and the object is the same. So when you call your method, the VM copies the reference; you're just changing a copy.
1 For references types, the phrasing "Call By Value [of the Reference]" or "Call by [Reference] Value" may help clear up the issue. Eric Lippert has written a popular article The Truth about Value Types which encourages treating reference values as a distinct concept from References (or instances of Reference types).
void somefucnt(point p,int x){
Console.writeline("value of x is "+p.x);
x=22;
Console.writeline("value of x is "+p.x);
}
Here, the x=22 won´t change p.x but the parameter x of (point p,int x)
Normally, your assumtion about values/references is ok (if I understood it correctly).
Tip: Google for c# this instead of passing a object to it´s own method
You change the value of the parameter (x), not the value of p.x, value types are passed by value unless you use the ref keyword.
Like in your first example, there is no relationship between i and j as well as the parameter x, and p1.x.Each variable has it's own space in the memory.So changing one of them doesn't affect to the other.
You have two different variables named x in the somefucnt function. One is the member variable x which you are trying to change, the other is the function input parameter in void somefucnt(point p, int x). When you say x = 22, the input parameter x is changed instead of the member variable x.
If you change the line x = 22 to this.x = 22 then it should work as you expect.
Side note:
A good practice to avoid confusion is to always have class members private and name them as _x. Otherwise, have public auto properties in CamelCase, like this:
public int X { get; set; }
These methods avoid ambiguity between class variables and function input variables.

Practical differences between classes and structs in .net (not conceptual)?

Whenever I tried to search about differences between classes and structs in C# or .net, I ended up with the conceptual overview of the two things like value type or the reference type, where the variables are allocated etc. But I need some practical differences. I have found some like different behavior of assignment operator, having constructors etc. Can anybody provide some more practical differences which will be directly useful while coding? Like the things works with one but not with other or same operation showing different behavior. And some common mistakes regarding these two.
Also please suggest where to consider using a struct instead of a class. And where the structs should not be used.
Edit:
Do I have to call the constructor explicitly or just declaring a struct type variable will suffice?(Should I make it a new question?)
OK, here are a few specific, practical differences:
A variable can be null if it’s a class, but is never null if it’s a struct.
default(T) is null for a class, but for a struct actually constructs a value (consisting of lots of binary zeros).
A struct can be made nullable by using Nullable<T> or T?. A class cannot be used for the T in Nullable<T> or T?.
A struct always has a public default constructor (a constructor with zero parameters). The programmer cannot override this constructor with a custom implementation — it is basically “set in stone”. A class allows the programmer to have no default constructor (or a private one).
The fields in a class can have default values declared on them. In a struct they can’t.
A class can inherit from another class, but a struct cannot be declared to derive from anything (it implicitly derives from System.ValueType).
It makes sense to use a class in object.ReferenceEquals(), but using a struct variable will always yield false.
It makes sense to use a class in a lock() statement, but using a struct variable will cause very subtle failure. The code will not be locked.
On a 32-bit system, you can theoretically allocate an array of up to 536,870,912 references to a class, but for a struct you need to take the size of the struct into account because you are allocating actual instances.
Structs in a container can only be modified if the container is a built-in array:
struct Point { public int x, y; void Move(int dx, int dy) { x += dx; y += dy; } }
...
Point[] points = getPointsArray();
points[0].Move(10, 0) = 10;
// points[0].x is now 10 higher.
List<Point> points = getPointsList();
points[0].Move(10, 0);
// No error, but points[0].x hasn't changed.
For this reason, I strongly favour immutable structs:
Point Move(int dx, int dy) { return new Point(x + dx, y + dy); }
...
points[0] = points[0].Move(10, 0); // Always works.
General observation: classes are usually better. Structs excel when you want to hold small, conceptually atomic data structures such as Point, Complex (number), Rational, etc.
structs, as they are value types, are copied on assignment; if you create your own struct, you should make it immutable, see Why are mutable structs evil?
Sometimes you don't want what you're passing to be mutable, and since a mutable struct may just be pure evil, I'd steer clear of ever creating one :) Here's an example a situation:
class Version:
class AccountInfo {
public string OwnerName { get; set; }
public string AccountNumber { get; set; }
}
struct Version:
struct AccountInfo {
public string OwnerName;
public string AccountNumber;
}
Now picture you called a method like this:
public bool TransferMoney(AccountInfo from, AccountInfo to, decimal amount)
{
if(!IsAuthorized(from)) return false;
//Transfer money
}
A struct is a Value type, meaning a copy gets passed into the method. The class version means a reference gets passed into the method, you wouldn't want for example the account number to be changeable after the authorization passed, you want nothing to be changed in an operation like this...you want an immutable value type. There's another question here asking why mutable structs are evil...any operation where you wouldn't want anything affected by the reference object changing, would be a practical place where a struct may fit better.
The example above may be somewhat silly, but the point is any sensitive operation where the passed in data shouldn't change in another thread or by any means really would be a place you look at passing by value.
Where they are allocated (heap vs. stack) is not something you really care about while you use them (not that you should disregard this - you should by all means study the differences and understand them).
But the most important practical difference you will come across the first time you decide to replace your class with a struct, is that structs are passed by value, while class instances are passed by reference.
This means that when you pass a struct to a method, a copy of its properties is created (a shallow copy) and your method actually gets a different copy than the one you had outside the method. When you pass an instance of a class, only a reference to the same place in memory is passed to the method, and your method is then dealing with exactly the same data.
For example, if you have a struct named MyStruct, and a class named MyClass, and you pass them to this method:
void DoSomething(MyStruct str, MyClass cls)
{
// this will change the copy of str, but changes
// will not be made to the outside struct
str.Something = str.Something + 1;
// this will change the actual class outside
// the method, because cls points to the
// same instance in memory
cls.Something = cls.Something + 1;
}
when the method ends, your class' property will be incremented, but your struct's property will remain unchanged, because str variable inside the DoSomething method does not point to the same place in memory.
The singularly important practical difference is that structs are value types, whereas classes are reference types. That has a few implications.
First of all, structs are copied on assignment. These two code blocks will have a different result (please note, normally you should neither use public fields nor mutable structs, I'm doing this for demonstration purposes only):
struct X
{
public int ID;
public string Name;
}
X x1 = new X { ID = 1, Name = "Foo" };
X x2 = x1;
x2.Name = "Bar";
Console.WriteLine(x1.Name); // Will print "Foo"
class Y
{
public int ID;
public string Name;
}
Y y1 = new Y { ID = 2, Name = "Bar" };
Y y2 = y1;
y2.Name = "Baz";
Console.WriteLine(y1.Name); // Will print "Baz"
X and Y are exactly the same, except that X is a struct. The results of this are different because every time we assign an X, a copy is made, and if we change the copy then we aren't changing the original. On the other hand, when we assign the contents of y1 to y2, all we've done is copied a reference; both y1 and y2 refer to physically the same object in memory.
The second consequence of structs being value types is generic constraints. If you want to pass in value types, the name of the constraint is literally "struct" or "class":
public class MyGeneric<T>
where T : struct
{ ... }
The above will let you create a MyGeneric<int> or MyGeneric<X>, but not a MyGeneric<Y>. On the other hand, if we change it to where T : struct, we're no longer allowed to create either of the first two, but MyGeneric<Y> is okay.
Last but not least, you need to use structs when writing interop, because with structs you're able to guarantee a specific arrangement in memory.
The link Tejs provided (http://www.jaggersoft.com/pubs/StructsVsClasses.htm) is a good explanation (although it is a bit out of date, particularly on the explanation of events).
The most import practical difference is that a struct is a value type, meaning it is passed by value rather than by reference. What this really means is that when a struct is passed as an argument, it is actually passed by copy. As a result, operations on one instance of a struct do not affect other instances.
Consider the following code:
struct NumberStruct
{
public int Value;
}
class NumberClass
{
public int Value = 0;
}
class Test
{
static void Main()
{
NumberStruct ns1 = new NumberStruct();
NumberStruct ns2 = ns1;
ns2.Value = 42;
NumberClass nc1 = new NumberClass();
NumberClass nc2 = nc1;
nc2.Value = 42;
Console.WriteLine("Struct: {0}, {1}", ns1.Value, ns2.Value);
Console.WriteLine("Class: {0}, {1}", nc1.Value, nc2.Value);
}
}
Because both ns1 and ns2 are of the NumberStruct value type, they each have their own storage location, so the assignment of ns2.Number does not affect the value of ns1.Number. However, because nc1 and nc2 are both reference types, the assignment of nc2.Number does affect the value of nc1.Number because they both contain the same reference.
[Disclaimer: The above code and text taken from Sams Teach Yourself Visual C# 2010 in 24 Hours]
Also, as others have already pointed out, structs should always be immutable. (Yes, in this example the struct is mutable but it was to illustrate the point.) Part of that means that structs should not contain public fields.
Since structs are value types, you cannot inherit from a struct. You also cannot derive a struct from a base class. (A struct can implement interfaces, however.)
A struct is also not allowed to have an explicitly declared public default (parameterless) contstructor. Any additional constructors you declare must completely initialize all of the struct fields. Structs also cannot have an explicitly declared destructor.
Since structs are value types, they shouldn't implement IDisposable and shouldn't contain unmanaged code.
Here's an interesting link: http://www.jaggersoft.com/pubs/StructsVsClasses.htm
For the most part though, there isn't much of a compelling reason to use structs when classes offer far more to the developer.

How did the code achieve pass by reference?

Inside main i declared a local int[] array (int[] nums). I did not pass it by reference.
But when i print values of local array i get squared value of each element.
What is the reason for that?
delegate void tsquare(int[] a);
static void Main()
{
int[] nums = { 1, 2, 3 };
tsquare sqr = new tsquare(SomeClass.Square);
sqr(nums);
foreach (int intvals in nums)
{
Console.WriteLine(intvals);
}
}
class SomeClass
{
public static void Square(int[] array)
{
for (int i = 0; i < array.Length; i++)
{
array[i] = array[i] * array[i];
}
}
}
Update:
My appologies to all.What i tought is int[] {Array}is a value type,and the Delegate done
some trick on it.Now from your answer ,i understand Array is Reference type.
There are two concepts here.
Reference types vs. value types
Passing by value vs. passing by reference
Let's tackle the second one first.
Passing something by value means that you give the method its own copy of that value, and it's free to change that value however it wants to, without those changes leaking back into the code that called the method.
For instance, this:
Int32 x = 10;
SomeMethod(x); // pass by value
There's no way x is going to be anything other than 10 after the call returns in this case, since whatever SomeMethod did to its copy of the value, it only did to its own value.
However, passing by reference means that we don't really give the method its own value to play with, rather we give it the location in memory where our own value is located, and thus anything that method does to the value will be reflected back to our code, because in reality, there's only one value in play.
So this:
Int32 x = 10;
SomeMethod(ref x); // pass by reference
In this case, x might hold a different value after SomeMethod returns than it did before it was called.
So that's passing by value vs. passing by reference.
And now to muddle the waters. There's another concept, reference types vs. value types, which many confuses. Your question alludes to you being confused about the issue as well, my apologies if you're not.
A reference type is actually a two-part thing. It's a reference, and it's whatever the reference refers to. Think of a house you know the address of. You writing the address on a piece of paper does not actually put the entire house on that paper, rather you have a "reference" to that particular house on your piece of paper.
A reference type in .NET is the same thing. Somewhere in memory there is an object, which is a set of values, grouped together. The address of this object you store in a variable. This variable is declared to be a type which is a reference type, which allows this two-part deal.
The nice thing about reference types is that you might have many references to the same actual object, so even if you copy the reference around, you still only have one object in memory.
Edit: In respect to the question, an array is a reference type. This means that your variable only holds the address of the actual array, and that array object is located somewhere else in memory.
A value type, however, is one thing, the entire value is part of the "value type", and when you make copies of that, you make distinct copies
Here's an example of value types:
struct SomeType
{
public Int32 Value;
}
SomeType x = new SomeType;
x.Value = 10;
SomeType y = x; // value type, so y is now a copy of x
y.Value = 20; // x.Value is still 10
However, with a reference type, you're not making a copy of the object it refers to, only the reference to it. Think of it like copying the address of that house onto a second piece of paper. You still only have one house.
So, by simply changing the type of SomeType to be a reference type (changing struct to class):
class SomeType
{
public Int32 Value;
}
SomeType x = new SomeType;
x.Value = 10;
SomeType y = x; // reference type, so y now refers to the same object x refers to
y.Value = 20; // now x.Value is also 20, since x and y refer to the same object
And now for the final thing; passing a reference type by value.
Take this method:
public void Test(SomeType t)
{
t.Value = 25;
}
Given our class-version of SomeType above, what we have here is a method that takes a reference type parameter, but it takes it as being passed by value.
What that means is that Test cannot change t to refer to another object altogether, and make that change leak back into the calling code. Think of this as calling a friend, and giving him the address you have on your piece of paper. No matter what your friend is doing to that house, the address you have on your paper won't change.
But, that method is free to modify the contents of the object being referred to. In that house/friend scenario, your friend is free to go and visit that house, and rearrange the furniture. Since there is only one house in play, if you go to that house after he has rearranged it, you'll see his changes.
If you change the method to pass the reference type by reference, not only is that method free to rearrange the contents of the object being referred to, but the method is also free to replace the object with an altogether new object, and have that change reflect back into the calling code. Basically, your friend can tell you back "From now on, use this new address I'll read to you instead of the old one, and forget the old one altogether".
The array reference is passed by value automatically because it is a reference type.
Read:
Reference Types
Value Types
Most of the other answers are correct but I believe the terminology is confusing and warrants explanation. By default, you can say that all parameters in C# are passed by value, meaning the contents of the variable are copied to the method variable. This is intuitive with variables of value types, but the trick is in remembering that variables that are reference types (including arrays) are actually pointers. The memory location the pointer contains is copied to the method when it is passed in.
When you apply the ref modifier, the method gets the actual variable from the caller. For the most part the behavior is the same, but consider the following:
public void DoesNothing(int[] nums)
{
nums = new []{1, 2, 3, 4};
}
In DoesNothing, we instantiate a new int array and assign it to nums. When the method exits, the assignment is not seen by the caller, because the method was manipulating a copy of the reference (pointer) that was passed in.
public void DoesSomething(ref int[] nums)
{
nums = new []{1, 2, 3, 4};
}
With the ref keyword, the method can essentially reach out and affect the original variable itself from the caller.
To achieve what you seemed to originally want, you could create a new array and return it, or use Array.CopyTo() in the caller.
In C#, all parameters are passed by value by default. There are two kinds of types in C#, namely value and reference types.
A variable of reference type when passed as a parameter to a function will still be passed by value; that is if the function changes the object referred to by that variable, after the function completes the variable that was passed in will still refer to the same object (including null) as it did prior to calling the function in the same context.
However, if you use the ref modifier when declaring the function parameter than the function may change the object being referenced by the variable in the caller's context.
For Value types this is more straightforward but it is the same concept. Bear in mind, int[] is a reference type (as are all arrays).
Consider the differences in these functions when passing in some some array of ints:
public static void Square1(int[] array)
{
for (int i = 0; i < array.Length; i++)
{
array[i] = array[i] * array[i];
}
}
public static void Square2(int[] array)
{
array = {10, 20, 30};
for (int i = 0; i < array.Length; i++)
{
array[i] = array[i] * array[i];
}
}
public static void Square3(ref int[] array)
{
array = {10, 20, 30};
for (int i = 0; i < array.Length; i++)
{
array[i] = array[i] * array[i];
}
}
You're not passing it by reference. The array is being passed in by value, but arrays in .NET are reference types, so you're passing in a reference to the array, which is why you're seeing the values squared.
Read the following SO question - it explains the differences between pass-by-value and pass-by-reference. The accepted answer has a link in it to a good article about the topic that should help you understand the difference.
what is different between Passing by value and Passing by reference using C#
Arrays are objects and are passed by reference. Ints are structs and are passed by value (unless you use the ref keyword in your method signature as per the picky guy in the comments) (who was right) (but picky).

Categories

Resources