I've been researching a bit about reflections in C # and would like to know if I use a dictionary with keys-values can create an object with the variable with the name of each key in the dictionary and their values, the key value of that dictionary.
I have a method that does the opposite, that extracts an object from a dictionary, this dictionary contains the keys and the class properties and their values, the value of the properties.
I wonder how to do this if possible.
Below is my method, which extracts a dictionary of an object:
protected Dictionary<String, String> getObjectProperty(object objeto)
{
Dictionary<String, String> dictionary = new Dictionary<String, String>();
Type type = objeto.GetType();
FieldInfo[] field = type.GetFields();
PropertyInfo[] myPropertyInfo = type.GetProperties();
String value = null;
foreach (var propertyInfo in myPropertyInfo)
{
if (propertyInfo.GetIndexParameters().Length == 0)
{
value = (string)propertyInfo.GetValue(objeto, null);
value = value == null ? null : value;
dictionary.Add(propertyInfo.Name.ToString(), value);
}
}
return dictionary;
}
If you've already got a dictionary, I'd avoid reflection and just use DynamicObject
For example:
public class DynamicDictionary : DynamicObject
{
private readonly Dictionary<string, object> dictionary;
public DynamicDictionary(Dictionary<string, object> dictionary)
{
this.dictionary = dictionary;
}
public override bool TryGetMember(
GetMemberBinder binder, out object result)
{
return dictionary.TryGetValue(binder.Name, out result);
}
public override bool TrySetMember(
SetMemberBinder binder, object value)
{
dictionary[binder.Name] = value;
return true;
}
}
Which can be used as follows:
dynamic x = new DynamicDictionary(
new Dictionary<string, object> {{"Name", "Peter"}});
Console.WriteLine(x.Name);
I am not sure if this is what you're looking for, but judging by your question, I think you want to
instantiate types at run time from the types located in a dictionary, which will be obtained by providing a key.
If that is so, then you can create the following class which will hold key-value pairs of strings which will be your keys, and Types which will represent your values which will be instantiated.
class DictionaryActivator
{
Dictionary<string, Type> Dictionary = new Dictionary<string, Type>();
public DictionaryActivator()
{
Dictionary.Add("MyCar", typeof(Car));
Dictionary.Add("MyHouse", typeof(House));
Dictionary.Add("MyFruit", typeof(Fruit));
Dictionary.Add("MyComputer", typeof(Computer));
}
public T GetInstance<T>(string type, params object[] parameters)
{
if (parameters.Count() == 0)
{
return (T)Activator.CreateInstance(Dictionary[type]);
}
else
{
return (T)Activator.CreateInstance(Dictionary[type], parameters.ToArray());
}
}
}
You can also create four test classes to test this setup.
class House
{
public int Number = 25;
}
class Car
{
public double Price = 50000;
}
class Fruit
{
public string Name = "Apple";
}
class Computer
{
public string Cpu { get; set; }
public string Gpu { get; set; }
public Computer(string cpu, string gpu)
{
Cpu = cpu;
Gpu = gpu;
}
}
Once this is done, you can run the following lines of code to get all the types from the dictionary, instantiate them and cast them to appropriate types. As you might notice, the last Computer example is showing you how to add multiple parameters (in this case two) to the newly created instance and return it as an instance of type object.
In the end you can cast it to the Computer type so you can check that the constructor parameters actually went to the corresponding properties.
class Program
{
static void Main()
{
var source = new DictionaryActivator();
Console.WriteLine(source.GetInstance<Car>("MyCar").Price);
Console.WriteLine(source.GetInstance<House>("MyHouse").Number);
Console.WriteLine(source.GetInstance<Fruit>("MyFruit").Name);
var computer = source.GetInstance<object>("MyComputer", "Fast CPU", "Fast GPU");
Console.WriteLine((computer as Computer).Cpu);
Console.WriteLine((computer as Computer).Gpu);
Console.Read();
}
}
Since ExpandoObject is a dictionary, you can use this extension function:
public static object With(this IDictionary<string, object> obj, IDictionary<string,object> additionalProperties)
{
foreach (var name in additionalProperties.Keys)
obj[name] = additionalProperties[name];
return obj;
}
Usage:
var dynamicObj = new System.Dynamic.ExpandoObject().With(myDictionary);
Related
I have a class Example which contains a dictionary object Dict and as such I can access a dictionary value with key "X" using Example.Dict["X"].
However, I'm wondering if it's possible to carry out these accesses as follows: Example.X.
I would usually handle this using a basic compiler macro in C or C++ but seeing as C# doesn't have this feature I'm wondering if it is possible via reflection or otherwise.
You can do this with DynamicObject:
public class Example : DynamicObject
{
public Dictionary<string, string> Dict { get; } = new Dictionary<string, string>() { ["Foo"] = "bar" };
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
result = null;
if (!Dict.TryGetValue(binder.Name, out var value))
return false;
result = value;
return true;
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
if (Dict.ContainsKey(binder.Name))
{
Dict[binder.Name] = value?.ToString();
return true;
}
return Dict.TryAdd(binder.Name, value?.ToString());
}
}
An an example above I have initialised the Dictionary<string,string> with a default element. This allows me to write code such as:
dynamic ex = new Example();
Console.WriteLine(ex.Foo); // Outputs "bar"
ex.SomethingElse = "SomeValue"; // sets an element in the dictionary
Whether this is a good idea is an exercise for the reader.
I use a template engine that renders templates from c# objects (nested). I would like to reflect and figure out which properties / objects are used in each template string.
An ideal way would be to build a "dummy" object representing the right shape and render this in the template. I would then inspect this object afterwards to find out which properties were accessed. This would allow me to keep this logic independant of the template library.
Any idea how i might implement this? The expando object is built dynamically like this:
var dynamicObject = new ExpandoObject() as IDictionary<string, Object>;
foreach (var property in properties) {
dynamicObject.Add(property.Key,property.Value);
}
Had some ideas along these lines:
public class DummyObject {
public DummyObject() {
Accessed = new Dictionary<string, bool>();
}
public Dictionary<string, bool> Accessed;
object MyProp {
get {
Accessed["MyProp"] = true;
return "";
}
}
}
But this custom property obviously doesn't work with the dictionary / expando object. Any ideas of a route forward here?
You can override the TryGetMember method on DynamicObject:
public sealed class LoggedPropertyAccess : DynamicObject {
public readonly HashSet<string> accessedPropertyNames = new HashSet<string>();
public override bool TryGetMember(GetMemberBinder binder, out object result) {
accessedPropertyNames.Add(binder.Name);
result = "";
return true;
}
}
and then the following will output the accessed property names
dynamic testObject = new LoggedPropertyAccess();
string firstname = testObject.FirstName;
string lastname = testObject.LastName;
foreach (var propertyName in testObject.accessedPropertyNames) {
Console.WriteLine(propertyName);
}
Console.ReadKey();
N.B. There is still an issue here -- this works only as long as the template library expects only strings from the properties. The following code will fail, because every property will return a string:
DateTime dob = testObject.DOB;
In order to resolve this, and also allow for nested objects, have TryGetMember return a new instance of LoggedPropertyAccess. Then, you can override the TryConvert method as well; where you can return different values based on the conversion to different types (complete code):
using System;
using System.Collections.Generic;
using System.Dynamic;
namespace DynamicObjectGetterOverride {
public sealed class LoggedPropertyAccess : DynamicObject {
public readonly Dictionary<string, object> __Properties = new Dictionary<string, object>();
public readonly HashSet<string> __AccessedProperties = new HashSet<string>();
public override bool TryGetMember(GetMemberBinder binder, out object result) {
if (!__Properties.TryGetValue(binder.Name, out result)) {
var ret = new LoggedPropertyAccess();
__Properties[binder.Name] = ret;
result = ret;
}
__AccessedProperties.Add(binder.Name);
return true;
}
//this allows for setting values which aren't instances of LoggedPropertyAccess
public override bool TrySetMember(SetMemberBinder binder, object value) {
__Properties[binder.Name] = value;
return true;
}
private static Dictionary<Type, Func<object>> typeActions = new Dictionary<Type, Func<object>>() {
{typeof(string), () => "dummy string" },
{typeof(int), () => 42 },
{typeof(DateTime), () => DateTime.Today }
};
public override bool TryConvert(ConvertBinder binder, out object result) {
if (typeActions.TryGetValue(binder.Type, out var action)) {
result = action();
return true;
}
return base.TryConvert(binder, out result);
}
}
}
and use as follows:
using System;
using static System.Console;
namespace DynamicObjectGetterOverride {
class Program {
static void Main(string[] args) {
dynamic testObject = new LoggedPropertyAccess();
DateTime dob = testObject.DOB;
string firstname = testObject.FirstName;
string lastname = testObject.LastName;
dynamic address = testObject.Address;
address.House = "123";
address.Street = "AnyStreet";
address.City = "Anytown";
address.State = "ST";
address.Country = "USA";
WriteLine("----- Writes the returned values from reading the properties");
WriteLine(new { firstname, lastname, dob });
WriteLine();
WriteLine("----- Writes the actual values of each property");
foreach (var kvp in testObject.__Properties) {
WriteLine($"{kvp.Key} = {kvp.Value}");
}
WriteLine();
WriteLine("----- Writes the actual values of a nested object");
foreach (var kvp in testObject.Address.__Properties) {
WriteLine($"{kvp.Key} = {kvp.Value}");
}
WriteLine();
WriteLine("----- Writes the names of the accessed properties");
foreach (var propertyName in testObject.__AccessedProperties) {
WriteLine(propertyName);
}
ReadKey();
}
}
}
I have following parent class:
public class BaseType
{
public abstract Dictionary<string, object> dict { get; set; }
}
Child class:
public override Dictionary<string, object> dict
{
get
{
return fn();
}
set
{
//set dictionary[key]=value }
}
fn is implemented in child class as:
public static Dictionary<string, object> fn()
{
Dictionary<string, object> dictionary = new Dictionary<string, object>();
dictionary.Add("key1", "0");
dictionary.Add("key2", "something");
return dictionary;
}
I need to access this dictionary as follows:
BaseType test=new Child();
test.dict["key1"]=1;//set property
object strGet= test.dict["key2];//get property
How can I achieve the above get and set?
Your parent class is already invalid. You cannot have a property that takes arguments.
You can only expose the dictionary as a property itself. Note that you also need to make the class abstract as well:
public abstract class BaseType
{
public abstract Dictionary<string, object> Dict { get; set; }
}
Then, in subtypes of that class, you can set up the getter and setter so it returns a custom dictionary:
public class MyType : BaseType
{
public override Dictionary<string, object> Dict
{
get
{
return GetSomeDictionary();
}
set
{
DoSomethingWith(value);
}
}
}
Note, that this does not allow you to overwrite the behavior when you do someObj.Dict["key"] = "foo". The item accessor is built into the dictionary type, and you cannot overwrite that from within your class.
What you could do is expose a IDictionary<string, object> instead and provide your own type that wraps a normal dictionary but exposes your desired behavior instead.
If the whole purpose of your code is just to provide some default value for the dictionary, then you can solve this a lot easier:
public class MyType : BaseType
{
private Dictionary<string, object> _dict = null;
public override Dictionary<string, object> Dict
{
get
{
if (_dict == null)
{
_dict = InitializeDictionary();
}
return _dict;
}
set
{
_dict = value;
}
}
}
Where InitializeDictionary() returns a new dictionary with the default values.
I got it!! This way we can dynamically set the value of any key in dictionary.
public object objValue;
public string strKey;
public override Dictionary<string, object> dictionary
{
get
{
return fn();
}
set
{
setTest(strKey,objValue);
}
}
public void setTest(string strKey, object objValue)
{
dictionary[strKey] = objValue;
}
I have three classes: SomeThing, SomeOtherThing, and YetAntherThing. All three have an identical member called Properties. In each class, it is a key/value pair such that I can reference obj1.Name, obj1.Value, obj2.Name, obj2.Value, obj3.Name, and obj3.Value. I'd like to pass these three objects into a single method that could iterate through their respective "Properties" collections without having to know at compile time which it was operating on. I envision something like:
SomeThing obj1;
SomeOtherThing obj2;
YetAntherThing obj3;
DoProperties( obj1, obj1.GetType() );
DoProperties( obj2, obj2.GetType() );
DoProperties( obj3, obj3.GetType() );
...
private void DoProperties( object obj, Type objectType )
{
// this is where I get lost. I want to "cast" 'obj' to the type
// held in 'objectType' so that I can do something like:
//
// foreach ( var prop in obj.Properties )
// {
// string name = prop.Name;
// string value = prop.Value;
// }
}
Note: The classes SomeThing, SomeOtherThing, and YetAntherThing are defined externally, I have no control over them or access to their source code, and they are all sealed.
You've got two options; either get each class to implement an interface that exposes the collection, eg:
interface IHasProperties
{
PropertyCollection Properties {get;}
}
Then declare your method, referencing that interface:
private void DoProperties(IHasProperties obj)
{
foreach (var prop in obj.Properties)
{
string name = prop.Name;
string value = prop.Value;
}
}
Or use reflection to look-up the Properties collection at run-time, e.g.:
private void DoProperties(object obj)
{
Type objectType = obj.GetType();
var propertyInfo = objectType.GetProperty("Properties", typeof(PropertyCollection));
PropertyCollection properties = (PropertyCollection)propertyInfo.GetValue(obj, null);
foreach (var prop in properties)
{
// string name = prop.Name;
// string value = prop.Value;
}
}
The interface mentioned by FacticiusVir is the way to go, if you have control over the source of each object. Absent that, there is a third option in .NET 4. dynamic.
Given
class A
{
public Dictionary<string, string> Properties { get; set; }
}
class B
{
public Dictionary<string, string> Properties { get; set; }
}
class C
{
public Dictionary<string, string> Properties { get; set; }
}
You can accept the parameter as type dynamic and your code will compile (and bomb at runtime if it is not valid).
static void DoSomething(dynamic obj)
{
foreach (KeyValuePair<string, string> pair in obj.Properties)
{
string name = pair.Key;
string value = pair.Value;
// do something
}
}
The values in a file are read as string and can be double, string or int or maybe even lists. An example file:
DatabaseName=SomeBase
Classes=11;12;13
IntValue=3 //this is required!
DoubleValue=4.0
I was thinking something like this:
class ConfigValues
{
private static SomeObject _utiObject;
private static string _cfgFileName = "\\SomeSettings.cfg";
private static Dictionary<string, Type> _settingNamesAndTypes =
new Dictionary<string, Type>();
private static Dictionary<string, object> _settings = new Dictionary<string, object>();
private static string _directory = string.Empty;
const string _impossibleDefaultValue = "987ABC654DEF321GHI";
public static T GetConfigValue<T>(string cfgName)
{
object value;
if (_settings.TryGetValue(cfgName, out value))
return (T)value;
else
return default(T);
}
public static bool LoadConfig(Dictionary<string, Type> reqSettings,
Dictionary<string, Type> optSettings,
Dictionary<string, object> optDefaultValues, out string errorMsg)
{
errorMsg = string.Empty;
try
{
_utiObject = new SomeObject(new string[] { "-c", CfgFileNameAndPath });
}
catch (Exception e)
{
errorMsg = string.Format("Unable to read {0}. Exception: {1}",
CfgFileNameAndPath, e.Message);
return false;
}
foreach (KeyValuePair<string, Type> kVPair in reqSettings)
{
if (!ReadCheckAndStore(kVPair, null, out errorMsg))
return false;
_settingNamesAndTypes.Add(kVPair.Key, kVPair.Value);
}
foreach (KeyValuePair<string, Type> kVPair in optSettings)
{
if (!ReadCheckAndStore(kVPair, optDefaultValues[kVPair.Key], out errorMsg))
return false;
_settingNamesAndTypes.Add(kVPair.Key, kVPair.Value);
}
return true;
}
private static bool ReadCheckAndStore(KeyValuePair<string, Type> kVPair, object defaultValue, out string errorMsg)
{
errorMsg = string.Empty;
string usedDefaultValue, value = string.Empty;
/* required setting */
if (defaultValue == null)
usedDefaultValue = _impossibleDefaultValue;
else
usedDefaultValue = defaultValue.ToString();
//all string parameters below
_utiObject.GetConfigValue(kVPair.Key, usedDefaultValue, ref value);
if (_impossibleDefaultValue == value)
{
errorMsg = string.Format("Required configuration setting {0} was not" +
"found in {1}", kVPair.Key, CfgFileNameAndPath);
return false;
}
Type type = kVPair.Value;
_settings[kVPair.Key] = Convert.ChangeType(value, type);
return true;
}
}
PS. Additional issue is default values for optional settings. It's not elegant to pass them to LoadConfig in separate Dictionary, but that is an other issue...
The only way I can think of doing this is to have Dictionary<String,Object> and then cast the Object to the appropriate type.
Your underlying problem is how to dynamically specify the type:
Dynamically specify the type in C#
Turns out that type casting (actually unboxing) in C# has very little overhead:
C# performance analysis- how to count CPU cycles?
Update:
Here is how you do the casting:
Dictionary<String,Object> parameters = new Dictionary<String,Object>();
// cast a string
parameters.Add("DatabaseName", "SomeBase");
// cast a list
parameters.Add("Classes", new List<int> { int.Parse("11"), int.Parse("12"), int.Parse("13") });
// cast an integer
parameters.Add("IntValue", int.Parse("3"));
// cast a double
parameters.Add("DoubleValue", Double.Parse("4.0"));
Then when you want to use the values you just do the unboxing:
int intValue = (int)parameters["IntValue"];
Double doubleValue = (Double)parameters["DoubleValue"];
List<int> classes = (List<int>)parameters["Classes"];
// etc...
As I mentioned before: after doing performance testing I found that unboxing has negligent overhead so you should not see any noticeable performance issues.
Update 2.0:
I'm guessing you want to automatically convert the type without having to explicitly specify it when you're adding it into the _settings dictionary. It should work if your dictionary's value is an Object:
Type t = typeof(double);
Object val = Convert.ChangeType("2.0", t);
// you still need to unbox the value to use it
double actual = (double)val;
So your example should work:
_settings[kVPair.Key] = Convert.ChangeType(value, type);
You just need to unbox the value with the correct type when you're going to use it.
You don't have to do this with generics.
You could simply have three methods like
public string GetStringConfig(string key){}
public List<int> GetListConfig(string key){}
public int GetIntegerConfig(string key){}
(you would have to throw an error if you try to parse / convert a string that does not match)
The above is like using a SQLAdapter.
This does of course assume you know the type of object the key should return