(C# VB) Could I change all variables' values in a class dynamically? - c#

I've seen ways to list all variables in a certain class, but is there a way to set their values?
I want a method I can call, and it can reset all variables' values to false / 0 , I know I can manually set those to false / 0, but any change to their values would mess up everything, and I'm just seeing if there's anything more dynamic / easy way that this could be done ?
Currently I'm doing the following:
// These are just some of the vars that are here.
Error = false;
double GUM = 0, MUM = 0;
decimal Mass = 0, GAcc = 0, Fg = 0, FµsRes = 0, FµkRes = 0, Fµs = FµsNS.Value, Fµk = FµkNS.Value;

As others have mentioned, you could use Reflection to set all the class fields to their default values:
using System;
namespace ConsoleApp
{
class Program
{
static void Main(string[] args)
{
var myClass = new MyClass();
myClass.Error = true;
myClass.GUM = 1;
myClass.MUM = 2;
myClass.Mass = 3.5m;
myClass.GAcc = 4.5m;
myClass.Fg = 5.5m;
ResetFields(myClass);
// All fields are reseted
}
public static void ResetFields(object source)
{
foreach (var fieldInfo in source.GetType().GetFields() )
{
fieldInfo.SetValue(source, GetDefault(fieldInfo.FieldType) );
}
}
public static object GetDefault(Type type)
{
if (type.IsValueType)
{
return Activator.CreateInstance(type);
}
return null;
}
}
public class MyClass
{
public bool Error = false;
public double GUM = 0, MUM = 0;
public decimal Mass = 0, GAcc = 0, Fg = 0;
//etc etc
}
}
A better approach however, is to create a class to only hold the values and re-create it when needed:
namespace ConsoleApp
{
class Program
{
static void Main(string[] args)
{
var myClass = new MyClass();
myClass.Variables = new MyVariables();
myClass.Variables.Error = true;
myClass.Variables.GUM = 1;
myClass.Variables.MUM = 2;
myClass.Variables.Mass = 3.5m;
myClass.Variables.GAcc = 4.5m;
myClass.Variables.Fg = 5.5m;
myClass.Variables = new MyVariables();
// All fields are reseted
}
}
public class MyVariables
{
public bool Error = false;
public double GUM = 0, MUM = 0;
public decimal Mass = 0, GAcc = 0, Fg = 0;
}
public class MyClass
{
public MyVariables Variables;
// etc etc
public int Xyz
{
get { return Variables.GUM + Variables.MUM; } // Use calculated properties
}
}
}
The GetDefault method is shown in this answer.

Related

c# Accessing specific members of a class with a list without Reflection

I want to check specific fields of a class for content. If there is no value, it should give a message. The current example is working. But I am looking for a way to to the same without Reflection.
using System;
using System.Reflection;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
TableDescription table1 = new TableDescription { BUYER_AID = 0, DESCRIPTION_LONG = 3, EAN = 2, SUPPLIER = 17};
TableDescription table2 = new TableDescription();
string [] members = new string[] { "BUYER_AID", "DESCRIPTION_LONG", "EAN" };
CheckAndSetValue(table1, table2, members);
}
static void CheckAndSetValue(TableDescription t1, TableDescription t2, string[] list)
{
foreach (string name in list)
{
Type type = typeof(TableDescription);
FieldInfo typeinfo = type.GetField(name);
short value = Convert.ToInt16(typeinfo.GetValue(t1));
if (0 != value)
{
typeinfo.SetValue(t2, value);
}
else
{
Console.WriteLine($"Value for {name} is missing!");
}
}
}
}
public class TableDescription
{
public short BUYER_AID = 0;
public short DESCRIPTION_LONG = 0;
public short EAN = 0;
public short SUPPLIER = 0;
}
}
Is there a way to to it something like:
var[] members = new var[]{TableDescription.BUYER_AID, TableDescription.DESCRIPTION_LONG, TableDescription.EAN};
I am looking for a solution to work without stings. Working with Strings will make trouble with refactoring and on error it will crash during runtime.

XMl Serialize and Deserialize Multiple derived Classes in C# [duplicate]

