Access911.net   |   a9BBS   |   OTaA System  
  搜索文章:  
Access911欢迎您光临  
   主页      上传      繁體版       论坛     
设为首页  |  加入收藏   
  
你现在的位置:文章索引 -> 文章分类 -> C#/.Net  
 首页|  近日更新|  下载  |  文章索引  |  搜索|  术语|  承接工程|  
 
系统正在加载内容,请耐心等待...
 
 查询
 窗体
 报表
 
 
 VBA
 函数
 ADO/DAO/ADO.NET
 API
 ADP
 安全
 发布
 OA
 ASP/ASP.NET
 其他语言
 控件
 DELPHI
 C#/.Net
 本站
 其他
 小例程
 常用软件
 参考文档
 业主作品
 网友大作
 
 
友情链接
 access911.net
 
访问人次
 1701953
 
站长 E-Mail
 net911@sina.com
 access911@gmail.com
 
RSS 订阅

显示附加信息 >>>

.NET 中用反射来生成和执行 IList<IInterfaceType> 的属性

作者:cg1  摘自:access911.net  :cg1  更新日期:2015-4-17  浏览人次:

 

问题:

主要难点是在如何动态生成 IList<接口> 的属性。属性本身就是接口类型,而其包含的泛型参数也是接口。
用 Json.Net 做 ORM 都没有找到解决方案,就自己写了个简单的。

 

回答:


using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
//需要引用 Json.net 的类库。http://www.newtonsoft.com/json 可以下载,也可以屏蔽代码中演示用的json解析部分
//using Newtonsoft.Json;
//using Newtonsoft.Json.Linq;
//using Newtonsoft.Json.Serialization;
using System.Reflection;
using System.Diagnostics;


namespace qq20662.WeiXin.Tests.Models
{
    //IList反射的操作的演示,请查看标有 ?????? 的行次。
    //IList反射不出 Add 方法。奇怪。
    /// <summary>
    /// IList反射的操作的演示,问题未解决20150416,问题在20150417日已经解决了,看++++的行次。
    /// </summary>
    public class ReflectionIList
    {
        public void test1()
        {
            //如果普通生成可以这样:
            AA a1 = new AA();
            a1.Ap1 = "xx";
            BB_1 b1 = new BB_1();
            b1.Bp1 = 115;
            BB_2 b2=new BB_2();
            b2.Bp1 = 171;
            //注意这里可以替换为其他实现了 IList接口的用户自定义类
            a1.AaBb = new List<IBB>();      
            a1.AaBb.Add(b1);
            a1.AaBb.Add(b2);

            //如何通过反射生成 AA 的对象。
            //当 AaBb 中无法确定使用那个具体类来实例化,允许直接使用BB_1
            string jString = @"{
                ""Ap1"":""xx"",
                ""AaBb"":[{""Bp1"":115},{""Bp1"":171}]
            }";

            //假定已经把json全部解析完毕了。这几行可以屏蔽
            //JObject jo = JObject.Parse(jString);

            //这里可以得到 qq20662.WeiXin.Tests ,在每个人的项目中都不一样的,
            //可以复制出来,下面要用的
            Debug.Print(typeof(AA).Assembly.GetName().Name);
            //这里可以得到 qq20662.WeiXin.Tests.Models.AA ,在每个人的项目中都不一样的,
            //可以复制出来,下面要用的
            Debug.Print(typeof(AA).FullName);                   
            //假定可以用工厂模式从配置文件加载 AA 的 type fullname
            object oa1 = Activator.CreateInstance(
                    Assembly.Load("access911.WeiXin.Tests")
                        .GetType("qq20662.WeiXin.Tests.Models.AA"));
            //获取 oa1 的所有属性
            PropertyInfo[] props =oa1.GetType()
                .GetProperties(BindingFlags.Public 
                    | BindingFlags.Instance) ;
            foreach (PropertyInfo prop in props) { 
                //这里可以与json做匹配,看属性名是否符合。
                //比较简单,就忽略了。
                if (prop.Name == "AaBb") {
                    //得到泛型中的类型,如 IBB
                    Type t2 = prop.PropertyType.GetGenericArguments().First();  
                    Type[] typeArgs = { t2 };               //生成泛型参数
                    //假定提供参数,可以用 List<> 来实现 IList 接口
                    Type algTypeGen = typeof(List<>);       //生成列表
                    Type algType = algTypeGen.MakeGenericType(typeArgs);    //生成具体的泛型列表。
                    object oAaBb = Activator.CreateInstance(algType);

                    //下面省略用反射获取 BB_1 类型的对象。基本根上面差不多,
                    //可以用工厂类根据json和预先设置的字符串来返回实例
                    BB_1 b3 = new BB_1();
                    b3.Bp1 = 9999;

                    MethodInfo addMethod = prop.PropertyType
                                                    .GetMethod("Add");
                    //??????下面这行就比较奇怪了,按道理 IList的属性应该有 Add 方法,
                    //但是这里返回的是null,未获取到。
                    //这里返回 true 表示没有add方法,奇怪。
                    Debug.Print((addMethod == null).ToString());        

                    MethodInfo[] ms = prop.PropertyType.GetMethods();
                    foreach(MethodInfo mItem in ms ){
                        Debug.Print(mItem.Name);
                    }
                    //??????上面循环的输出结果是下面这些。
                    //get_Item
                    //set_Item
                    //IndexOf
                    //Insert
                    //RemoveAt

                    //下面这行的返回值是 System.Collections.Generic.IList`1[[qq20662.WeiXin.Tests.Models.IBB, qq20662.WeiXin.Tests, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]
                    //应该是对的,那 Add 方法到哪里去了? IList.Add 方法应该有的呀?
                    Debug.Print(prop.PropertyType.FullName);

                }
            }


