Dynamic Dictionary usage in C# - c#

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.

Related

Creating a list composed of object property references

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));
}

Cannot set value to Dictionary Key

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.

C# add properties at runtime

I've read few posts, and I'm still having troubles with adding properties to a class in runtime. It should be simple, because I have a class like this:
public class MyClass
{
String Template;
String Term;
}
During runtime, I have to add few attributes, like Phone, Email (it depends...).
Could someone please explain me how to add these properties during class initialization?
Srecko
I don't think adding a property is the right thing to do here.
The attributes like "Email" or "Phone" are just some additional pairs of a key and a value. You could use a Dictionary, but that would prevent you from using a key more than once (more than one email address for a contact for example). So you could just as well use a List<KeyValuePair<string, string>>. Like that:
public class MyClass
{
String Template;
String Term;
public List<KeyValuePair<string, string>> Attributes { get; private set; }
public MyClass() {
Attributes = new List<KeyValuePair<string, string>();
}
public void AddAttribute(string key, string value) {
Attributes.Add(new KeyValuePair<string, string>(key, value));
}
}
// to be used like this:
MyClass instance = new MyClass();
instance.AddAttribute("Email", "test#example.com");
instance.AddAttribute("Phone", "555-1234");
If you have c# 4.0 you can use the Expando object.
for earlier versions of c#, the generally accepted way of doing this is to create a "property bag" i.e. a collection (or dictionary) of key value pairs
dynamic foo = new ExpandoObject();
foo.Bar = "test";
you could add an dictionary with for your Key/Value-Pairs.
Then if you add your attributes you just add Key = Attributename, Value = YourValue to the dictionary.
Reading is as easy - just get the Value to the Key = Attributename from your dictionary.

Another c# reflection

