How to set class fields using keys? - c#

I wrote a generic method which should let us send type, an array which includes field names and an array which includes field values. I need to get class field by key from a dictionary and set value from dictionary to these fields and create new instance of this object
private static T test<T>(T obj, string[] fieldArr, string[] valueArr)
{
Type type = obj.GetType();
List<string> data = new List<string>();
var bindingFlags = BindingFlags.Instance |
BindingFlags.NonPublic |
BindingFlags.Public;
List<PropertyInfo> props = type.GetProperties(bindingFlags).ToList();
Dictionary<string, string> dict = new Dictionary<string, string>();
FieldInfo[] fieldInfos = type.GetFields();
for (int i = 0; i < fieldArr.Length; i++)
{
dict.Add(fieldArr[i], valueArr[i]);
}
var de = new List<PropertyInfo>();
foreach (var item in dict)
{
var fi = type.GetProperty(item.Key);
object obji = null;
fi.SetValue(obji, item.Value);
de.Add(fi);
}
return T;
}
Any suggestions?

Related

creating IList<T> values at runtime from variables

Im getting data from a solaceconnection which returns data as so {Account:"023": hasAccount:true} and I need to break it up and put it into two list (IList names and IList values). Names will be "Account" and "hasAccount" which I am able to do. But, Im having a problem with values. I am trying to get the type of the values ("023" and true in this example) and creating IList of type string" for "023" and IList of type bool for true. I have been trying the below but
Cache.ToList().ForEach(row => {
List<string> _namesList = new List<string>();
List<object> _valuesList = new List<object>();
FieldInfo[] fields = row.GetType().GetFields(BindingFlags.Public |
BindingFlags.NonPublic |
BindingFlags.Instance);
fields.ToList().ForEach(field => {
var fieldName = field.Name;
var fieldValue = field.GetValue(row);
_namesList.Add(fieldName);
var m_oEnum = Activator.CreateInstance(fieldValue.GetType(), new object[] { 1 }); // Length 1
//var m_oEnum = new propertyType[] { fieldValue };
_valuesList.Add(m_oEnum);
});
});
My intentions with var m_oEnum is to create a IList or array of type stirng or bool and set the fieldvalue in it. But Im not able to do it since i get the exception thrown "Constructor on type 'System.Boolean' not found." for line
var m_oEnum = Activator.CreateInstance(objectType, new object[] { 1 }); // Length 1
is it possible to create an array on the fly with a datatype and place the value in it? Thanks
Value types should be handled differently.
Cache.ToList().ForEach(row => {
List<string> _namesList = new List<string>();
List<object> _valuesList = new List<object>();
FieldInfo[] fields = row.GetType().GetFields(BindingFlags.Public |
BindingFlags.NonPublic |
BindingFlags.Instance);
fields.ToList().ForEach(field => {
var fieldName = field.Name;
var fieldValue = field.GetValue(row);
_namesList.Add(fieldName);
var objectType = fieldValue.GetType();
if (objectType.IsValueType)
{
_valuesList.Add(fieldValue);
}
else
{ // What about types without a parameterless constructor?
var m_oEnum = Activator.CreateInstance(objectType, new object[] { 1 }); // Length 1
_valuesList.Add(m_oEnum);
}
});
});

How to map dictionary with values containg tuples to class instance

