Access an instance dictionary from a string at runtime? - c#

[Serializable]
public class DOCharStats
{
public int Stamina { get; set; }
public int maxStamina { get; set; }
}
[Serializable]
public class DOMapStats
{
public int xlocation { get; set; }
public int ylocation { get; set; }
}
//Name of char and stats
public static Dictionary<string, DOCharStats> dCharStats = new Dictionary<string, DOCharStats>();
public static Dictionary<string, DOMapStats> dMapStats = new Dictionary<string, DOMapStats>();
//Name of container and dict.
public static Dictionary<string, object> dContainer = new Dictionary<string, object>();
static void Main(string[] args)
{
DOCharStats newStats = new DOCharStats();
dCharStats.Add("MC", newStats);
Console.WriteLine(dCharStats["MC"].Stamina);
Console.WriteLine(dCharStats["MC"].maxStamina);
newStats.Stamina = 5;
newStats.maxStamina = 10;
Console.WriteLine(dCharStats["MC"].Stamina);
Console.WriteLine(dCharStats["MC"].maxStamina);
DOMapStats mapstats = new DOMapStats();
mapstats.xlocation = 20;
mapstats.ylocation = 40;
dMapStats.Add("MC", mapstats);
//How to access dCharStats(dictionary variant) from a string?
dContainer.Add("_dCharStats",dCharStats);
dContainer.Add("_dMapStats", dMapStats);
}
dCharStats and dMapStats will be modified by other methods while the program is running.
I would like to access & modify dCharStats or dMapStats based on a string. I have tried doing this via dContainer, but I am unable to cast dCharStats(object) to dCharStats(Dictionary<String,DOCharStats>) in a generic fashion.
Is there a way to access an instance dictionary (dCharStats) from a string at runtime?

dContainer.Add(_dCharStats, dCharStats);
dContainer.Add("_dMapStats", dMapStats);
object secondObj = (object)dCharStats;
dynamic someObj = dContainer[_dCharStats];
foreach (dynamic blah in someObj)
{
dynamic internalObj = blah.Value;
int somevalue = internalObj.GetType().GetProperty("Stamina").GetValue(internalObj, null);
internalObj.GetType().GetProperty("Stamina").SetValue(internalObj, 8080, null);
}
Console.WriteLine("After:"+dCharStats["MC"].Stamina);
Console.WriteLine("After:" + dCharStats["MC"].maxStamina);
An hour or two after posting this, it looks like using dynamic variables resolves my issue.

Related

how to declare a class using the new keyword as property in a static class in c#

