Say, I have these properties in a class :
public class Example
{
public List<Toyota> listToyota;
public List<Honda> listHonda;
public List<Huyndai> listHuyndai;
...
...
}
And there will be more properties if there are new car brands. Each brand is a table.
Normally, I would do this to get the data from tables :
Example result = new Example();
switch (brandname)
{
case "Toyota":
result.listToyota = * select table from context * ;
break;
case "Honda":
result.listHonda = * select table from context * ;
break;
...
}
Also, I'll have to add more code when there are new brands. I found this very annoying/time-consuming and decided to switch to a dynamic approach. I've sucessfully get the tables dynamically :
tblName = "Toyota";
IEnumerable<dynamic> table = typeof(MyContext).GetProperty(tblName).GetValue(context, null) as IEnumerable<dynamic>;
But I failed to dynamically set the property value, in this example, is listToyota
:
query = (from a in table select a).ToList() as List<dynamic>;
SetPropertyValue(result, "listToyota", query);
I got this error :
Object of type 'System.Collections.Generic.List1[System.Object]' cannot be converted to type 'System.Collections.Generic.List1[Toyota]'.
SetPropertyValue
is a very simple function using System.Reflection
:
static void SetPropertyValue(object p, string propName, object value)
{
Type t = p.GetType();
System.Reflection.PropertyInfo info = t.GetProperty(propName);
if (info == null)
return;
if (!info.CanWrite)
return;
info.SetValue(p, value, null);
}
Any advices are greatly appreciated!
Please try something like this
static void SetPropertyValue(object p, string propName, object value)
{
Type t = p.GetType();
System.Reflection.PropertyInfo info = t.GetProperty(propName);
if (info == null)
return;
if (!info.CanWrite)
return;
var elemtype = info.PropertyType.GetElementType();
var castmethod = typeof(Enumerable).GetMethod("Cast", BindingFlags.Public | BindingFlags.Static).MakeGenericMethod(elemtype);
var tolist = typeof(Enumerable).GetMethod("ToList", BindingFlags.Public | BindingFlags.Static).MakeGenericMethod(elemtype);
var collection = castmethod.Invoke(null, new object[] { value });
var list = tolist.Invoke(null, new object[] { collection });
info.SetValue(p, list, null);
}
I think the main problem is your software design. I wouldn't use dynamic this way.
I would create a Brand-Class. If you want to use dynamic, try something like this:
public class DynamicBrand : DynamicObject { private IDictionary<string, object> myDynamicValues; public DynamicBrand() : base() { myDynamicValues = new Dictionary<string, object>(); } public void AddMember(string Name, object Value) { if (!myDynamicValues.ContainsKey(Name.Trim().ToLower())) { myDynamicValues.Add(Name.ToLower().Trim(), Value); } else { throw new Exception("The Member with the Name: " + Name + " already exists!"); } } public override bool TrySetMember(SetMemberBinder Binder, object Value) { if (myDynamicValues.ContainsKey(Binder.Name.ToLower())) { myDynamicValues[Binder.Name.ToLower()] = Value; return true; } else { myDynamicValues.Add(Binder.Name.ToLower(), Value); } return true; } publc override bool TryGetMember(GetMemberBinder Binder, out object Result) { if (myDynamicValues.ContainsKey(Binder.Name.ToLower())) { Result = myDynamicValues[Binder.Name.ToLower()]; return true; } else { Result = null; return false; } }
I would change your example class
public class Example { // string = brand-name; list = list of dynamic brand items public Dictionary<string, List<DynamicBrand>> brands; }
Whenyou fill your data, just add a new dynamic brand to your brands-list and simply add the member you need.
EDIT : Dynamic isn't a very nice solution for your problem. I would think about a completly different structure.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.