class Program
{
static void Main()
{
int i = 0;
whatever x = new whatever(i);
Console.WriteLine(x);
i = 1;
Console.WriteLine(x);
Console.ReadKey();
}
class whatever
{
public whatever(object variable)
{
this.variable = () => variable.ToString();
}
private Func<string> variable;
public string data;
public override string ToString()
{
data = variable();
return data;
}
}
Output:
0
0
what I want to do is get updated i's value.
If you want to capture the local variable then you've put the lambda in the wrong place. The lambda has to go where it can be closed over the outer variable you want to capture.
class Program
{
static void Main()
{
int i = 0;
var x = new Whatever<int>(()=>i);
Console.WriteLine(x);
i = 1;
Console.WriteLine(x);
Console.ReadKey();
}
}
class Whatever<T>
{
private Func<T> variable;
public Whatever(Func<T> func)
{
this.variable= func;
}
public override string ToString()
{
return this.variable().ToString();
}
}
Does that make sense? See, the lambda has to be where the "i" is declared, so that "i" is an outer variable of the lambda and therefore the lambda sees changes to it.
i is an integer (value type), which is passed by value - a copy of the value is passed to the whatever constructor. When you change its value on the Main method, it doesn't change what has been already passed to the class. So you can't get the updated value on whatever.
If you have an object which holds a field of an integer value, and then pass that object to whatever, then changes to that field will be reflected on the class.
Maybe the problem is that delegate is bound to boxed integer data. This is why you change your int and delegate evaluates to old boxed data.
Try it with constructor that takes an int.
But, yes it's true that ints are pased by value, so this will not work.
Pass delegate to ctor.
class Program
{
static void Main()
{
int i = 0;
whatever x = new whatever(() => i.ToString());
Console.WriteLine(x);
i = 1;
Console.WriteLine(x);
Console.ReadKey();
}
class whatever
{
public whatever(Func<string> someFunc)
{
this.variable = someFunc;
}
private Func<string> variable;
public string data;
public override string ToString()
{
data = variable();
return data;
}
}
}
Output:
0
1
Or as other have indicated:
class Program
{
static void Main()
{
var myRefType = new MyRefType();
myRefType.MyInt = 0;
var x = new whatever(myRefType);
Console.WriteLine(x);
myRefType.MyInt = 1;
Console.WriteLine(x);
Console.ReadKey();
}
class whatever
{
public whatever(MyRefType myRefType)
{
this.variable = () => myRefType.MyInt.ToString();
}
private Func<string> variable;
public override string ToString()
{
return variable();
}
}
class MyRefType
{
public int MyInt { get; set; }
}
}
Outputs:
0
1
Integers are of value type, not reference type.
int is value type, meaning its value is copied each time you use it and not its reference. The best way to make this work is make reference type around int:
class IntRef
{
public int Val;
}
You will need to always use IntRef.Val and passing the IntVal itself around will retain the reference.
Related
I've this class:
public class Pair<T, V>
{
public T A = default;
public V B = default;
public Pair()
{
A = default;
B = default;
}
public Pair(T a, V b)
{
A = a;
B = b;
}
public override bool Equals(object obj)
{
Pair<T, V> other = obj as Pair<T, V>;
return A.Equals(other.A) && B.Equals(other.B);
}
public override int GetHashCode()
{
return base.GetHashCode();
}
public override string ToString()
{
return "Pair: (" + A.ToString() + " , " + B.ToString() + ")";
}
}
And I have a class with two Pair variables:
public class FakeClass<T>
{
public T LastValue { get; protected set; } = default;
public T CurrentValue = default;
public void Execute()
{
LastValue = CurrentValue
}
}
public class FakeClassWithPair : FakeClass<Pair<int, int>> { }
Now if I execute this code:
FakeClassWithPair fake = new FakeClassWithPair();
fake.CurrentValue.A = 2;
fake.CurrentValue.B = 5;
fake.Execute();
fake.CurrentValue.A = 32;
fake.CurrentValue.B = 53;
In debugging Current Value and Last Value have the same value "32" and "53".
How can I avoid this?
Classes are reference types, so when you set LastValue = CurrentValue, that means both LastValue and CurrentValue refer to the same object.
If you want Value semantics you should declare your Pair as a struct. This means that an assignment does a copy of the value. Except ofc there already are a built in type for this: ValueTuple, with some special syntax that lets you declare types like (int A, int B). There is also a regular Tuple<T1, T2> if you do want a reference type.
Also note that I see no way for your example to run, fake.CurrentValue should be initialized to null and crash when accessed. Using a value type would also solve this, since they cannot be null.
So just change your example to FakeClassWithPair:FakeClass<(int A, int B)> and everything should work as you expect it to.
Definitely do not roll your own class for a pair if you want value semantics. Use the built-in value tuple, defined as (T a, V b).
Also if your content of FakeClass is cloneable then you should take advantage of that (for example arrays are cloneable). So the assignment in Execute() would check if the current value implements ICloneable and proceeds accordingly.
See this example code with output. The first example with fk variable is defined by FakeClass<(int,int)> and the second example with fa variable is defined by FakeClass<int[]>. Some fun code is added to display arrays as list of vales in ToString() in order to mimic the behavior of tuples with arrays.
public class FakeClass<T>
{
public T LastValue { get; protected set; } = default(T);
public T CurrentValue = default(T);
public void Execute()
{
if (CurrentValue is ICloneable cloneable)
{
LastValue = (T)cloneable.Clone();
}
else
{
LastValue = CurrentValue;
}
}
public override string ToString()
{
if (typeof(T).IsArray)
{
object[] last, current;
Array cv = CurrentValue as Array;
if (cv != null)
{
current = new object[cv.Length];
cv.CopyTo(current, 0);
}
else
{
current = new object[0];
}
Array lv = LastValue as Array;
if (lv != null)
{
last = new object[lv.Length];
lv.CopyTo(last, 0);
}
else
{
last = new object[0];
}
return $"Current=[{string.Join(",",current)}], Last=[{string.Join(",",last)}]";
}
return $"Current={CurrentValue}, Last={LastValue}";
}
}
class Program
{
static void Main(string[] args)
{
var fk = new FakeClass<(int a, int b)>();
fk.CurrentValue = (1, 2);
Console.WriteLine(fk);
// Current=(1, 2), Last=(0, 0)
fk.Execute();
fk.CurrentValue = (3, 4);
Console.WriteLine(fk);
// Current=(3, 4), Last=(1, 2)
var fa = new FakeClass<int[]>();
fa.CurrentValue = new int[] { 1, 2 };
Console.WriteLine(fa);
//Current=[1,2], Last=[]
fa.Execute();
fa.CurrentValue = new int[] { 3, 4 };
Console.WriteLine(fa);
//Current=[3,4], Last=[1,2]
}
}
As you probably know in D language we have an ability called Voldemort Types and they are used as internal types that implement particular range function:
auto createVoldemortType(int value)
{
struct TheUnnameable
{
int getValue() { return value; }
}
return TheUnnameable();
}
Here is how the Voldemort type can be used:
auto voldemort = createVoldemortType(123);
writeln(voldemort.getValue()); // prints 123
Now I want to make sure that, Is this the equivalent to delegate in C#?
public static void Main()
{
var voldemort = createVoldemortType(123);
Console.WriteLine(voldemort());
}
public static Func<int> createVoldemortType(int value)
{
Func<int> theUnnameable = delegate()
{
return value;
};
return theUnnameable;
}
There isn't an exact equivalent of a Voldermort type in C#. The closest you have to such local scope classes is called Anonymous Types. Problem is, unlike Voldermort types, you can't refer to their static type at compile time outside of the local declaration:
public object SomeLocalMethod() // Must return either `dynamic` over `object`
{
var myAnonClass = new { X = 1, Y = "Hello" };
Console.WriteLine(myAnonClass.Y); // Prints "Hello";
return myAnonClass;
}
void Main()
{
object tryLookAtAnon = SomeLocalMethod(); // No access to "X" or "Y" variables here.
}
If however, we enter the land of dynamic, you can refer to the underlying class fields, but we lose type safety:
void Main()
{
dynamic tryLookAtAnon = SomeLocalMethod();
Console.WriteLine(tryLookAtAnon.X); // prints 1
}
public dynamic SomeLocalMethod()
{
var myAnonClass = new { X = 1, Y = "Hello" };
Console.WriteLine(myAnonClass.Y); // Prints "Hello";
return myAnonClass;
}
A delegate in C# is similar to a delegate in D. They hold a reference to a function.
I have been searching for a way to save the references of variables of various types into a dictionary, together with a corresponding key. Then i would like to modify the instance of the variable by accessing its reference through the dictionary by its key.
For storing the references, i tried to use <object>, but without success. Neither Dictionaries nor Lists accept anything like Dictionary<string, ref int>.
The following code compiles, but seems to update the variables by value only. Any ideas or workarounds?
Here's the (tested) code:
class Test1
{
IDictionary<string, object> MyDict = new Dictionary<string, object>();
public void saveVar(string key, ref int v) //storing the ref to an int
{
MyDict.Add(key, v);
}
public void saveVar(string key, ref string s) //storing the ref to a string
{
MyDict.Add(key, s);
}
public void changeVar(string key) //changing any of them
{
if(MyDict.GetType() == typeof(int))
{
MyDict[key] = (int)MyDict[key] * 2;
}
if(MyDict.GetType() == typeof(string))
{
MyDict[key] = "Hello";
}
}
}
And this is how i call the methods of the class
Test1 t1 = new Test1();
int myInt = 3;
string myString = "defaultString";
Console.WriteLine(myInt); //returns "3"
Console.WriteLine(myString); //returns "defaultString"
t1.saveVar("key1", ref myInt);
t1.saveVar("key2", ref myString);
t1.changeVar("key1");
t1.changeVar("key2");
Console.WriteLine(myInt); //should return "6"
Console.WriteLine(myString); //should return "Hello"
The best solution I can think of for this is to store delegates in the dictionary that will allow you to retrieve and modify the variables.
Let’s start by declaring a type that contains a getter and a setter delegate:
sealed class VariableReference
{
public Func<object> Get { get; private set; }
public Action<object> Set { get; private set; }
public VariableReference(Func<object> getter, Action<object> setter)
{
Get = getter;
Set = setter;
}
}
The dictionary would have the type:
Dictionary<string, VariableReference>
To store a variable, say foo of type string, in the dictionary, you’d write the following:
myDic.Add(key, new VariableReference(
() => foo, // getter
val => { foo = (string) val; } // setter
));
To retrieve the value of a variable, you’d write
var value = myDic[key].Get();
To change the value of a variable to newValue, you’d write
myDic[key].Set(newValue);
This way, the variable that you’re changing is genuinely the original variable foo, and foo can be anything (a local variable, a parameter, a field on an object, a static field... even a property).
Putting this all together, this is what the class Test1 would look like:
class Test1
{
Dictionary<string, VariableReference> MyDict = new Dictionary<string, VariableReference>();
public void saveVar(string key, Func<object> getter, Action<object> setter)
{
MyDict.Add(key, new VariableReference(getter, setter));
}
public void changeVar(string key) // changing any of them
{
if (MyDict[key].Get() is int)
{
MyDict[key].Set((int)MyDict[key].Get() * 2);
}
else if (MyDict[key].Get() is string)
{
MyDict[key].Set("Hello");
}
}
}
// ...
Test1 t1 = new Test1();
int myInt = 3;
string myString = "defaultString";
Console.WriteLine(myInt); // prints "3"
Console.WriteLine(myString); // prints "defaultString"
t1.saveVar("key1", () => myInt, v => { myInt = (int) v; });
t1.saveVar("key2", () => myString, v => { myString = (string) v; });
t1.changeVar("key1");
t1.changeVar("key2");
Console.WriteLine(myInt); // actually prints "6"
Console.WriteLine(myString); // actually prints "Hello"
Apart from the problem Kevin points out, you need to wrap your value types in some kind of reference type.
The problem, as you've figured out, is that generic types don't work with the ref keyword, and when you assign a new value type into your dictionary, it's replacing the reference with a different reference, not updating it. There is no way to retain the ref semantics once you assign it to the dictionary.
But, what you could do is something like this, simply wrap the value type in a reference type:
public class MyRef<T> {
public T Ref {get;set;}
}
public class Test1
{
Dictionary<string, object> MyDict = new Dictionary<string, object>();
public void saveVar(string key, object v)
{
MyDict.Add(key, v);
}
public void changeVar(string key, object newValue) //changing any of them
{
var ref1 = MyDict[key] as MyRef<int>;
if (ref1 != null) {
ref1.Ref = (int)newValue;
return; // no sense in wasting cpu cycles
}
var ref2 = MyDict[key] as MyRef<string>;
if (ref2 != null) {
ref2.Ref = newValue.ToString();
}
}
public void DoIt()
{
var v = new MyRef<int> { Ref = 1 };
saveVar("First", v);
changeVar("First", 2);
Console.WriteLine(v.Ref.ToString()); // Should print 2
Console.WriteLine(((MyRef<int>)MyDict["First"]).Ref.ToString()); // should also print 2
}
}
A ref parameter's reference can not leave the scope of the method that calls it. This is because the variable that is reference cannot be guaranteed to be in scope after the method call has finished. You need to use a tool other than ref to create a layer of indirection allowing a variable a caller is using to be mutated.
Doing this is quite easy though. You simply need a class with a mutable member:
public class Pointer
{
public object Value { get; set; }
}
You can now write:
class Test1
{
IDictionary<string, Pointer> MyDict = new Dictionary<string, Pointer>();
public void saveVar(string key, Pointer pointer) //storing the ref to an int
{
MyDict.Add(key, pointer);
}
public void changeVar(string key) //changing any of them
{
if (MyDict[key].Value.GetType() == typeof(int))
{
MyDict[key].Value = (int)(MyDict[key].Value) * 2;
}
if (MyDict[key].Value.GetType() == typeof(string))
{
MyDict[key].Value = "Hello";
}
}
}
Since you're now mutating a reference type that the caller also has a reference to, they can observe the change to its value.
I wanted to know: How to add new members to the list, so that when I change the values of variables will also change the list.
For example:
int a=4;
list<int> l=new list<int>();
l.Add(a);
a=5;
foreach(var v in l)
Console.WriteLine("a="+v);
Output:
a=4
thanks
You need to use reference types if you want that to happen.
With value types, such as int, you get a copy of the variable in the list, not a copy of the reference.
See Value Types and Reference Types on MSDN.
This will not work for a list of value type variables, each time you are changing a value type variable you get a new variable value copy in a stack. So a solution would be using some kind of reference type wrapper.
class NumericWrapper
{
public int Value { get; set; }
}
var items = new List<NumericWrapper>();
var item = new NumericWrapper { Value = 10 };
items.Add(item);
// should be 11 after this line of code
item.Value++;
You could build out a wrapper container and then just update the wrapper's value as needed. Something like below, for example:
//item class
public class Item<T>
{
T Value {get;set;}
}
//usage example
private List<String> items = new List<string>();
public void AddItem( Item<string> item)
{
items.Add(item);
}
public void SetItem(Item<T> item,string value)
{
item.Value=value;
}
You will have to wrap the int inside a reference type.
Try this:
internal class Program
{
private static void Main(string[] args)
{
IntWrapper a = 4;
var list = new List<IntWrapper>();
list.Add(a);
a.Value = 5;
//a = 5; //Dont do this. This will assign a new reference to a. Hence changes will not reflect inside list.
foreach (var v in list)
Console.WriteLine("a=" + v);
}
}
public class IntWrapper
{
public int Value;
public IntWrapper()
{
}
public IntWrapper(int value)
{
Value = value;
}
// User-defined conversion from IntWrapper to int
public static implicit operator int(IntWrapper d)
{
return d.Value;
}
// User-defined conversion from int to IntWrapper
public static implicit operator IntWrapper(int d)
{
return new IntWrapper(d);
}
public override string ToString()
{
return Value.ToString();
}
}
I know Func<> is used to pass a method that has a return value to be used inside another method. I know Action<> is used to pass a method that does not have a return value to be used inside another method. Is there a way to pass in a property so it's get/set can be used inside another method?
For example, here is a method that uses Func<>:
public bool RangeCheck (int minVal, int maxVal, Func<< int, int >> someMethod)
{
bool retval = true;
try
{
for (int count = min; count <= max; count++)
{
int hello = someMethod(count);
}
}
catch
{
retval = false;
}
return retval;
}
What I am looking for is something like this:
public bool RangeCheck(int min, int max, Prop<< int >> someProperty)
{
bool retval = true;
try
{
for (int count = min; count <= max; count++)
{
someProperty = count;
}
}
catch
{
retval = false;
}
return retval;
}
Is there anything out there like this? I can't find anything. This would be very useful. Thanks.
Could you use a lambda as a wrapper?
MyClass myClass = new MyClass();
bool val = RangeCheck(0, 10, () => myClass.MyProperty);
If you're looking to do both, you would make two lambdas, one for set, and one for get.
bool val = RangeCheck(0, 10, () => myClass.MyProperty, (y) => myClass.MyProperty = y);
My syntax is probably off, but I think this gives the idea.
Not that I know of. You could try using reflection and pass the object along with the corresponding PropertyInfo object of the property you want to get the value of. You then call PropertyInfo's SetValue function to assign a value to it (assuming it's read/write, of course).
public void SetMyIntValue()
{
SetPropertyValue(this, this.GetType().GetProperty("MyInt"));
}
public int MyInt { get; set; }
public void SetPropertyValue(object obj, PropertyInfo pInfo)
{
pInfo.SetValue(obj, 5);
}
Why not simply make it a ref argument?
public bool RangeCheck(int min, int max, ref int someProperty)
You can now set the value of someProperty inside the method.
And call it like so:
RangeCheck(min, max, ref myProperty);
You could use a Func like this Func<int, T>
void Main()
{
var sc = new SimpleClass();
var result = RangeCheck(0, 10, x => sc.Value = x );
System.Console.WriteLine(result);
System.Console.WriteLine(sc.Value);
}
public class SimpleClass
{
public int Value { get; set; }
}
public bool RangeCheck<T>(int minVal, int maxVal, Func<int, T> someMethod)
{
bool retval = true;
try
{
for (int count = minVal; count <= maxVal; count++)
{
//someMethod(count); //is not a range check,
//Did you mean
someMethod(count - minValue);
}
}
catch
{
retval = false;
}
return retval;
}