使用反射将"列表"<dynamic>设置为"列表"<T>



比如说,我在一个类中有这些属性:

public class Example
{
    public List<Toyota> listToyota; 
    public List<Honda> listHonda; 
    public List<Huyndai> listHuyndai; 
    ... 
    ... 
}

如果有新的汽车品牌,将会有更多的属性。每个品牌都是一张桌子。

通常,我会这样做以从表中获取数据:

Example result = new Example();
switch (brandname)
{
    case "Toyota":
        result.listToyota = * select table from context * ; 
        break;
    case "Honda":
        result.listHonda = * select table from context * ; 
        break;
        ...
}

此外,当有新品牌时,我将不得不添加更多代码。我发现这非常烦人/耗时,并决定切换到动态方法。我已经成功地动态获取了表格:

tblName = "Toyota"; 
IEnumerable<dynamic> table = typeof(MyContext).GetProperty(tblName).GetValue(context, null) as IEnumerable<dynamic>;

但是我未能动态设置属性值,在此示例中,listToyota

query = (from a in table select a).ToList() as List<dynamic>;
SetPropertyValue(result, "listToyota", query);

我收到此错误:

类型为"System.Collections.Generic.List1[System.Object]"的对象 无法转换为类型 "System.Collections.Generic.List1[Toyota]"。

SetPropertyValue 是一个非常简单的函数,使用 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);
}

任何建议都非常感谢!

请尝试这样的事情

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

我认为主要问题是你的软件设计。我不会以这种方式使用动态。

  1. 我会创建一个品牌类。如果要使用动态,请尝试如下操作:

    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;
             }
        }
    
  2. 我会改变你的示例类

    public class Example
    {
        // string = brand-name; list = list of dynamic brand items
        public Dictionary<string, List<DynamicBrand>> brands;
    }
    
  3. 当您填写数据时,只需将一个新的动态品牌添加到您的品牌列表中,然后只需添加您需要的成员即可。

编辑:动态不是解决您问题的好方法。我会考虑一个完全不同的结构。

最新更新