I have a dictionary of type Dictionary<string, (int Id, string Code, string Name)>:
var dict = new Dictionary<string, (int Id, string Code, string Name)>
{
["subjectType"] = (1, "1Code", "1Name"),
["residentType"] = (2, "2Code", "2Name"),
["businessType"] = (3, "3Code", "3Name"),
// and so on...
};
I use tuple (int Id, string Code, string Name) here but I can replace it with a class. So, it doesn't matter tuple or class, I just need to have three properties (Id, Code, Name) for each dictionary item.
I need to project this dictionary into a class, so I map each property of output model separately like this:
public static OutputModel Map(
Dictionary<string, (int Id, string Code, string Name)> dictionary) =>
new OutputModel
{
SubjectTypeId = dictionary["subjectType"].Id,
SubjectTypeCode = dictionary["subjectType"].Code,
SubjectTypeName = dictionary["subjectType"].Name,
ResidentTypeId = dictionary["residentType"].Id,
ResidentTypeCode = dictionary["residentType"].Code,
ResidentTypeName = dictionary["residentType"].Name,
BusinessTypeId = dictionary["businessType"].Id,
BusinessTypeCode = dictionary["businessType"].Code,
BusinessTypeName = dictionary["businessType"].Name,
// and so on...
};
I wonder is there any other (more fancy) way to do the same mapping?
You could do the following.
var outPutModel = new OutputModel();
foreach (var keyValuePair in dictionary)
outPutModel.Write(keyValuePair);
public class OutputModel
{
public void Write(KeyValuePair<string, (int Id, string Code, string Name)> keyValuePair)
{
var type = typeof(OutputModel);
type.GetProperty(keyValuePair.Key + "Id", BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Public).SetValue(this, keyValuePair.Value.Id);
type.GetProperty(keyValuePair.Key + "Code", BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Public).SetValue(this, keyValuePair.Value.Code);
type.GetProperty(keyValuePair.Key + "Name", BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Public).SetValue(this, keyValuePair.Value.Name);
}
}
See it in action:
https://dotnetfiddle.net/jfKYsG

Using expression trees to construct an object with unknown members

I'm trying to create a generic function that will take 2 instances of a struct and create a new instance using the values of the passed-in instances. I'm mostly there but I'm having trouble figuring out how to build the expression tree to take the new values as parameters in the MemberInit (first time using expression trees).
I'm trying to avoid creating garbage (so no boxing) as much as possible.
Here's what I have so far:
private static readonly Dictionary<Type, FieldInfo[]> fieldInfoCache = new Dictionary<Type, FieldInfo[]>();
private static readonly Dictionary<FieldInfo, dynamic> compiledDelegates = new Dictionary<FieldInfo, dynamic>();
private static T Lerp<T>(T start, T end, float amount) where T : new()
{
FieldInfo[] fields;
var type = typeof(T);
if(!fieldInfoCache.TryGetValue(type, out fields))
{
fields = typeof(T).GetFields(BindingFlags.Public | BindingFlags.Instance);
fieldInfoCache.Add(type, fields);
}
var binds = new List<MemberBinding>();
foreach(var fieldInfo in fields)
{
dynamic getter;
if(!compiledDelegates.TryGetValue(fieldInfo, out getter))
{
var targetExp = Expression.Parameter(type, type.Name);
var fieldExp = Expression.Field(targetExp, fieldInfo);
getter = Expression.Lambda(typeof(Func<,>).MakeGenericType(type, fieldInfo.FieldType), fieldExp, targetExp).Compile();
compiledDelegates.Add(fieldInfo, getter);
}
var startVal = getter.Invoke(start);
var endVal = getter.Invoke(end);
//This needs to be assigned to something
var newVal = fieldInfo.FieldType.IsAssignableFrom(typeof(float)) ? LerpF(startVal, endVal, amount) : Lerp(startVal, endVal, amount);
var fieldParamExp = Expression.Parameter(fieldInfo.FieldType, "newVal");
var bind = Expression.Bind(fieldInfo, fieldParamExp);
binds.Add(bind);
}
//How do I fix these two lines?
var memberInit = Expression.MemberInit(Expression.New(type), binds);
var result = Expression.Lambda<Func<T>>(memberInit).Compile().Invoke();
return result;
}
The part that I'm stumped on is how to feed the values into those last 2 lines without causing boxing
Instead of
var fieldParamExp = Expression.Parameter(fieldInfo.FieldType, "newVal");
try use
var fieldParamExp = Expression.Constant(newVal);
Update:
For efficient cache you could use something like
var startPar = Expression.Parameter(typeof (T), "start");
var endPar = Expression.Parameter(typeof (T), "end");
var amountPar = Expression.Parameter(typeof (float), "amount");
foreach (var fieldInfo in fields)
{
MethodInfo mi;
if (fieldInfo.FieldType.IsAssignableFrom(typeof (float)))
{
mi = typeof (Program).GetMethod("LerpF");
}
else
{
mi = typeof (Program).GetMethod("Lerp").MakeGenericMethod(fieldInfo.FieldType);
}
var makeMemberAccess = Expression.Call(mi, Expression.MakeMemberAccess(startPar, fieldInfo), Expression.MakeMemberAccess(endPar, fieldInfo), amountPar);
binds.Add(Expression.Bind(fieldInfo, makeMemberAccess));
}
var memberInit = Expression.MemberInit(Expression.New(type), binds);
var expression = Expression.Lambda<Func<T, T, float, T>>(memberInit, startPar, endPar, amountPar);
Func<T, T, float, T> resultFunc = expression.Compile();
// can cache resultFunc
var result = resultFunc(start, end, amount);
But I don't know how you decide to use start or end parameter, so there may be some more complex conditions in bindings.