            // +++++++ 请注意,下面这部分是最终答案
            var oProp = oa1.GetType().GetProperty("AaBb").GetValue(oa1, null);
            //下面这行也能得到add方法。
            //oa1.GetType().GetProperty("AaBb").PropertyType.GetInterfaces()[0].GetMethod("Add")

            Type[] typeInterfaces = oProp.GetType().GetInterfaces();
            // 注意上面这行会返回多个接口。表示这个属性对象符合多个接口。其中 IList ICollection`1(泛型) 接口有add方法。
            //+        [0]    {Name = "IList`1" FullName = "System.Collections.Generic.IList`1[[qq20662.WeiXin.Tests.Models.IBB, access911.WeiXin.Tests, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]"}    System.Type {System.RuntimeType}
            //+        [1]    {Name = "ICollection`1" FullName = "System.Collections.Generic.ICollection`1[[qq20662.WeiXin.Tests.Models.IBB, access911.WeiXin.Tests, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]"}    System.Type {System.RuntimeType}
            //+        [2]    {Name = "IEnumerable`1" FullName = "System.Collections.Generic.IEnumerable`1[[qq20662.WeiXin.Tests.Models.IBB, access911.WeiXin.Tests, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]"}    System.Type {System.RuntimeType}
            //+        [3]    {Name = "IEnumerable" FullName = "System.Collections.IEnumerable"}    System.Type {System.RuntimeType}
            //+        [4]    {Name = "IList" FullName = "System.Collections.IList"}    System.Type {System.RuntimeType}
            //+        [5]    {Name = "ICollection" FullName = "System.Collections.ICollection"}    System.Type {System.RuntimeType}

            foreach (Type tItf in typeInterfaces) {
                Debug.Print(tItf.Name);
                //有add方法的接口有2个,因此会添加两个子对象。
                if (tItf.GetMethod("Add") != null) {
                    Debug.Print(string.Format("接口{0}有add方法。",tItf.Name));
                    //这里省略了用反射来获取 IList<>泛型中类型参数并生成对象的过程。
                    //可以用工厂模式
                    var oBb_X = Activator.CreateInstance(typeof(BB_1));
                    oBb_X.GetType().GetProperty("Bp1").SetValue(oBb_X,3222,null);
                    tItf.GetMethod("Add").Invoke(oProp, new object[] { oBb_X});
                }
            }
        }
    }


    public class AA
    {
        public string Ap1;

        protected IList<IBB> _aaBb = new List<IBB>();
        public IList<IBB> AaBb{
            get{return _aaBb ;}
            set { _aaBb = value; }
        }

    }
    public interface IBB
    {
        int Bp1 { get; set; }
        void Add();
    }
    public class BB_1 : IBB
    {
        public int Bp1 { get; set; }
        public void Add() { }

    }
    public class BB_2 : IBB
    {
        public int Bp1 { get; set; }
        public void Add() { }

    }


}


 

本站文章旨在为该问题提供解决思路及关键性代码,并不能完成应该由网友自己完成的所有工作,请网友在仔细看文章并理解思路的基础上举一反三、灵活运用。

access911.net 原创文章,作者本人对文章保留一切权利。
如需转载必须征得作者同意并注明本站链接

 

 
相关文章
     没有手动相关文章
     Linq中用反射生成非实体类的代码,作用只是加快点速度
     access911.net靠什么生存(网友提问引发思考)
     数据访问接口体系及数据对象模型探讨
 
评论
     查看或发表更多的评论,请单击这里。
 
 
 
 
 
   
  Access911.net   |   a9BBS   |   OTaA System   |
建站日期:2000年4月2日  |  设计施工:陈格 ( access911 & cg1 )
 Copyright © 2000 - 2003 COMET, 陈格 保留所有权利