I have a csv file where each row is a different type of record. I am parsing the csv and want to store the rows (varied types of records) in various types of custom classes.
At each row i need to instantiate a different class based on the record type.
So taken from other reflection examples, I have the code below;
Type type = Type.GetType("myNamespace." + className);
object recordclass = Activator.CreateInstance(type);
so i have an object named recordclass of the correct type, but how do I use it?
all I really want to do is access the properties of the class and populate the row data, and then later add to a container class.
I guess im missing something about the runtime nature of reflection. Please help me connect the dots!
Hope that all makes sense!
TIA,
Gary
With the example you give you could cast your object to the actual type you need:
Type type = Type.GetType("myNamespace." + className);
object recordclass = Activator.CreateInstance(type);
var record = recordClass as ConcreteRecordType;
if(record != null)
record.Name = csv["Name"];
Alternatively look into using a Factory to return populated record objects:
public class RecordFactory
{
RecordBase ParseCsvRow(string[] columns)
{
const int typeDescriminatorColumn = 0;
switch (columns[typeDescriminatorColumn])
{
case "RecordTypeA":
return new RecordTypeA(columns[1], columns[2], ...);
case "RecordTypeB":
return new RecordTypeB(columns[1], columns[2], ...);
default:
throw new InvalidOperationException("Unexpected descriminator: " + columns[typeDescriminatorColumn]);
}
}
}
If you want to store values into your recordclass's property via reflection use this
var property = type.GetProperty(propertyName);
property.SetValue(recordclass,value,null);
If you read the docs, you will see, Type.GetType requires a full qualified type name.
If I understand the problem correctly you have a file which contains text values for records. Each record is stored in a single line, and the start of each line is an identifier to say which kind of record is to be built.
It is possible to use reflection for this but not really neccessary. The problem with using reflection is that you need to know all the properties for the different record types in order to access them by name. At this point, you may as well be working with typed objects but if you are using the a single routine to create all the records (using CreateInstance()) all you have is an untyped object.
Another solution is to have a set of routines each of which take in, say an IEnumerable (the input line split by the comma, excluding the record id) and return an object (or a record, if you have a base record class) and use a factory to select which routine to use for each row.
You register the routines with the factory by some ID (the first field in the record as you are doing is good, it can be the record class name but doesn't have to be) and the iterate through the CSV lines, using the first piece to select the method from the factory and building the record.
Hopefully the example will explain a bit better :? Sorry about the volume of code
The builders in the example just return empty records but populating them from the row pieces should be easy. Another version is to just pass in the row, or a set of rows if a record can cover a number of rows (a but more complicated if the records take in different numbers of rows)
hth,
Alan.
public string[] Input = new[]{
"R1, F1, F2, F3",
"R2, F2, F4",
"R3, F2",
"R3, F2",
"R4, F1, F2, F3, F4"
};
public class RecordOne {
}
public class RecordTwo {
}
public class RecordThree {
}
public class RecordFour {
}
public class BuilderFactory {
public BuilderFactory() {
Builders = new Dictionary<string, Func<IEnumerable<string>, object>>();
}
private Dictionary<string, Func<IEnumerable<string>, object>> Builders { get; set; }
public void RegisterBuilder(string name, Func<IEnumerable<string>, object> builder) {
Builders.Add(name, builder);
}
public Func<IEnumerable<string>, object> GetBuilder(string name) {
return Builders[name];
}
}
[TestMethod]
public void LoadRecords() {
var factory = new BuilderFactory();
factory.RegisterBuilder("R1", BuildRecordOne);
factory.RegisterBuilder("R2", BuildRecordTwo);
factory.RegisterBuilder("R3", BuildRecordThree);
factory.RegisterBuilder("R4", BuildRecordFour);
var output = Input.Select(line => {
var pieces = line.Split(',').Select(val => val.Trim());
var builder = factory.GetBuilder(pieces.First());
return builder(pieces.Skip(1));
});
Assert.IsTrue(new[] {typeof(RecordOne),
typeof(RecordTwo),
typeof(RecordThree),
typeof(RecordThree),
typeof(RecordFour)}.SequenceEqual(output.Select(rec => rec.GetType())));
}
private static RecordOne BuildRecordOne(IEnumerable<string> pieces) {
return new RecordOne();
}
private static RecordTwo BuildRecordTwo(IEnumerable<string> pieces) {
return new RecordTwo();
}
private static RecordThree BuildRecordThree(IEnumerable<string> pieces) {
return new RecordThree();
}
private static RecordFour BuildRecordFour(IEnumerable<string> pieces) {
return new RecordFour();
}

C# Accessing object properties indexer style

Is there any tool,library that would allow me to access my objects properties indexer style ?
public class User
{
public string Name {get;set;}
}
User user = new User();
user.Name = "John";
string name = user["Name"];
Maybe the dynamic key word could help me here ?
You can use reflection to get property value by its name
PropertyInfo info = user.GetType().GetProperty("Name");
string name = (string)info.GetValue(user, null);
And if you want to use index for this you can try something like that
public object this[string key]
{
get
{
PropertyInfo info = this.GetType().GetProperty(key);
if(info == null)
return null
return info.GetValue(this, null);
}
set
{
PropertyInfo info = this.GetType().GetProperty(key);
if(info != null)
info.SetValue(this,value,null);
}
}
Check out this about indexers. The dictionary stores all the values and keys instead of using properties. This way you can add new properties at runtime without losing performance
public class User
{
Dictionary<string, string> Values = new Dictionary<string, string>();
public string this[string key]
{
get
{
return Values[key];
}
set
{
Values[key] = value;
}
}
}
You could certainly inherit DynamicObject and do it that way.
http://msdn.microsoft.com/en-us/library/system.dynamic.dynamicobject.trygetindex.aspx
Using the simple indexer method mentioned here by others would limit you to either returning only 'object' (and having to cast) or having only string types in your class.
Edit: As mentioned elsewhere, even with dynamic, you still need to use either reflection or some form of lookup to retrieve the value inside the TryGetIndex function.
You cannot do this until the class implements a Indexer.
If you just want to access a property based on a string value you could use reflection to do something similar:
string name = typeof(User).GetProperty("Name").GetValue(user,null).ToString();
You could build it yourself with reflection and indexer.
But for what do you need such a solution?

Categories