I fall in a weird situation, so essentially I need to create a Dictionary with a string as Key and a custom object as Value. The Dictionary have this implementation:
public static Dictionary<string, ForecastType> FullTime
{
get
{
return new Dictionary<string, ForecastType>()
{
{ "1", new ForecastType { Type = SignType.PartialFinal, Sign = Signs.HomeHomePF } },
...
}
}
}
as you can see the key is 1 and the value is a custom class called ForecastType:
public class ForecastType : ViewModel
{
private double _value;
public double Value
{
get { return _value; }
set
{
_value = value;
OnPropertyChanged();
}
}
public Signs Sign { get; set; }
public SignType Type { get; set; }
}
the property Sign and Type don't need an explaination, it's only an implementation of an Enum.
The property Value instead, cause me a lot of headache. In particular I can't set the value to this property, each value that I assign I get 0.
I also implemented the ViewModel, I though to an issue related on PropertyChanged, but even this hasn't fixed the situation.
I valorize the Value property in this way:
FullTime["1"].Value = 5;
Note that the OnPropertyChanged() is called correctly, and the value inside it is 5, but when I set a breakpoint, later the FullTime["1"].. line I get as .Value "0".
What am I doing wrong?
Thanks for any help. Best regards.
The problem is in the FullTime property itself. It always returns a new dictionary:
get
{
return new Dictionary<string, ForecastType>() {...};
}
Every time you call it, whether to set or get anything in that dictionary, you're always getting a brand new dictionary. No dictionary is ever persisted in memory.
Save an instance in the class and return that instance instead. Perhaps something like this:
private static Dictionary<string, ForecastType> _myDict;
public static Dictionary<string, ForecastType> FullTime
{
get
{
if (_myDict == null)
_myDict = new Dictionary<string, ForecastType>() {...};
return _myDict;
}
}
This way it will be initialized the first time you call that property, and any subsequent calls to that property will yield the previously initialized dictionary.
Instead of having the getter for the FullTime property return a new dictionary, you can, as of C# 6, provide a default value for the property like so:
public static Dictionary<string, ForecastType> FullTime {get;} = new Dictionary<string, ForecastType> () { /* initial dictionary values go here */ };
Your FullTime has only a getter, which whenever is called returns a new dictionary with the default value of ForecastType.Value. One possible solution it would be the following:
public static Dictionary<string, ForecastType> FullTime { get; } =
new Dictionary<string, ForecastType>
{
{ "1", new ForecastType
{
Type = SignType.PartialFinal,
Sign = Signs.HomeHomePF
}
// ...
};
The difference is that now you have create a property with only a getter but with a default value, which cannot be changed. This value is a reference to a dictionary Dictionary<string, ForecastType>. Whenever you read the value of this property you would get the same reference but now you could mutate the state of the object that this reference points to, by adding new items to the dictionary, changing values etc.
Related
I am trying to do the following thing:
- From within a 1st method, I am going through a bunch of objects (of same type) and extracting pointers to specific properties into a list
- This list will then be fed to a another method elsewhere in my program at some point in time and has to modify all the properties (as per provided list) of the original objects
In other words, say we have the following class:
public class Something
{
public SomeFlag = False;
public Something()
{
}
}
Somewhere in the system, we have composed a related list of objects into List.
Now, we want to scan through this list and extract into "List< bool> flags" all the flags (by reference?):
List<bool> flags = new List<bool>();
foreach (var stuff in List<Something>)
{
flags.Add(stuff.SomeFlag);
}
Finally, somewhere else, I want to update these flags, but the update should affect the original object:
public static void SetStates(List<bool> myList)
{
// The flag should get set to true by reference in the original object
myList.SomeFlag = True;
}
Using actions could be one way to achive this:
public class Something
{
public bool SomeFlag { get; set; }
}
internal class Program
{
private static void Main()
{
var somethings = new[] {new Something(), new Something()};
var flags = new List<Action<bool>>();
// create your list of 'pointers'
foreach (var something in somethings)
{
flags.Add(x => something.SomeFlag = x);
}
// set them all to true
foreach (var action in flags)
{
action(true);
}
// check the results
foreach (var something in somethings)
{
Console.WriteLine(something.SomeFlag);
}
Console.WriteLine("press any key to exit...");
Console.ReadLine();
}
}
In C#, you cannot save a reference to a property value (like a pointer to the memory location where the value is stored). You only can save a reference to an object which contains this property value.
In your var list = new List<Something>(), you can store those references to the objects.
Note that it's impossible for value types though. If Something is a struct, not a class, then the list will contain copies of the objects, not the references to the objects. So the rest of my answer assumes we're talking about class Something.
You can define a property changing behavior and apply it using the list of the objects.
If you already know at compile time which properties and which values do you need, you can create a lambda and pass it around.
// Define the behavior and get the object list
Action<Something> setter = o => o.Someflag = true;
var objectList = new List<Something>();
// Call your processing method later on
SetProperties(objectList, setter);
void SetProperties<T>(List<T> objects, Action<T> setter)
{
objects.ForEach(setter);
}
If you don't know at compile which properties and which values you will need, then things get much more complicated. You will need to use Reflection to obtain the property descriptors and to set the values.
Here is a simplified example:
// Define the behavior and get the object list
var objectList = new List<Something>();
string propertyName = "SomeFlag";
PropertyInfo pi = typeof(Something).GetProperty(propertyName);
MethodInfo setter = pi.GetSetMethod();
object value = true;
// Call your processing method later on
SetProperties(objectList, setter, value);
void SetProperties<T>(List<T> objects, MethodInfo setter, object value)
{
var arguments = new object[] { value } ;
objects.ForEach(o => setter.Invoke(o, arguments));
}
I've created a data class that I plan to use to send data to be persisted in the database and to return data from the database in a strongly typed way. In addition to its properties, the class contains a Dictionary that I populate in the constructor with the name of and reference to each property. This makes the properties enumerable and enables me to iterate through them using 'foreach'.
This works great when setting property values and sending the object to be persisted in the database. I can iterate through the Dictionary keys, get the value of each property, and add a SqlParameter for each property using the key as the parameter name and the property value as the parameter value.
However, going the other way doesn't work. I can iterate through the Dictionary keys and get the value of each column in each row of the SqlDataReader, but when I try to assign these values to my data object using the Dictionary's reference to the corresponding object property, a curious thing occurs. The assignments succeed, BUT the data object properties all retain their initial, default values. I can view the data object properties and see these initial, default values. I can also view the Dictionary entry values and see the updated values that were read and assigned from the SqlDataReader.
This makes no sense. The Dictionary is supposed to provide access to each property (the 'object' generic type) via its key (the 'string' generic type), but its acting like its maintaining a separate copy of each Dictionary 'KeyValuePair'.
What gives?
I'm doing all this in C# in the context of an ASP.NET Core 2.1.1 project running on macOS 10.13.6 High Sierra.
I've searched StackOverflow extensively, and I see lots of recommendations for using reflection to do this type of thing. I'll refactor my code to use reflection if necessary, but I'd really like to understand where and how my mental model for what's happening is off.
An explanation of what's happening and why would be MOST appreciated.
Example Data Class with Property Dictionary
using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Runtime.Serialization;
using Newtonsoft.Json;
namespace MyOrg.MyProj.Data
{
[DataContract]
public class DataObj
{
#region Attributes
[Required]
[DataMember(Name = "dataObjectId")]
public Int64 DataObjectId { get; set; }
[Required]
[DataMember(Name = "guid")]
public Guid Guid { get; set; }
public virtual Dictionary<string, object> DataMembers { get; set; } //NOTE: Implements the IEnumerable interface in order to support 'foreach' operations, etc on 'DataObj' class attributes
#endregion Attributes
#region Constructors
public DataObj(Int64 dataObjectId, Guid guid)
{
try
{
DataObjectId = dataObjectId;
Guid = guid;
DataMembers = new Dictionary<string, object>
{
{ "DataObjectId", DataObjectId },
{ "Guid", Guid }
};
}
catch (Exception e)
{
Console.WriteLine($"RUNTIME EXCEPTION while INSTANTIATEing DataObj, " + e.Message + ", " + e.StackTrace);
}
}
#endregion Constructors
#region Methods
/// <summary>
/// Implements the IEnumerable interface in order to support 'foreach' operations, etc on 'DataObj' class attributes
/// </summary>
/// <returns>Enumerator</returns>
public Dictionary<string, object>.Enumerator Enumerator()
{
return DataMembers.GetEnumerator(); //NOTE: Return the Dictionary object's IEnumerator rather than implementing IEnumerable for the 'DataObj' class itself
}
#endregion Methods
Example Data Access Class (excerpt)
reader = command.ExecuteReader();
dataObjList = new List<DataObj>();
if (reader.HasRows)
{
while (reader.Read())
{
tempDataObj = new DataObj(-1, new Guid("00000000-0000-0000-0000-000000000000"));
keys = new List<String>(tempDataObj.DataMembers.Keys); //NOTE: Can't modify a Dictionary while iterating through it. See the 'Why This Error?' section of https://stackoverflow.com/questions/604831/collection-was-modified-enumeration-operation-may-not-execute
foreach (String key in keys)
{
tempDataObj.DataMembers[key] = reader[key];
}
dataObjList.Add(tempDataObj);
For 'key' = 'DataObjectId', 'Guid', etc, I expect the value of tempDataObj.DataObjectId, tempDataObj.Guid, etc to be set to the value returned from the database in 'reader[key]'.
Instead, it retains its initial, default value as set in the constructor, i.e. '-1'. This is true for both value and reference data types.
However, when I inspect tempDataObj.DataMembers["DataObjectId"], it has been set to the value returned from the database in 'reader[key]'.
Inspecting the Object Property and Dictionary Values
tempDataObj.DataMembers["DataObjectId"] should be referencing the tempDataObj.DataObjectId property, etc, but the Dictionary appears to be maintaining its own value rather than providing an object reference to the 'DataObjectId' property.
What's going on here? Thank you!
You're storing the data twice - once in a Dictionary, and a second time in a field. There's no need to store it twice. Just do this:
[DataContract]
public class DataObj
{
[Required]
[DataMember(Name = "dataObjectId")]
public Int64 DataObjectId
{
get => (long)DataMembers[nameof(DataObjectId)];
set => DataMembers[nameof(DataObjectId)] = value;
}
[Required]
[DataMember(Name = "guid")]
public Guid Guid
{
get => (Guid)DataMembers[nameof(Guid)];
set => DataMembers[nameof(Guid)] = value;
}
public Dictionary<string, object> DataMembers { get; } = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
public DataObj(Int64 dataObjectId, Guid guid)
{
DataObjectId = dataObjectId;
Guid = guid;
}
public Dictionary<string, object>.Enumerator Enumerator()
{
return DataMembers.GetEnumerator();
}
}
FYI, you can also look at using an ExpandoObject, which lets you access something in a way that looks like a class, but is really just a Dictionary. https://learn.microsoft.com/en-us/dotnet/api/system.dynamic.expandoobject?view=netframework-4.7.2
I have never used an ExpandoObject and I think the whole idea is as perverse as VBA's default of option explicit being off and On Error Resume Next. On the other hand, I don't deal with databases much.
I see two (main) routes to do what you want. In both cases you should implement a custom indexer.
In the indexer explicitly check the name given to it and get or set the field or property accordingly.
Use reflection, i.e. GetField() or GetProperty(), to get the field or property and GetValue() or SetValue() to get or set the values.
Below is a demonstration where ExposeByExplicitIndexer0 and its descendants use way 1 and ExposeByIndexerUsingReflection0 and its descendants use way 2.
public class ExposeByExplicitIndexer0
{
public int Int0 = 1;
public string String0 = "A";
public virtual object this[string name]
{
get
{
switch (name)
{
case "Int0":
return this.Int0;
case "String0":
return this.String0;
default:
throw new IndexOutOfRangeException();
}
}
set
{
switch (name)
{
case "Int0":
this.Int0 = (int)value;
break;
case "String0":
this.String0 = (string)value;
break;
default:
throw new IndexOutOfRangeException();
}
}
}
}
public class ExposeByExplicitIndexer1 : ExposeByExplicitIndexer0
{
protected Guid _Guid1 = Guid.Empty;
public Guid Guid1
{
get
{
return this._Guid1;
}
set
{
this._Guid1 = value;
}
}
public override object this[string name]
{
get
{
switch (name)
{
case "Guid1":
return this.Guid1;
default:
return base[name];
}
}
set
{
switch (name)
{
case "Guid1":
this.Guid1 = (Guid)value;
break;
default:
base[name] = value;
break;
}
}
}
}
public class ExposeByIndexerUsingReflection0
{
public object this[string name]
{
get
{
FieldInfo fieldInfo;
if ((fieldInfo = this.GetType().GetField(name)) != null)
{
return fieldInfo.GetValue(this);
}
PropertyInfo propertyInfo;
if ((propertyInfo = this.GetType().GetProperty(name)) != null)
{
return propertyInfo.GetValue(this);
}
throw new IndexOutOfRangeException();
}
set
{
FieldInfo fieldInfo;
if ((fieldInfo = this.GetType().GetField(name)) != null)
{
fieldInfo.SetValue(this, value);
return;
}
PropertyInfo propertyInfo;
if ((propertyInfo = this.GetType().GetProperty(name)) != null)
{
propertyInfo.SetValue(this, value);
return;
}
throw new IndexOutOfRangeException();
}
}
}
public class ExposeByIndexerUsingReflection1 : ExposeByIndexerUsingReflection0
{
public int Int1 = 1;
public string String1 = "A";
}
public class ExposeByIndexerUsingReflection2 : ExposeByIndexerUsingReflection1
{
protected Guid _Guid2 = Guid.Empty;
public Guid Guid2
{
get
{
return this._Guid2;
}
set
{
this._Guid2 = value;
}
}
}
public class Program
{
static void Main(string[] args)
{
Guid newGuid = Guid.NewGuid();
Console.WriteLine("Expose by explicit indexer:");
ExposeByExplicitIndexer1 exposeByExplicitIndexer1 = new ExposeByExplicitIndexer1();
exposeByExplicitIndexer1["Int0"] = 10;
exposeByExplicitIndexer1["String0"] = "AAA";
exposeByExplicitIndexer1["Guid1"] = newGuid;
Console.WriteLine("output via indexer:");
Console.WriteLine(exposeByExplicitIndexer1["Int0"]);
Console.WriteLine(exposeByExplicitIndexer1["String0"]);
Console.WriteLine(exposeByExplicitIndexer1["Guid1"]);
Console.WriteLine("output via fields or properties:");
Console.WriteLine(exposeByExplicitIndexer1.Int0);
Console.WriteLine(exposeByExplicitIndexer1.String0);
Console.WriteLine(exposeByExplicitIndexer1.Guid1);
Console.WriteLine("Expose by indexer using reflection:");
ExposeByIndexerUsingReflection2 exposeByIndexerUsingReflection2 = new ExposeByIndexerUsingReflection2();
exposeByIndexerUsingReflection2["Int1"] = 10;
exposeByIndexerUsingReflection2["String1"] = "AAA";
exposeByIndexerUsingReflection2["Guid2"] = newGuid;
Console.WriteLine("output via indexer:");
Console.WriteLine(exposeByIndexerUsingReflection2["Int1"]);
Console.WriteLine(exposeByIndexerUsingReflection2["String1"]);
Console.WriteLine(exposeByIndexerUsingReflection2["Guid2"]);
Console.WriteLine("output via fields or properties:");
Console.WriteLine(exposeByIndexerUsingReflection2.Int1);
Console.WriteLine(exposeByIndexerUsingReflection2.String1);
Console.WriteLine(exposeByIndexerUsingReflection2.Guid2);
Console.Read();
}
}
In way 1 every descendant that adds new fields or properties has to extend the indexer. That's more work in general but also offers an easy way of flexibility i.e. for adding some casts or expose some field or property via an alias, etc.
Way 2 needs less effort in the descendants. But being as flexible as in way 1 may become more difficult in turn. Maybe some mixed solution is also possible overriding the indexer in some descendant to inject special logic.
I want to create a class with fixed properties and the capability to extend them as dynamic or ExpandoObject can.
e.g:
public class DynamicInstance : DynamicObject
{
public string FixedTestProperty { get; set; }
}
Usage:
DynamicInstance myCustomObj = new DynamicInstance();
myCustomObj.FixedTestProperty = "FixedTestValue";
myCustomObj.DynamicCreatedTestProperty = "Custom dynamic property value";
Finally if I serialize that class with json.net or something else output something like that:
{
FixedTestProperty: 'FixedTestValue',
DynamicCreatedTestProperty: 'Custom dynamic property value'
}
You need to inherit DynamicObject and override the TryGetMember and TrySetMember methods. Here is a class which has one property named One. However, you can add more to it dynamically.
public class ExpandOrNot : DynamicObject
{
public string One { get; set; }
// The inner dictionary.
Dictionary<string, object> dictionary
= new Dictionary<string, object>();
// This property returns the number of elements
// in the inner dictionary.
public int Count
{
get
{
return dictionary.Count;
}
}
// If you try to get a value of a property
// not defined in the class, this method is called.
public override bool TryGetMember(
GetMemberBinder binder, out object result)
{
// Converting the property name to lowercase
// so that property names become case-insensitive.
string name = binder.Name.ToLower();
// If the property name is found in a dictionary,
// set the result parameter to the property value and return true.
// Otherwise, return false.
return dictionary.TryGetValue(name, out result);
}
// If you try to set a value of a property that is
// not defined in the class, this method is called.
public override bool TrySetMember(
SetMemberBinder binder, object value)
{
// Converting the property name to lowercase
// so that property names become case-insensitive.
dictionary[binder.Name.ToLower()] = value;
// You can always add a value to a dictionary,
// so this method always returns true.
return true;
}
}
Usage
dynamic exp = new ExpandOrNot { One = "1" };
exp.Two = "2";
More info here.
<== Fiddle Me ==>
This is possible using TrySetMember on DynamicObject.
The example at the bottom of this shows how to do it: https://msdn.microsoft.com/en-us/library/system.dynamic.dynamicobject.trysetmember(v=vs.110).aspx
I have a simple class that is intended for options of an winforms application. There should be a method that reset options to their default values. I know I can add a separate method to take care of this, but the code will be huge (If I add more options to the class) :
public SensorOptions()
{
ShowLabelMax = ShowLabelMin = ShowLabelAvr = ShowReceivedTextBox = true;
ChartMaxValue = 140;
ChartMinValue = -40;
ShowChartMinValue = ShowChartMaxValue = ShowChartAvrValue = ShowChartAvrLine = true;
LogFolder = Environment.SpecialFolder.MyDocuments.ToString();
LoggingEnabled = true;
}
public void ResetOptions()
{
this = new SensorOptions(); //can not do. 'this' is read-only
}
I mean I can copy/paste the code from constructor into ResetOptions() method. But is there any smarter ways to achieve this?
You cannot assign this because you may have references to this instance of your class in your program. If you could re-construct the object by re-assigning this, it would mean that all references to the old instance of the class become invalid.
No matter how many options you have in your class, you initialize each of them one or the other way (because you mention default value in your question - so you need to assign that default value somewhere at least once, probably in the constructor). Therefore, the solution to your problem is simple - move all initializers to the separate method and call it in the constructor, and then also call it every time you need to reset your options to their default values.
If any of your options are not assigned a default value explicitly, and use system default and you don't want to write option=default(optionType) for each option, you can use reflection to enumerate all fields/properties in that class and assign default values to them, like this:
public static object GetDefault(Type type)
{
if(type.IsValueType) return Activator.CreateInstance(type);
return null;
}
foreach(var field in this.GetType().GetFields())
field.SetValue(this, GetDefault(field.FieldType));
foreach(var prop in this.GetType().GetProperties())
prop.SetValue(this, GetDefault(prop.PropertyType));
Move all of the code from the constructor into the ResetOptions method, then in your constructor call the ResetOptions method. Your initialisiation code is only in one place then.
You have very simple architecture for your situation. In my opinion it would be better to apply a trick for this:
you have class for holding all your options (pseudo code):
class AllOptionsBackstage
{
public bool ShowLabelMax { get; set; }
public bool ShowLabelMin { get; set; }
public bool ShowLabelAvr { get; set; }
public AllOptionsBackstage()
{
// apply default values here
}
}
.....
class MyOptions
{
private AllOptionsBackstage _options;
public MyOptions()
{
Reset();
}
public bool ShowLabelMax
{
get{ return _options.ShowLabelMax; }
set{ _options.ShowLabelMax = value; }
}
public bool ShowLabelMin
{
get{return _options.ShowLabelMin;}
set{_options.ShowLabelMin=value; }
}
public bool ShowLabelAvr
{
get{ return _options.ShowLabelAvr;}
set{ _options.ShowLabelAvr = value; }
}
public void Reset()
{
_options = new AllOptionsBackstage(); // will reset all your options to default
}
}
I am using a Dynamic dictionary in C#. The problem I am facing is the behavior of TryGetMember which I am overriding in the dynamic dictionary class.
Here's the code of dynamic dictionary.
class DynamicDictionary<TValue> : DynamicObject
{
private IDictionary<string, TValue> m_dictionary;
public DynamicDictionary(IDictionary<string, TValue> a_dictionary)
{
m_dictionary = a_dictionary;
}
public override bool TryGetMember(GetMemberBinder a_binder, out object a_result)
{
bool returnValue = false;
var key = a_binder.Name;
if (m_dictionary.ContainsKey(key))
{
a_result = m_dictionary[key];
returnValue = true;
}
else
a_result = null;
return returnValue;
}
}
Here, TryGetMember will be called at runtime whenever we refer some key from outside, but it's strange that binder's Name member which always gives the key what we refer from outside, it always resolves the key name written as characters of alphabets.
e.g. if the object of DynamicDictionary made as:
Dictionary<string,List<String>> dictionaryOfStringVsListOfStrings;
//here listOfStrings some strings list already populated with strings
dictionaryOfStringVsListOfStrings.Add("Test", listOfStrings);
dynamic dynamicDictionary_01 = new
DynamicDictionary<List<String>(dictionaryOfStringVsListOfStrings);
string somekey = "Test";
//will be resolve at runtime
List<String> listOfStringsAsValue = dynamicDictionary_01.somekey
Now what happens here is "somekey" will become the value of a_binder (i.e a_binder.Name="somekey"). It should be resolved as a_binder.Name = "Test" and then from the dynamic dictionary it will locate listOfStrings against this key (i.e. actually "Test" but it resolves not the value but actual variable name as key).
Is there a way around this?
The point of dynamic typing is to make the member names themselves get resolved from the source code member access.
Dynamic typing is working exactly as it's meant to here - it's not designed to retrieve the value of the variable and use that as the member name - it's designed to use the member name you used in your source code (i.e. "somekey").
It sounds like you really don't need dynamic typing at all here - just use Dictionary<string,List<String>> as normal:
List<String> listOfStringsAsValue = dictionary[somekey];
EDIT: It sounds like you actually want to encapsulate a dictionary like this:
public class Foo // TODO: Come up with an appropriate name :)
{
private readonly Dictionary<string, List<string>> dictionary =
new Dictionary<string, List<string>>();
public List<string> this[string key]
{
get
{
List<string> list;
if (!dictionary.TryGetValue(key, out list))
{
list = new List<string>();
dictionary[key] = list;
}
return list;
}
}
}
Then you can do:
foo["first"].Add("value 1");
foo["second"].Add("value 2")
foo["first"].Add("value 1.1");
If you want to be able to attempt to fetch a list without creating a new one if it doesn't exist, you could add a method to do that.
It really doesn't sound like you need DynamicObject here.