This question already has answers here:
Using XmlSerializer to serialize derived classes
(3 answers)
Closed 4 years ago.
I tried following the Microsoft website documentation for addressing the above question. However, I'm not able to find the answer. So I tried writing the code, but my object is not getting serialized when I added more derived classes.
Here goes the code:
using System;
using System.IO;
using System.Xml.Serialization;
using System.Collections.Generic;
public class Orchestra
{
// public Instrument[] Instruments;
public List<Instrument> Instruments;
public int i;
public float f;
public string s1;
public string s2;
public B bc;
}
public class B
{
public double dd;
}
public class Instrument
{
public string Name;
}
public class Brass : Instrument
{
public bool IsValved;
}
public class Percussion : Instrument
{
public string name;
}
public class Run
{
public static void Main()
{
Run test = new Run();
test.SerializeObject("Override.xml");
test.DeserializeObject("Override.xml");
}
public void SerializeObject(string filename)
{
/* Each overridden field, property, or type requires
an XmlAttributes object. */
XmlAttributes attrs = new XmlAttributes();
/* Create an XmlElementAttribute to override the
field that returns Instrument objects. The overridden field
returns Brass objects instead. */
XmlElementAttribute attr = new XmlElementAttribute();
attr.ElementName = "Brass";
attr.Type = typeof(Brass);
attrs.XmlElements.Add(attr);
// attrs.XmlArrayItems.Add(attr);
attr.ElementName = "Percussion";
attr.Type = typeof(Percussion);
// Add the element to the collection of elements.
attrs.XmlElements.Add(attr);
// Create the XmlAttributeOverrides object.
XmlAttributeOverrides attrOverrides = new XmlAttributeOverrides();
/* Add the type of the class that contains the overridden
member and the XmlAttributes to override it with to the
XmlAttributeOverrides object. */
attrOverrides.Add(typeof(Orchestra), "Instruments", attrs);
// Create the XmlSerializer using the XmlAttributeOverrides.
XmlSerializer s =
new XmlSerializer(typeof(Orchestra), attrOverrides);
// Writing the file requires a TextWriter.
TextWriter writer = new StreamWriter(filename);
// Create the object that will be serialized.
Orchestra band = new Orchestra();
// Create an object of the derived type.
//Brass i = new Brass();
//i.Name = "Trumpet";
//i.IsValved = true;
//Instrument[] myInstruments = { i };
//band.Instruments = myInstruments;
List<Instrument> myInstruments = new List<Instrument>();
myInstruments.Add(new Brass() { Name = "Trumpet", IsValved = true });
myInstruments.Add(new Percussion() { Name = "Percussion", name = "Mridangam" });
band.Instruments = myInstruments;
band.i = 128;
band.f = 5.678f;
band.s1 = "Hi!";
band.s2 = "GOOD!!!";
B b = new B();
b.dd = 2.35674848;
band.bc = b;
// Serialize the object.
s.Serialize(writer, band);
writer.Close();
}
public void DeserializeObject(string filename)
{
XmlAttributeOverrides attrOverrides =
new XmlAttributeOverrides();
XmlAttributes attrs = new XmlAttributes();
// Create an XmlElementAttribute to override the Instrument.
XmlElementAttribute attr = new XmlElementAttribute();
attr.ElementName = "Brass";
attr.Type = typeof(Brass);
// Add the element to the collection of elements.
attrs.XmlElements.Add(attr);
attrOverrides.Add(typeof(Orchestra), "Instruments", attrs);
// Create the XmlSerializer using the XmlAttributeOverrides.
XmlSerializer s =
new XmlSerializer(typeof(Orchestra), attrOverrides);
FileStream fs = new FileStream(filename, FileMode.Open);
Orchestra band = (Orchestra)s.Deserialize(fs);
Console.WriteLine(band.i);
Console.WriteLine(band.f);
Console.WriteLine(band.s1);
Console.WriteLine(band.s2);
Console.WriteLine(band.bc.dd);
Console.WriteLine("Brass:");
/* The difference between deserializing the overridden
XML document and serializing it is this: To read the derived
object values, you must declare an object of the derived type
(Brass), and cast the Instrument instance to it. */
//Brass b;
//Percussion p;
Brass b;
// Percussion p;
//b = (Brass)i;
// int ii = 0;
foreach (Instrument i in band.Instruments)
//foreach(Instrument i in band.List<Instrument>)
{
// int i = 0;
// ii++;
// if (ii == 1)
// {
b = (Brass)i;
Console.WriteLine(
b.Name + "\n" +
b.IsValved);
// }
/*if (ii == 2)
{
p = (Percussion)i;
Console.WriteLine(
p.Name + "\n" +
p.name);
}*/
}
}
}
I even tried using XmlArrayItem. Could anyone guide how to go about this?
You have to add a new class Instruments to your code. See code below :
using System;
using System.IO;
using System.Xml.Serialization;
using System.Collections.Generic;
using System.Xml;
public class Orchestras
{
public List<Orchestra> orchestras = new List<Orchestra>();
}
public class Orchestra
{
[XmlElement]
public List<Instrument> Instruments { get; set; }
public int i;
public float f;
public string s1;
public string s2;
public B bc;
}
public class B
{
public double dd;
}
[XmlInclude(typeof(Brass))]
[XmlInclude(typeof(Percussion))]
public class Instrument
{
public string Name;
}
public class Brass : Instrument
{
public bool IsValved;
}
public class Percussion : Instrument
{
public string name;
}
public class Run
{
const string FILENAME = #"c:\temp\test.xml";
public static void Main()
{
Run test = new Run();
test.SerializeObject(FILENAME);
test.DeserializeObject(FILENAME);
}
public void SerializeObject(string filename)
{
Orchestras orchastras = new Orchestras();
Orchestra orchestra1 = new Orchestra();
orchastras.orchestras.Add(orchestra1);
List<Instrument> instruments = new List<Instrument>() {
new Instrument() { Name = "Brass"},
new Instrument() { Name = "Percussion"}
};
orchestra1.Instruments = instruments;
// Create the XmlSerializer using the XmlAttributeOverrides.
XmlSerializer s = new XmlSerializer(typeof(Orchestras));
// Writing the file requires a TextWriter.
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
XmlWriter writer = XmlWriter.Create(filename,settings);
// Create the object that will be serialized.
Orchestra band = new Orchestra();
orchastras.orchestras.Add(band);
// Create an object of the derived type.
//Brass i = new Brass();
//i.Name = "Trumpet";
//i.IsValved = true;
//Instrument[] myInstruments = { i };
//band.Instruments = myInstruments;
List<Instrument> myInstruments = new List<Instrument>();
myInstruments.Add(new Brass() { Name = "Trumpet", IsValved = true });
myInstruments.Add(new Percussion() { Name = "Percussion", name = "Mridangam" });
band.Instruments = myInstruments;
band.i = 128;
band.f = 5.678f;
band.s1 = "Hi!";
band.s2 = "GOOD!!!";
B b = new B();
b.dd = 2.35674848;
band.bc = b;
// Serialize the object.
s.Serialize(writer, orchastras);
writer.Close();
}
public void DeserializeObject(string filename)
{
// Create the XmlSerializer using the XmlAttributeOverrides.
XmlSerializer s =
new XmlSerializer(typeof(Orchestras));
FileStream fs = new FileStream(filename, FileMode.Open);
Orchestras band = (Orchestras)s.Deserialize(fs);
Console.WriteLine(band.orchestras[1].i);
Console.WriteLine(band.orchestras[1].f);
Console.WriteLine(band.orchestras[1].s1);
Console.WriteLine(band.orchestras[1].s2);
Console.WriteLine(band.orchestras[1].bc.dd);
Console.WriteLine("Brass:");
/* The difference between deserializing the overridden
XML document and serializing it is this: To read the derived
object values, you must declare an object of the derived type
(Brass), and cast the Instrument instance to it. */
//Brass b;
//Percussion p;
Instrument b;
// Percussion p;
//b = (Brass)i;
// int ii = 0;
foreach (Instrument i in band.orchestras[1].Instruments)
//foreach(Instrument i in band.List<Instrument>)
{
// int i = 0;
// ii++;
// if (ii == 1)
// {
b = i;
Console.WriteLine(
b.Name + "\n");
// }
/*if (ii == 2)
{
p = (Percussion)i;
Console.WriteLine(
p.Name + "\n" +
p.name);
}*/
}
}
}

