Saving instructions for later evaluation, possible? - c#

I want to save "instructions" for how a value should be determined at a later time, instead of saving the actual value at the current time.
Is this even possible?
A simple C# example:
int[] myArray = new int[2];
Dictionary<string, int> myDictionary = new Dictionary<string, int>();
//dictionary type can be changed if required
myArray[0] = 1;
myArray[1] = 2;
myDictionary.Add("total", (myArray[0] + myArray[1]) ); // Don't evaluate the value now
myArray[0] = 3;
myArray[1] = 4;
Console.WriteLine("total 2 = " + myDictionary["total"]); // Evaluate the value now
//Desired output: 7 (3+4), actual output = 3 (1+2)

You could use (expression bodied read-only) properties:
public int[] MyArray { get; set; }
public string CurrentResult => $"total: {MyArray.Sum()} ({string.Join("+", MyArray)})";
You can use local functions if you need local variables:
string GetCurrentResult() => $"total: {MyArray.Sum()} ({string.Join("+", MyArray)})";
MyArray[0] = 1;
MyArray[1] = 2;
Console.WriteLine(GetCurrentResult()); // total: 3 (1+2)
MyArray[0] = 3;
MyArray[1] = 4;
Console.WriteLine(GetCurrentResult()); // total: 7 (3+4)
If you don't use C#7 you could use a Func<string> delegate:
Func<string> GetCurrentResult = () => $"total: {MyArray.Sum()} ({string.Join("+", MyArray)})";

You are looking for Lazy<T>. It takes a Func<T> that doesn't evaluate until it is accessed via the Value property. Once it is evaluated, the result is stored for further access. So your code might look something like:
int[] myArray = new int[2];
var total = new Lazy<int>(() => myArray.Sum());
myArray[0] = 1;
myArray[1] = 2;
myArray[0] = 3;
myArray[1] = 4;
Console.WriteLine("total = " + total);
Console.WriteLine("total = " + total.Value);
Console.WriteLine("total = " + total);
The output of this code is:
total = Value is not created.
total = 7
total = 7
Note that, without calling total.Value, the result is not an int but rather a message telling us the expression hasn't been evaluated yet. Once total.Value has been called, subsequent accesses to total yield the value (due to implicit ToString() call in the Console.WriteLine()).
The benefit of using Lazy<T> is that the value is persisted, instead of being recalculated each time it is accessed. This makes it great for properties/fields in classes that may not be accessed each time the class is used but take a long time to generate a value.
Edit: Based on Op's feedback Lazy<T> isn't exactly what they are looking for.
If you always want to evaluate the expression each time it is accessed, you want a method or Func<T>. So imagine you have a class like this:
public class MyClass
{
public int[] Vals {get;set;}
}
If you want to define a custom way of getting the (for example) sum of Vals, you have a couple of simple options.
A Class method
public class MyClass
{
public int[] Vals {get;set;}
public int SumOfVals()
{
return Vals.Sum();
}
}
If you opt for the class method, you could (conceivably) make the class generic (MyClass<T>) and use a virtual/abstract method to implement the concrete SumOfVals method.
A Func<T> implemented in the Class
public class MyClass
{
public int[] Vals {get;set;}
public Func<int[], int> SumOfVals { get;set; }
}
Now you can set SumOfVals to some custom function each time the class is instantiated. If you don't set it to anything, you'll get a NullReferenceException if you try to do anything with it.
A Func<T> implemented inline
var vals = new int[2];
var sumVals = new Func<int[], int>((arr) => arr.Sum());
Console.WriteLine(sumVals(vals));
This is probably the most flexible, but this can lead to some spaghetti code. I would recommend just creating either a method in the class that calls into MyClass or creating a method in MyClass to handle this logic.

Related

Using struct in dictionary as a value