List all custom data stored in AppDomain

In order to store the state of processes when an error occured, I would like to list all (custom) data stored in AppDomain (by SetData).
The LocalStore property is private and AppDomain class not inheritable.
Is there any way to enumerate those data ?
AppDomain domain = AppDomain.CurrentDomain;
domain.SetData("testKey", "testValue");
FieldInfo[] fieldInfoArr = domain.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance);
foreach (FieldInfo fieldInfo in fieldInfoArr)
{
if (string.Compare(fieldInfo.Name, "_LocalStore", true) != 0)
continue;
Object value = fieldInfo.GetValue(domain);
if (!(value is Dictionary<string,object[]>))
return;
Dictionary<string, object[]> localStore = (Dictionary<string, object[]>)value;
foreach (var item in localStore)
{
Object[] values = (Object[])item.Value;
foreach (var val in values)
{
if (val == null)
continue;
Console.WriteLine(item.Key + " " + val.ToString());
}
}
}
Based on Frank59's answer but a bit more concise:
var appDomain = AppDomain.CurrentDomain;
var flags = BindingFlags.NonPublic | BindingFlags.Instance;
var fieldInfo = appDomain.GetType().GetField("_LocalStore", flags);
if (fieldInfo == null)
return;
var localStore = fieldInfo.GetValue(appDomain) as Dictionary<string, object[]>;
if (localStore == null)
return;
foreach (var key in localStore.Keys)
{
var nonNullValues = localStore[key].Where(v => v != null);
Console.WriteLine(key + ": " + string.Join(", ", nonNullValues));
}
Same solution, but as an F# extension method. May not need the null check.
https://gist.github.com/ctaggart/30555d3faf94b4d0ff98
type AppDomain with
member x.LocalStore
with get() =
let f = x.GetType().GetField("_LocalStore", BindingFlags.NonPublic ||| BindingFlags.Instance)
if f = null then Dictionary<string, obj[]>()
else f.GetValue x :?> Dictionary<string, obj[]>
let printAppDomainObjectCache() =
for KeyValue(k,v) in AppDomain.CurrentDomain.LocalStore do
printfn "%s" k

List all SystemColors

In Windows.Forms, I need to create a program which accepts any color and tries to find the corresponding system colors to it.
I was not able to figure out how to loop through all Colors of the System.Drawing.SystemColors class - it's a class, not an enum or a List.
How can I do this (some kind of reflection?)?
How about
public static Dictionary<string,object> GetStaticPropertyBag(Type t)
{
const BindingFlags flags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
var map = new Dictionary<string, object>();
foreach (var prop in t.GetProperties(flags))
{
map[prop.Name] = prop.GetValue(null, null);
}
return map;
}
or
foreach (System.Reflection.PropertyInfo prop in typeof(SystemColors).GetProperties())
{
if (prop.PropertyType.FullName == "System.Drawing.Color")
ColorComboBox.Items.Add(prop.Name);
}
And I cooked something up.
var typeToCheckTo = typeof(System.Drawing.Color);
var type = typeof(System.Drawing.SystemColors);
var fields = type.GetProperties(System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public).Where(p => p.PropertyType.Equals(typeToCheckTo));
foreach (var field in fields)
{
Console.WriteLine(field.Name + field.GetValue(null, null));
}

Categories