Using enum item to call a method

I have an enum with 30 items in it. Each item has a corresponding function with the same name. I would like to be able to call the function by referencing the enum at a certain position.
So if the value at enum[0] = Foo, I would like to be able to call Foo(string bar) by using something like enum(0)("foobar")
In the end the point is I am running each function as a task like so:
enum Test { AA, BB, CC, DD ....}
tasks[0] = Task.Run(() => { prices[0] = AA("a string"); });
tasks[1] = Task.Run(() => { prices[1] = BB("a string"); });
tasks[2] = Task.Run(() => { prices[2] = CC("a string"); });
//for 30 tasks
What I would like to do is something along the lines of:
enum Test { AA, BB, CC, DD ....}
for (int i = 0; i < 30; i++)
{
tasks[i] = Task.Run(() => { prices[i] = (Test)i("a string"); });
}
Task.WaitAll(tasks.ToArray());
Is this something that is even possible?
EDIT:
The enum relates to controls on a form so i have an array of textboxs, label and a array of prices that is populated with the results of the functions:
enum Dealers { Dealer1, Dealer2 ... Dealer29, Dealer30 };
static int noOfDealers = Enum.GetNames(typeof(Dealers)).Length;
decimal[] prices = new decimal[noOfDealers];
TextBox[] textBox = new TextBox[noOfDealers];
Label[] boxes = new Label[noOfDealers];
for (int i = 0; i < noOfDealers; i++)
{
textBox[i] = Controls.Find("txt" + (Dealers)i, true)[0] as TextBox;
boxes[i] = Controls.Find("box" + (Dealers)i, true)[0] as Label;
prices[i] = 0;
}
//RUN 30 TASKS TO POPULATE THE PRICES ARRAY
for (int i = 0; i < noOfDealers; i++)
{
textBox[i].Text = "£" + prices[i].ToString();
}
//LOOP THROUGH PRICES ARRAY AND FIND CHEAPEST PRICE, THEN COLOUR THE LABEL BACKGROUND GREEN FOR THE TEXT BOX WITH THE NAME AT ENUM VALUE WHATEVER I IS
I guess i am just trying to make my code as concise as possible, there is the potential for the amount of tasks to double and didn't want to end up with 60 lines to populate the tasks array
I would create dictionary and map enum to actions:
Dictionary<Test, Func<string,double>> actions = new Dictionary<Test, Func<string,double>>()
{
{Test.AA, (x) => { return 5;}},
{Test.BB, (x) => { return 15; }},
}; //x is your string
var res = actions[Test.AA]("hello");
I would strongly suggest using a built in construct - like an extension method and a simple switch:
public static int GetPriceWithString(this Test test, string str)
{
switch (test)
{
case Test.AA:
break;
case Test.BB:
break;
case Test.CC:
break;
case Test.DD:
break;
default:
throw new ArgumentOutOfRangeException(nameof(test), test, null);
}
}
then your loop looks almost the same:
for (int i = 0; i < 30; i++)
{
tasks[i] = Task.Run(() =>
{
prices[i] = ((Test)i).GetPriceWithString("a string");
});
}
What you want to do is possible with reflection, which can be a powerful tool - but ideally should only be used as a last resort, as it will hide what could be compile time errors, and cause less code readability.
Using a simple switch like this makes your code self-documented, so when you come back to this in a month you can quickly remember what the intention was.
How about using an array of delegates:
using System;
using System.Threading.Tasks;
namespace ConsoleApplication
{
class Program
{
private static int AA(string a) { return 0; }
private static int BB(string a) { return 1; }
private static int CC(string a) { return 2; }
private static Func<string, int>[] functions = new Func<string, int>[] { AA, BB, CC };
private static int[] prices = new int[functions.Length];
private static Task[] tasks = new Task[functions.Length];
static void Main(string[] args)
{
for (int i = 0; i < functions.Length; ++i)
tasks[i] = Task.Run(() => { prices[i] = functions[i]("a string"); });
Task.WaitAll(tasks);
}
}
}
An eg. speaks a lot more than words.
I used it in a winform so the this refers to win form.
I have assumed all your methods are public , have same signature & return the same type.
enum MyName { AA,BB,CC};
//Call this in one of your methods
string [] strVal= Enum.GetNames(typeof(MyName));
int x = CallFunction(strVal[0], "A");
int y = CallFunction(strVal[1], "h");
int z = CallFunction(strVal[1], "C");
//End Call this in one of your methods
int CallFunction(string strName,string strValue)
{
return Convert.ToInt32(this.GetType().InvokeMember(strName, BindingFlags.Public | BindingFlags.InvokeMethod|BindingFlags.Instance, null, this, new object[] { strValue }));
}
public int AA(string s)
{
return 1;
}
public int BB(string s)
{
return 2;
}
public int CC(string s)
{
return 3;
}
Another solution. I hope somebody will consider it as overkill :)
Create abstract class DealerBase.
public abstract class DealerBase
{
public string Name { get; }
public decimal Price { get; set; }
protected DealerBase(string name)
{
Name = name;
}
public abstract void UpdatePrice();
}
Then create classes for every dealers you have and implement own logic for UpdatePrice method.
public class Dealer1 : DealerBase
{
public Dealer1() : base("DealerOne") { }
public override void UpdatePrice()
{
//Calculate price
Price = DealerOneCalculationMethod();
}
}
public class Dealer2 : DealerBase
{
public Dealer2() : base("DealerTwo") { }
public override void UpdatePrice()
{
//Calculate price
Price = DealerTwoCalculationMethod();
}
}
And so on..
Then you just create collection of dealers which can be easily iterated
var dealers = new List<DealerBase>
{
new Dealer1(),
new Dealer2()
}
foreach(var dealer in dealers)
{
dealer.UpdatePrice();
}
You can loop dealers and generate textboxes, labels in the winforms.
But I suggest to use DataGridView where code will be tiny clearer.
First implement INotifyPropertyChanged interface in the base class DealerBase
public abstract class DealerBase : INotifyPropertyChanged
{
public string Name { get; }
protected decimal _Price;
public decimal Price
{
get { return _Price; }
set
{
if (Equals(_Price, value)) return;
_Price = value;
// next method will inform DataGridView about changes
// and update value there too
RaisePropertyChanged();
}
protected DealerBase(string name)
{
Name = name;
}
public abstract void UpdatePrice();
// Implementation of INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
The in the Form you can create BindingList<DealerViewModelBase> and set it to DataGridView.DataSource
public class YourForm: Form
{
public YourForm()
{
InitializeComponent();
var dealers = new List<DealerBase>
{
new Dealer1(),
new Dealer2()
};
var bindSource = new BindingList<DealerBase>(dealers);
dataGridView.DataSource = bindSource;
}
// Add button which update prices for all dealers
private void ButtonUpdatePrices_Click(object sender, EventArgs e)
{
var dealers = (BindingList<DealerBase>)dataGridView.DataSource;
foreach (var dealer in dealers)
{
dealer.UpdatePrice();
// Because we call `RaisePropertyChanged` in
// setter of Price - prices will be automatically
// updated in DataGridView
}
}
}
Idea of this approach you put different logic of different dealers in the separated class which. Because all dealer classes will inherit from same abstract class you can add different dealers to the collection.
You already have hardcoded enums and correspondent method which you try to link together. This approach make using of dealers collection little bid easy

Assignment to struct array inside method does not work in C#?

Here is the code snippet from my LinqPad:
public class Elephant{
public int Size;
public Elephant()
{
Size = 1;
}
}
public struct Ant{
public int Size;
}
private T[] Transform2AnotherType<T>(Elephant[] elephantList)
where T:new()
{
dynamic tArray = new T[elephantList.Length];
for (int i = 0; i < elephantList.Length; i++)
{
tArray[i] = new T();
tArray[i].Size = 100;
//tArray[i].Dump();
}
return tArray;
}
void Main()
{
var elephantList = new Elephant[2];
var elephant1 = new Elephant();
var elephant2 = new Elephant();
elephantList[0] = elephant1;
elephantList[1] = elephant2;
elephantList.Dump();
var r = Transform2AnotherType<Ant>(elephantList);
r.Dump();
}
I want to change one object array of known type,Elephant,to another object array of type T. T is not a class,but limited to struct which
provided by the already existed API.And every instance of type T shares some common property,says Size,but also has their own particular property which
I have omitted in my example code.So I put dynamic keyword inside the Transform2AnotherType<T>.
And I could not even to use Dump to make sure if the assignment has made effect,thus will throw RuntimeBinderException.
My question is: how to correctly make the assignment in such a struct array and return it back properly?
I suggest change your code like this:
public class Elephant
{
public Elephant()
{
Size = 1;
}
public int Size { get; set; }
}
public struct Ant
{
public int Size { get; set; }
}
private static T[] Transform2AnotherType<T>(Elephant[] elephantList)
where T : new()
{
T[] tArray = new T[elephantList.Length];
for (int i = 0; i < elephantList.Length; i++)
{
dynamic arrayElement = new T();
arrayElement.Size = 100;
tArray[i] = arrayElement;
//tArray[i].Dump();
}
return tArray;
}
static void Main()
{
var elephantList = new Elephant[2];
var elephant1 = new Elephant();
var elephant2 = new Elephant();
elephantList[0] = elephant1;
elephantList[1] = elephant2;
//elephantList.Dump();
var r = Transform2AnotherType<Ant>(elephantList);
//r.Dump();
}

Several strategies for serialization

I have a class, which can be serialized using binary formatter. I want to have a two strategies for serializing. The second strategy should be different from the main one by excluding some specific fields from being serialized. How can I achieve this?
You can use NonSerializedAttribute on that field which you don't want to Serialize.
Also look at this MSDN article on this.
Create two memento classes each with the information you want to serialize, and add code to read in/out the values from the main class to the memento classes.
link to Memento strategy in Wikipedia.
link to dotfactory article on the strategy with C# and VB.NET
Example
Crate a class with two dependent properties, "number" and "square". Setting each one completely defines the class. Create two seriazation classes to serialize the main class two different ways:
class Data // The main class to store data in
{
int x;
public Data() { this.x = 0; }
public int Number
{
get { return x; }
set { x = value; }
}
public int Square
{
get { return x * x; }
set { x = (int)Math.Sqrt(value); }
}
public void FromNumberStore(NumberMemento mem)
{
this.Number = mem.Number;
}
public void FromSqureStore(SquareMemento mem)
{
this.Square = mem.Square;
}
}
[Serializable]
class NumberMemento // memento #1
{
int x;
public NumberMemento() { x = 0; }
public NumberMemento(Data data)
{
this.x = data.Number;
}
public int Number
{
get { return x; }
set { x = value; }
}
}
[Serializable]
class SquareMemento // memento #2
{
int x2;
public SquareMemento() { x2 = 0; }
public SquareMemento(Data data)
{
this.x2 = data.Square;
}
public int Square
{
get { return x2; }
set { x2 = value; }
}
}
class Program // Sample code to check all around serialization.
{
static void Main(string[] args)
{
Data store = new Data();
store.Number = 9;
{
// Write and read based on number
NumberMemento mem1 = new NumberMemento(store);
BinaryFormatter bf1 = new BinaryFormatter();
FileStream fs = new FileStream("numstore.dat", FileMode.Create);
bf1.Serialize(fs, mem1);
fs.Close();
// clear data and deserialize
store.Number = 0;
fs = new FileStream("numstore.dat", FileMode.Open);
mem1 = bf1.Deserialize(fs) as NumberMemento;
fs.Close();
store.FromNumberStore(mem1);
// check store.Number == 9
}
{
// Write and read based on square
SquareMemento mem2 = new SquareMemento(store);
BinaryFormatter bf2 = new BinaryFormatter();
FileStream fs = new FileStream("sqrstore.dat", FileMode.Create);
bf2.Serialize(fs, mem2);
fs.Close();
// clear data and deserialize
store.Number = 0;
fs = new FileStream("sqrstore.dat", FileMode.Open);
mem2 = bf2.Deserialize(fs) as SquareMemento;
fs.Close();
store.FromSqureStore(mem2);
// check store.Number == 9
}
}
}

Categories

Resources