Hi I have a struct and dictionary as below and I'm trying to add it as a custom value
like
public struct data_inv
{
//protected static int p;
public float inventory;
public float supply;
public float demand;
};
public static IDictionary<int, data_inv> inv_stored = new Dictionary<int, data_inv>();
and I have tried to add value to dictionary but when I try to add a value like inv_stored[1].demand = 4;
its gives System.Collections.Generic.KeyNotFoundException: 'The given key was not present in the Dictionary.' exception. I'm new to coding, could any explain what im doing wrong
If you want to use a struct instead of a class, write this instead of inv_stored[1].demand = 4 (updated based on comments):
public struct data_inv
{
public float Inventory;
public float Supply;
public float Demand;
public data_inv(int demand)
{
Inventory = 0;
Supply = 0;
Demand = demand;
}
};
// ....
IDictionary<int, data_inv> inv_stored = new Dictionary<int, data_inv>();
data_inv myData = new data_inv(4);
inv_stored.Add(1, myData);
This is a way to add keyValue to a Dictionary.
data_inv shouldn't be a struct. It's mutable, and structs shouldn't be mutable, it's not representing a single value. You should make it a class instead.
public class data_inv
{
//protected static int p;
public float inventory;
public float supply;
public float demand;
};
Implementation:
// Add new item into dictionary
inv_stored.Add(1, new data_inv()
{
inventory = 20,
supply = 10,
demand = 5
});
Console.WriteLine(inv_stored[1].demand); // 5
inv_stored[1].demand = 4;
Console.WriteLine(inv_stored[1].demand); // 4
Edit:
Print all elements each in one line:
foreach (var kvp in inv_stored)
{
Console.Write("bucket:{0} ", kvp.Key);
Console.Write("inventory:{0}, ", kvp.Value.inventory);
Console.Write("supply:{0}, ", kvp.Value.supply);
Console.WriteLine("demand:{0}", kvp.Value.demand);
}
Example output:
bucket:1 inventory:20, supply:10, demand:4
bucket:2 inventory:16, supply:9, demand:7
Print all elements into a table format:
var buckets = inv_stored.Keys;
var inventory = inv_stored.Values.Select(x => x.inventory);
var supply = inv_stored.Values.Select(x => x.supply);
var demand = inv_stored.Values.Select(x => x.demand);
Console.WriteLine("buckets:\t{0}", string.Join("\t", buckets));
Console.WriteLine("inventory:\t{0}", string.Join("\t", inventory));
Console.WriteLine("supply: \t{0}", string.Join("\t", supply));
Console.WriteLine("demand: \t{0}", string.Join("\t", demand));
Example Output:
buckets: 1 2 3
inventory: 20 16 56
supply: 10 9 44
demand: 4 7 23
There's multiple problems with your code.
First, you can create a new record in a dictionary by doing something like dict[key] = value;. However, you can not do dict[key].field = value;. The setter can be used with non-existent keys, the getter can't.
Second, while you can use structs as values in a dictionary, you cannot set their fields directly. Structs use value-type semantics by default (i.e. whenever you don't explicitly use ref or take a pointer), so any change you made this way would be done to a copy of the struct, not the actual value in the dictionary. You can use something like this:
var val = dict[key];
val.field = newFieldValue;
dict[key] = val;
Third, it's generally considered bad practice to use mutable structs, exactly because of these complications. Mutable structs only have place in highly optimised code and native interop, and they need to be carefully tested and monitored. Heck, even many automated refactorings can break code with mutable structs.

Does C# have pointers to members like in C++?

In C++, you could write the following code:
int Animal::*pAge= &Animal::age;
Animal a;
a.*pAge = 50;
Is there similar functionality in C#?
Edit: To clarify, I am not asking about pointers. I am asking about "pointers to members", a feature found in C++ that is used with the .* and ->* operators.
Edit 2: Here is an example of a use case for members to pointers.
Let's say we have the following class:
class Animal
{
int age;
int height;
int weight;
…
}
And let's say that we want to write methods that will find the average age/height/weight/etc. of all Animals in an array. We could then do this:
int averageAge(Animal[] animals)
{
double average = 0;
for (…)
average += animals[i].age;
return average/animals.length;
}
int averageHeight(Animal[] animals)
{
//code here again
}
int averageWeight(Animal[] animals)
{
//code here again
}
We would end up copying and pasting a lot of code here, and if our algorithm for finding the average changed, we would encounter a maintenance nightmare. Thus, we want an abstraction of this process for any member. Consider something like this:
int averageAttribute(Animal[] animals, Func<Animal, int> getter)
{
double average = 0;
for (…)
average += getter(animals[i]);
return average/animals.length;
}
which we could then call with
averageAttribute(animals, (animal) => animal.age);
or something similar. However, using delegates is slower than it has to be; we are using an entire function just to return the value at a certain location in the Animal struct. In C++, members to pointers allow you to do pointer math (not the right term but I can't think of a better term) on structs. Just as you can say
int p_fourthAnimal = 3;
(animals + p_fourthAnimal)*
to get the value so many bytes ahead of the pointer stored in the variable animals, in C++, you could say
int Animal::* p_age = &Animal::age;
animal.*p_age //(animal + [the appropriate offset])*
to get the value so many bytes ahead of the pointer stored in the variable animal; conceptually, the compiler will turn animal.*p_age into (animal + [the appropriate offset])*. Thus, we could declare our averageAttribute as this instead:
int averageAttribute(Animal[] animals, Animal::* member)
{
double average = 0;
for (…)
average += animals[i].*member; //(animals[i] + [offset])*
return average/animals.length;
}
which we could then call with
averageAttribute(animals, &Animal::age);
In summary, pointers to members allow you to abstract a method such as our averageAttribute to all members of a struct without having to copy and paste code. While a delegate can achieve the same functionality, it is a rather inefficient way to get a member of a struct if you know you do not actually need the freedom allotted to you by a function, and there could even be edge use cases in which a delegate does not suffice, but I could not give any examples of such use cases. Does C# have similar functionality?
As other people have commented here, delegates are the way to achieve this in C#.
While a delegate can achieve the same functionality, it is a rather
inefficient way to get a member of a struct if you know you do not
actually need the freedom allotted to you by a function
It depends how the compiler and runtime implement that delegate. They could very well see that this is a trivial function and optimize the call away, like they do for trivial getters and setters. In F# for instance you can achieve this:
type Animal = { Age : int }
let getAge (animal:Animal) =
animal.Age
let inline average (prop:Animal->int) (animals:Animal[]) =
let mutable avg = 0.
for animal in animals do
avg <- avg + float(prop(animal)) // no function call in the assembly here when calling averageAge
avg / (float(animals.Length))
let averageAge = average getAge
You can get the same behaviour using delegates but that's not the same thing as delegates are pointers to functions in C++. What you're trying to achieve is possible in C# but not in the way you're doing in C++.
I think about a solution using Func:
public class Animal
{
public int Age { get; set; }
public int Height { get; set; }
public double Weight { get; set; }
public string Name { get; set; }
public static double AverageAttributeDelegates(List<Animal> animals, Func<Animal, int> getter)
{
double average = 0;
foreach(Animal animal in animals)
{
average += getter(animal);
}
return average/animals.Count;
}
}
List<Animal> animals = new List<Animal> { new Animal { Age = 1, Height = 2, Weight = 2.5, Name = "a" }, new Animal { Age = 3, Height = 1, Weight = 3.5, Name = "b" } };
Animal.AverageAttributeDelegates(animals, x => x.Age); //2
Animal.AverageAttributeDelegates(animals, x => x.Height); //1.5
It's working but you are bound to the int type of the property since the func is declared as Func<Animal, int>. You could set to object and handle the cast:
public static double AverageAttributeDelegates2(List<Animal> animals, Func<Animal, object> getter)
{
double average = 0;
foreach(Animal animal in animals)
{
int value = 0;
object rawValue = getter(animal);
try
{
//Handle the cast of the value
value = Convert.ToInt32(rawValue);
average += value;
}
catch(Exception)
{}
}
return average/animals.Count;
}
Example:
Animal.AverageAttributeDelegates2(animals, x => x.Height).Dump(); //1.5
Animal.AverageAttributeDelegates2(animals, x => x.Weight).Dump(); //3
Animal.AverageAttributeDelegates2(animals, x => x.Name).Dump(); //0
no, c# doesn't have a feature to point into (reference) object's members the way c++ does.
but why?
A pointer is considered unsafe. And even in unsafe area you cannot point to a reference or to a struct that contains references, because an object reference can be garbage collected even if a pointer is pointing to it. The garbage collector does not keep track of whether an object is being pointed to by any pointer types.
you mentioned a lot of duplicate code is used to implement it the non-pointer way, which isn't true.
Speed depends on how well the JIT compiles it, but you didn't test?
if you really run into performance problems, you need to think about your data structures and less about a certain way to access members.
If think the amount of comments under your Q shows, that you did not really hit a commonly accepted drawback of c#
var Animals = new Animal[100];
//fill array
var AvgAnimal = new Animal() {
age = (int)Animals.Average(a => a.age ),
height = (int)Animals.Average(a => a.height),
weight = (int)Animals.Average(a => a.weight)
};
the unsafe area of c# serves some ways access members by pointer, but only to value types like single structs and not for an array of structs.
struct CoOrds
{
public int x;
public int y;
}
class AccessMembers
{
static void Main()
{
CoOrds home;
unsafe
{
CoOrds* p = &home;
p->x = 25;
p->y = 12;
System.Console.WriteLine("The coordinates are: x={0}, y={1}", p->x, p->y );
}
}
}

Having an integer inside a method that increases by 1 everytime the method was called to a specific object of a lass

I have a 'Movie' class in my C# code that has an int[] ratings = new int[10]; as a field. I would like to place numbers in this empty array from my main program.
For that, I would need a method, that could point to the actual free index of the array to put the integer there, but the other integer that would point to the free index would be reset to 0 everytime the method is called. Thus, my question is, that how can I place an integer in my method that is increased everytime the method was called.
This is the method in the class:
public void Rate(int rating)
{
int x = 0;
ratings[x] = rating;
}
This is how I call it in the main program
Movie asd = new Movie(blabla...);
Rate.asd(1);
Rate.asd(1);
Rate.asd(1);
So I called it 3 times, and I would want the 'x' integer in the class's method to increase.
Thanks in advance.
First of all, you have an error in the code you have posted.
As I suppose rather than:
Movie asd = new Movie(blabla...);
Rate.asd(1);
Rate.asd(1);
Rate.asd(1);
you want to paste here:
Movie asd = new Movie(blabla...);
asd.Rate(1);
asd.Rate(1);
asd.Rate(1);
As C# does not allow to use static method variables (like i.e. C++ does) you have two options:
first, make x value (from Rate method) a Movie's class variable, so Rate method will "remember" the next index,
second (and better) rather than intiger array - if possible use any kind of list or queue (which can manage indexing for you).
The problem is that local variables are discarded when exiting a method.
class SomeClass
{
private int x = 42;
public void DoSometing(int y)
{
int a = y + 5;
x += a * a;
// a stops to exist here
}
}
Solution is to store the variable in the containing class as well
class SomeOtherClass
{
private int x = 42;
private int a = 0;
public void DoSomething(int y)
{
a = y + 5;
x += a * a;
}
}
Now SomeOtherClass remembers the value of a. That's basically the point of member variables a.k.a. fields - to store the state of the object.
More appropriate for your problem:
class ClassWithAnArrayAndCount
{
private int[] values = new int[10];
private int taken = 0;
public void Add(int value)
{
if (taken == 10)
throw new ArgumentOutOfRangeException(); // sorry, no more space
values[taken++] = value;
}
public int Taken { get { return taken; } }
}

Update a variable inside ForEach loop

I simply can't understand why this simple code is not working. My expected output is 10 and 15, but it is returning 2 and 3. That means that the update is not working.
List<int> numbers = new List<int>();
numbers.Add(2);
numbers.Add(3);
numbers.ForEach(n => n = n*5);
numbers.ForEach(n => Console.WriteLine(n));
Note: I've already searched a lot, but I could not understand this behavior.
How should I fix it?
Update: the same behavior for strings.
List<string> strings = new List<string>();
strings.Add("a");
strings.Add("b");
strings.ForEach(s => s = s + "--");
strings.ForEach(s => Console.WriteLine(s));
n is a copy of your current value in the list not a reference to your value.If you want to manipulate the values in your list then use a for loop
for(int i = 0; i<numbers.Count; i++)
numbers[i] *= 5;
More detailed explanation:
With a normal foreach loop your code doesn't even compile:
foreach(var n in numbers)
n = n * 5; // Readonly local variable cannot be used as an assignment target
Remember that List<T>.ForEach loop is not the same as foreach but it is just a method that takes a Action<int> delegate as argument and performs the specified action on the each element in your list.So it performs something like this (taken from the source code):
public void ForEach(Action<T> action)
{
// removed unnecessary parts for brevity
for(int i = 0 ; i < _size; i++)
{
action(_items[i]);
}
}
As you can see here the _item[i] is passed to the action and since int is a value types the copy of your value is passed rather than a reference.And that's why your values didn't change.
For strings: Apart from the fact that strings are immutable, assigning a new reference to a reference type doesn't change the object that holds the same reference.For example consider this:
static void Update(string s)
{
s = "bar";
}
string f = "foo";
Update(f);
Console.WriteLine(f); // foo
Assigning a new reference to s doesn't change the f, f stil holds the old reference and s is pointing to a new location in memory.This is not because s is a copy,it's not.If you change a property of s (with strings you can't do that but try with another reference type), it would update the property of f as well.It works in this way because s and f are two different strings that points to the same location in memory.So s is not bound to f.You can think they were declared like this:
string f = "foo";
string s = f;
s = "bar";
The only exception is when you pass f as a ref argument then the assignment will change the f as well:
static void Update(ref string s)
{
s = "bar";
}
string f = "foo";
Update(ref f);
Console.WriteLine(f); // bar
Because they are value types, rather than mutating the list you could create a modified one using Select
var newList= numbers.Select(n => n = n*5);
As imperative programmers, we love mutating things, which is not a brilliant idea!!
The reason why it did not work for strings is that because by default C# passes a copy of the reference rather than the actual reference.
void Fn(string s)
{
s = "not being changed";
}
Main()
{
var hello = "hello";
Fn(hello);
Console.WriteLine (hello); // prints hello again!!
}
However, if you want to change the reference you have to use the ref keyword.
void Fn(ref string s)
{
s = "Unfortunately, changed!";
}
Main()
{
var hello = "hello";
Fn(ref hello);
Console.WriteLine (hello); // Unfortunately, changed!!!
}
I think that changing parameters' values is a terrible idea and you shouldn't be doing that, you should return a new string that contains the new modifications.
The reason is because the parameter to the ForEach are passed by value and not by reference.
However, if you do pass a reference type, it must work as expected as shown below
class Program
{
static void Main(string[] args)
{
List<Frog> numbers = new List<Frog>();
numbers.Add(new Frog { name = "balcha" });
numbers.Add(new Frog { name = "Tibara" });
numbers.ForEach(n => n.name = "Bontu");
numbers.ForEach(n => Console.WriteLine(n.name));
Console.ReadLine();
}
class Frog
{
public string name { get; set; }
}
}
Output:
Bontu
Bontu

C#: Immutable class

I have a class which should be immutable in this class i have only get indexer a private set property so why this is not immutable and i can set some field in array as you could see in main class...
class ImmutableMatice
{
public decimal[,] Array { get; private set; } // immutable Property
public ImmutableMatice(decimal[,] array)
{
Array = array;
}
public decimal this[int index1, int index2]
{
get { return Array[index1, index2]; }
}
........
and in main method if i fill this class with data and change the data
static void Main(string[] args)
{
decimal[,] testData = new[,] {{1m, 2m}, {3m, 4m}};
ImmutableMatice matrix = new ImmutableMatice(testData);
Console.WriteLine(matrix[0,0]); // writes 1
testData[0, 0] = 999;
Console.WriteLine(matrix[0,0]); // writes 999 but i thought it should
// write 1 because class should be immutable?
}
}
Is there any way how to make this class immutable?
Ah yes the solution was copy array to new array in constructor like this:
public ImmutableMatice(decimal[,] array)
{
decimal[,] _array = new decimal[array.GetLength(0),array.GetLength(1)];
//var _array = new decimal[,] { };
for (int i = 0; i < array.GetLength(0); i++)
{
for (int j = 0; j < array.GetLength(1); j++)
{
_array[i, j] = array[i, j];
}
}
Array = _array;
}
That is because you are actually changing the data in the ARRAY, rather than the indexer.
static void Main(string[] args)
{
decimal[,] testData = new[,] {{1m, 2m}, {3m, 4m}};
ImmutableMatice matrix = new ImmutableMatice(testData);
Console.WriteLine(matrix[0,0]); // writes 1
testData[0, 0] = 999; // <--- THATS YOUR PROBLEM
Console.WriteLine(matrix[0,0]); // writes 999 but i thought it should
// write 1 because class should be immutable?
}
You can copy the array into your private property in the constructor to avoid this situation.
Note that you indeed cannot write matrix[0,0] = 999; because the indexer has no setter.
Edit
As Chris pointed out (how could I have missed it myself?) - you shouldn't expose the array as a property at all (which means in most cases it doesn't even have to be a property).
Consider the following code instead:
private decimal[,] _myArray; // That's private stuff - can't go wrong there.
public decimal this[int index1, int index2]
{
// If you only want to allow get data from the array, thats all you ever need
get { return Array[index1, index2]; }
}
Your class is immutable, but the objects inside it aren't.
Having public decimal[,] Array { get; private set; } will only guarantee that you cannot set the property Array to a new instance of Array, but it does not prevent you from accessing the existing object and changing its values (which aren't immutable).
You might want to look into the appropriately named ReadOnlyCollection<T> class.
As #Mike pointed out and I looked past the first time: there's a twist to this because you are accessing the value through the testData object and not through matrix. While the original point still stands, it is more exact to say that the problem you have is that you are changing values in the underlying object which has its reference passed around. You're bypassing the ImmutableMatice object alltogether.
The beforementioned solution of using a ReadOnlyCollection<T> still stands: by creating this read-only wrapper around it, you won't be able to change it anymore afterwards. Howver this is only the case when you actually use it the way its intended: through ImmutableMatice and not through the underlying collection which you still have a reference to.
Another solution that solves this problem is to copy the contents of the original array to another one to "disconnect" it from the array your still have a reference to.
In order to illustrate this, consider the following samples. The first one demonstrates how the underlying reference can still be influenced while the second one shows how it can be solved by copying your values to a new array.
void Main()
{
var arr = new[] { 5 };
var coll = new ReadOnlyCollection<int>(arr);
Console.WriteLine (coll[0]); // 5
arr[0] = 1;
Console.WriteLine (coll[0]); // 1
}
void Main()
{
var arr = new[] { 5 };
var arr2 = new int[] { 0 };
Array.Copy(arr, arr2, arr.Length);
var coll = new ReadOnlyCollection<int>(arr2);
Console.WriteLine (coll[0]); // 5
arr[0] = 1;
Console.WriteLine (coll[0]); // 5
}

Categories

Resources