I am currently building a namespace to handle complicated string actions. because I use the this string keyword, I must declare where the functions and properties are located as static. (the name of this class is "StringExtension") now I have another class named StringExtensionSettings and I use its boolean properties to determent what functions in the class StringExtension will be enabled. (for the user to choose what functions he wants to use and what not)
ex:
public class StringExtensionSettings
{
public bool DecryptString { get; set; } = true;
public bool EncryptString { get; set; } = true;
public bool RandomMix { get; set; } = true;
public bool AddMidSubString { get; set; } = true;
}
I don't want to warp the string in a class because it will make it complicated for the user. is there is any way to enable or disable function in a static class based on another class properties? and/or how to declare a class within a static class?
thank you in advance!
Additional resources:
the StringExtension class:
static class StringExtension
{
//this is what I'm trying to declare: gives an error
public StringExtensionSettings StringSettings = new StringExtensionSettings();
public static string AddMidSubString(this string Str, string MidSubString)
{
StringBuilder Result = new StringBuilder(Str);
Result.Insert(Result.Length / 2, MidSubString);
return Result.ToString();
}
public static string RandomMix(this string Str)
{
char[] array = Str.ToCharArray();
Random rng = new Random();
int n = array.Length;
while (n > 1)
{
n--;
int k = rng.Next(n + 1);
var value = array[k];
array[k] = array[n];
array[n] = value;
}
return new string(array);
}
// and more functions...
Follow-up of my comment in the OP
Within a Singleton (class), you are still able/ allowed to define fields.
The singleton design pattern is an interface. It is a popular class
type for programs. It allows a class to enforce that it is only
allocated (read -> created) once.
public sealed class StringExtensionSettings
{
private StringExtensionSettings()
{
}
private static StringExtensionSettings instance = null;
public static StringExtensionSettings Instance
{
get
{
if (instance == null)
{
instance = new StringExtensionSettings();
}
return instance;
}
}
public bool DecryptString { get; set; } = true;
public bool EncryptString { get; set; } = true;
public bool RandomMix { get; set; } = true;
public bool AddMidSubString { get; set; } = true;
}
Usage:
Single Field call
StringExtensionSettings.Instance.AddMidSubString
Implementation
public static string AddMidSubString(this string Str, string MidSubString)
{
if (StringExtensionSettings.Instance.AddMidSubString)
{
StringBuilder Result = new StringBuilder(Str);
Result.Insert(Result.Length / 2, MidSubString);
return Result.ToString();
}
throw new Exception($"Not allowed to call {nameof(AddMidSubString)}");
}
Summarized; calling StringExtensionSettings.Instancecreates a new instance of StringExtensionSettings, only (once!), when the private field instance of StringExtensionSettings is null.

make a snapshoot object of the current status of a static class

I have a static class in my system keeping track of the frequency of measurements, the number of samples currently read, what sensors are on an which are off and all those nice details.
Now I make a measurement and want to create a report in the report I want to save all the information stored in the static class. something like this :
public static class Details{
public static int samplesRead { get; set;}
public static int frequency { get; set;}
public static List<devices> devices { get; set;}
}
public class Patient{...} // name, surname , blabla
public class ResultsSet {
public DateTime date;
public Patient patient;
public *DetailsObject* details;
}
public void main {
patient p = new patient(...);
... make the measurements ...
var results = new ResultSet();
results.patient = p;
results.DateTime = DateTime.Now();
results.details = **here the magic ** Details.ToObject();
results.Serialize(myFilePath);
}
How can one acomplish that conversion to a single defined object?
it is the capability of making an snapshot of the static class in an object. [...] Just make an object.
So what you could do is to create a DTO that has the same properties as your static class:
public class DetailsSnapshot
{
public int samplesRead { get; set; }
public int frequency { get; set; }
public List<device> devices { get; set; }
}
Not you can map and return such an object at any given time:
public static class Details{
public static int samplesRead { get; set;}
public static int frequency { get; set; }
public static List<device> devices { get; set; }
public static DetailsSnapshot MakeSnapShot()
{
return new DetailsSnapshot
{
samplesRead = samplesRead,
frequency = frequency,
devices = devices.ToList()
};
}
}
You can have then such an snap-shot-object in your results:
public class ResultsSet
{
public DateTime date;
public Patient patient;
public DetailsSnapshot detailsSnapShot;
}
and make the snap shot (here the magic) the following way:
results.detailsSnapShot = Details.MakeSnapShot();
EDIT:
There is also a way using reflection. With this approach you would scan your Details class for the properties and extract the values. You could return a Dictionary which basically maps the names of the properties to the values:
public static Dictionary<string, object> MakeSnapShotReflection()
{
PropertyInfo [] allPorperties = typeof(Details).GetProperties(BindingFlags.Public | BindingFlags.Static);
Dictionary<string, object> valuemapping = new Dictionary<string, object>();
for (int i = 0; i < allPorperties.Length; i++)
{
valuemapping.Add(allPorperties[i].Name, allPorperties[i].GetValue(null));
}
return valuemapping;
}
This way would allow you to extend the Details class with further properties without worrying about extending anything else.
Or the short version:
public static Dictionary<string, object> MakeSnapShotReflection()
{
PropertyInfo[] allPorperties = typeof(Details).GetProperties(BindingFlags.Public | BindingFlags.Static);
return allPorperties.ToDictionary(key => key.Name, value => value.GetValue(null));
}
With this approach you could still use intellisens to access the correct values:
Test Data:
public static class Details
{
public static int samplesRead { get; set;} = 100;
public static int frequency { get; set; } = 2700;
public static List<device> devices { get; set; } = new List<device>()
{
new device { Name = "sensor1" },
new device { Name = "sensor 2" }
};
}
public class device
{
public string Name { get; set; }
}
Test Code to access values:
void Main()
{
Dictionary<string, object> details = Details.MakeSnapShotReflection();
Console.WriteLine(details[nameof(Details.frequency)]);
Console.WriteLine(details[nameof(Details.samplesRead)]);
foreach (var element in details[nameof(Details.devices)] as IEnumerable<device>)
{
Console.WriteLine(element.Name);
}
}
OUTPUT:
2700
100
sensor1
sensor 2
If you want to save and restore it, make it a non-static class and serialise/deserialise it using JSON or XML. You can then go JsonConvert.SerialiseObject and JsonConvert.Deserialise object. Nice and simple.
If you want to ensure only one instance, make the class a singleton.
public class Details
{
private static readonly Details _instance = new Details();
static Details()
{
}
private Details()
{
}
public Details Intance
{
get
{
return _instance;
}
}
public int samplesRead { get; set;}
public int frequency { get; set;}
public List<devices> devices { get; set; }
}
Then you can access it's properties this way:
Details.Instance.samplesRead
If the class has to be static, you can use reflection to serialise it:
public static string SerializeStaticProperties(Type type)
{
var properties = type.GetProperties(BindingFlags.Static | BindingFlags.Public);
var data = new List<Property>();
foreach (var property in properties)
{
data.Add(new Property
{
Name = property.Name,
Type = property.PropertyType,
Value = JsonConvert.SerializeObject(property.GetValue(null))
});
}
return JsonConvert.SerializeObject(data);
}
public static void DeserializeStaticProperties(Type type, string json)
{
var data = JsonConvert.DeserializeObject<List<Property>>(json);
foreach (var item in data)
{
var property = type.GetProperty(item.Name, BindingFlags.Static | BindingFlags.Public);
if (property != null)
{
property.SetValue(null, JsonConvert.DeserializeObject(item.Value, item.Type));
}
}
}
public class Property
{
public string Name { get; set; }
public Type Type { get; set; }
public string Value { get; set; }
}

c# need help working with arrays

is there a way to put these into either a 1 D array or a 2 D array. ? i have produced code and it looks a bit untidy as well as long can this be shortened?
double worstPrice = 6.47;
double bestPrice = 0.99;
double CivetCatPrice =29.14;
double whenPrice = 10.50;
double everythingPrice = 319.56;
int bestStock = 3238;
int worstStock = 8;
int civetCatstock = 3;
int whenStock = 37;
int everythingStock = 2;
You can make an array for each doubles and ints like this
double[] priceData = new double[]{ 6.47, 0.99, 29.14, 10.50, 319.56 };
int[] stockData = new int[]{ 3238, 8, 3, 37, 2 };
Alternatively you can use a dictionary if you wish for them to keep their names
Dictionary<string, double> priceDict = new Dictionary<string, double>();
priceDict.Add("worstPrice", 6.47);
//And so on for each double
Dictionary<string, int> stockDict = new Dictionary<string, int>();
priceDict.Add("bestStock", 3238);
//And so on for each int
The values in these can be called like so
double worstMinusBestPrices = priceData[0] - priceData[1]; //For arrays
double worstMinusBestPrices = priceDict["worstPrice"] - priceDict["bestPrice"] //For dictionaries
You could implement a custom class which holds these values as proprties with meaningful names. Then your code will be much more readable, maintainable and robust.
For example (you don't need all of these classes, it should just give you an idea):
public abstract class Animal
{
public Animal(string animalName)
{
this.Name = animalName;
}
//insert properties and methods which all aimals share here
public string Name { get; set; }
}
public class CibetCat : Animal
{
public CibetCat() : base("CibetCat")
{
}
//insert properties and methods which all CibetCats share here
}
Now your class that holds the price and stock informations as well as the reference to the animal itself(CibetCat in your example):
public class AnimalStock // or AnimalPrice or whatever
{
public AnimalStock(Animal animal)
{
this.Animal = animal;
}
public AnimalStock(Animal animal, decimal worstPrice, decimal bestPrice, int bestStock, int worstStock)
{
this.Animal = animal;
this.Worstprice = worstPrice;
this.BestPrice = bestPrice;
this.BestStock = bestStock;
this.WorstStock = worstStock;
}
public Animal Animal { get; set; }
public decimal Worstprice { get; set; }
public decimal BestPrice { get; set; }
public int BestStock { get; set; }
public int WorstStock { get; set; }
// ...
}
Lot of code but not complex. Now You can write this simple and readable code:
Animal cibetCat = new CibetCat();
AnimalStock stock = new AnimalStock(cibetCat);
stock.BestPrice = 0.99m;
stock.Worstprice = 6.47m;
stock.BestStock = 3238;
// ...
Later you can access all these properties(or it's methods) from a single instance.
Console.WriteLine("Animal's best-price is: {0}", stock.BestPrice); // etc
As Alfie pointed out, you could use a dictionary - but you're then referencing things by a string identifier, that you have to remember.
Another way would be to use a class or struct. There are of course many ways to do this, but some include:
public class Things
{
public double worstPrice = 6.47;
public double bestPrice = 0.99;
public double CivetCatPrice =29.14;
public double whenPrice = 10.50;
public double everythingPrice = 319.56;
public int bestStock = 3238;
public int worstStock = 8;
public int civetCatstock = 3;
public int whenStock = 37;
public int everythingStock = 2;
}
Another way would be:
public class Things
{
public double WorstPrice { get; readonly set; }
public double BestPrice = { get; readonly set; }
// etc
public Things(double worstPrice, double bestPrice) // etc
{
WorstPrice = worstPrice;
BestPrice = bestPrice;
}
}
There are pros and cons to both approaches. Another potential is to use a collection of a class/struct to group things and aggregate them in meaningful ways.
Like:
public class Thing
{
public string ThingLabel { get; readonly set; }
public double ThingPrice { get; readonly set; }
public int ThingQuantity { get; readonly set; }
// the value of your stock, calculated automatically based on other properties
public double ThingValue { get { ThingPrice * ThingQuantity; } }
public Thing(string thingLabel, double thingPrice, int thingQuantity)
{
ThingLabel = thingLabel;
// etc
}
}
public void DoStuff()
{
List<Thing> list = new List<Thing>();
Thing thing = new Thing("Civet cat", 500, 10);
list.Add(thing);
list.Add(new Thing("Sea flap flap", 100, 5);
list.Add(new Thing("Nope Rope", 25, 4);
Console.WriteLine("The value of {0}'s stock is: {1}", thing.ThingLabel, thing.Value);
}
and yet another way is to use a base class and create sub classes of your different types. The possibilities are nearly endless! You just have to decide which way works best for you now, you later, and your potential team.

Serialization of two Dictionaries at once

I have two classes as below and I'm using them in two separate Dictionaries. How can I Serialize these two Dictionaries to a single file? my Serialization implementation for a single Dictionary can be found at this link:
Serialize a Dictionary<string, object>
[Serializable]
class Beam
{
public string Name { get; set; }
public double Width { get; set; }
}
[Serializable]
class Column
{
public string Name { get; set; }
public double Width { get; set; }
}
Here are my Dictionaries:
var Dic1 = new Dictionary<string, Beam>
{
{"Beam1", new Beam{Name = "B1", Width = 10}},
{"Beam2", new Beam{Name = "B2", Width = 5}},
};
var Dic2 = new Dictionary<string, Column>
{
{"Column1", new Column{Name = "C1", Width = 10}},
{"Column2", new Column{Name = "C2", Width = 5}},
};
Here is the complete code I've written so far but I'm getting an exception:
[Serializable]
public static class Building
{
public static Dictionary<string, Beam> Beams;
public static Dictionary<string, Column> Columns;
}
[Serializable]
public class Beam
{
public string Name { get; set; }
}
[Serializable]
public class Column
{
public string Name { get; set; }
}
static class Program
{
static void Main()
{
Building.Beams.Add("Beam1", new Beam { Name = "B1"});
Building.Columns.Add("Column1", new Column { Name = "C1" });
Serialize();
}
static void Serialize()
{
var fs = new FileStream("DataFile.dat", FileMode.Create);
var formatter = new BinaryFormatter();
try
{
// I'm getting an excepting here:
// 'Savef.Building' is a 'type' but is used like a 'variable'
formatter.Serialize(fs, Building);
}
catch (SerializationException e)
{
Console.WriteLine("Failed to serialize. Reason: " + e.Message);
throw;
}
finally
{
fs.Close();
}
}
}
Create a class marked with the Serializable attribute, containing instances of these two dictionaries:
[Serializable]
public class Building
{
public static Building Instance = new Building();
public readonly Dictionary<string, Beam> Beams = new Dictionary<string, Beam>();
public readonly Dictionary<string, Column> Columns = new Dictionary<string, Column>();
public static Dictionary<string, Beam> AllBeams
{
get { return Instance.Beams; }
}
}
EDIT
A Singleton pattern used to avoid the exception.
In the other parts of the code use Building.Instance to access the dictionaries.
EDIT2
A static property introduced: Building.AllBeams. You can use it as shorthand.

How to Serialize/DeSerialize a Dictionary variable?

I have a Dictionary variable, the program reads XML files, and then instantiates objects stored in the Dictionary variable by type for performance. I would like to store the Dictionary variable to memcache for reuse, but, because the Dictionary variable and instantiated objects are reference types, when I operate instantiated objects to change some value, the cache value of memcache also changed.
Code like the following.
Dictionary variable and XPathNavigator variable of class can't serialize. How can I Serialize/DeSerialize or achieve a similar effect? Thanks.
namespace ObjectReference
{
public interface IMyObject
{
int Id { get; set; }
string Url { get; set; }
bool State { get; set; }
bool SetItemXml(XPathNavigator navigator);
}
[Serializable]
public class MyLink : IMyObject
{
public int Id { get; set; }
public string Url { get; set; }
public bool State { get; set; }
private XPathNavigator _xmlNavigator;
public bool SetItemXml(XPathNavigator navigator)
{
_xmlNavigator = navigator.Clone();
Id = int.Parse(_xmlNavigator.SelectSingleNode("id").Value);
Url = _xmlNavigator.SelectSingleNode("url").Value;
return true;
}
}
[Serializable]
public class MyPicture : IMyObject
{
public int Id { get; set; }
public string Url { get; set; }
public bool State { get; set; }
private XPathNavigator _xmlNavigator;
public bool SetItemXml(XPathNavigator navigator)
{
_xmlNavigator = navigator.Clone();
Id = int.Parse(_xmlNavigator.SelectSingleNode("id").Value);
Url = _xmlNavigator.SelectSingleNode("url").Value;
return true;
}
}
public partial class _Default : System.Web.UI.Page
{
public IDictionary<string, IDictionary<int, IMyObject>> CreateObjects()
{
IDictionary<string, IDictionary<int, IMyObject>> objects = new Dictionary<string, IDictionary<int, IMyObject>>();
var reader = new XmlTextReader(new StringReader(#"<?xml version='1.0' encoding='utf-8'?><root><item><type>MyLink</type><id>1</id><url>http://www.google.com</url></item><item><type>MyLink</type><id>2</id><url>http://stackoverflow.com</url></item><item><type>MyPicture</type><id>3</id><url>http://static.adzerk.net/Advertisers/2565.png</url></item></root>"));
XPathNavigator navigator = new XPathDocument(reader).CreateNavigator();
XPathNodeIterator nodes = navigator.Select("//root/item");
while (nodes.MoveNext())
{
string classType = nodes.Current.SelectSingleNode("type").Value;
int id = int.Parse(nodes.Current.SelectSingleNode("id").Value);
if (!objects.ContainsKey(classType) || !objects[classType].ContainsKey(id))
{
IMyObject myObject = Activator.CreateInstance(Type.GetType(string.Concat("ObjectReference.", classType))) as IMyObject;
myObject.SetItemXml(nodes.Current);
if (!objects.ContainsKey(classType))
objects.Add(classType, new Dictionary<int, IMyObject>() { { id, myObject } });
else if (!objects[classType].ContainsKey(id))
objects[classType].Add(id, myObject);
}
}
return objects;
}
protected void Page_Load(object sender, EventArgs e)
{
IDictionary<string, IDictionary<int, IMyObject>> ObjectList = new Dictionary<string, IDictionary<int, IMyObject>>();
if (HttpContext.Current.Cache["ObjectCache"] != null)
{
ObjectList = (Dictionary<string, IDictionary<int, IMyObject>>)HttpContext.Current.Cache["ObjectCache"];
}
else
{
ObjectList = CreateObjects();
HttpContext.Current.Cache.Insert(
"ObjectCache",
ObjectList,
null,
DateTime.Now.AddMinutes(2),
System.Web.Caching.Cache.NoSlidingExpiration);
}
foreach(var parent in ObjectList)
{
foreach(var child in ObjectList[parent.Key])
{
if(false == child.Value.State)
{
//TODO... Note here
child.Value.State = true;
}
}
}
}
}
}
Have a look at something like XML Serializable Generic Dictionary

Categories

Resources