Work.Dynamic.Loaddll.Note

今天做动态加载dll发现一个好的泛型读取列的方法,结合自己的使用,还有自己的命名的越来越感觉好一些,看代码就像读英文。

DllFile.cs.Code
 1     /// <summary>
 2     /// dll文件
 3     /// </summary>
 4     internal struct DllFile
 5     {
 6         /// <summary>
 7         /// 文件名
 8         /// </summary>
 9         public string Name { get; set; }
10 
11         /// <summary>
12         /// 二进制文件
13         /// </summary>
14         public byte[] Content { get; set; }
15 
16         /// <summary>
17         /// 描述
18         /// </summary>
19         public string Comment { get; set; }
20 
21         /// <summary>
22         /// 上传用户id
23         /// </summary>
24         public string OwnerId { get; set; }
25 
26         /// <summary>
27         /// 上传时间
28         /// </summary>
29         public DateTime UploadTime { get; set; }
30     }
DataRow.ReadColumn.Code.Generic (泛型读取列.感觉还不错)
 1       private static T GetColumnValue<T>(DataRow dr, string name)
 2         {
 3             try
 4             {
 5                 if (dr[name] == DBNull.Value)
 6                 {
 7                     return GetDefault<T>();
 8                 }
 9                 else
10                 {
11                     return (T)dr[name];
12                 }
13             }//如果不存在这一列
14             catch (ArgumentException ex)
15             {
16                 throw new ArgumentException(string.Format("{0}列不存在。", name));
17             }
18         }
19         private const string emptyStr = "";
20         /// <summary>
21         /// 根据类型获取默认值
22         /// </summary>
23         /// <typeparam name="T"></typeparam>
24         /// <returns></returns>
25         private static T GetDefault<T>()
26         {
27             T t = default(T);
28             if (emptyStr is T)
29                 return (T)(object)emptyStr;
30             return t;
31         }

结合自己的代码读取列

Read.DllFile from DataRow.Code
 1   protected ICollection<DllFile> GetDllFiles(DataSet ds)
 2         {
 3             ICollection<DllFile> result = new Collection<DllFile>();
 4             if (null == ds)
 5                 throw new ArgumentNullException("ds");
 6             int rCount = ds.Tables[0].Rows.Count;
 7             if (rCount > 0)
 8             {
 9                 for (int i = 0; i < rCount; i++)
10                 {
11                     DataRow dr = ds.Tables[0].Rows[i];
12                     result.Add(FormatDllFile(dr));
13                 }
14             }
15             return result;
16         }
17 
18         private DllFile FormatDllFile(DataRow dr)
19         {
20             DllFile file = new DllFile();
21             file.OwnerId = GetColumnValue<string>(dr, userField);
22             file.Name = GetColumnValue<string>(dr, fileNameField);
23             file.Content = GetColumnValue<byte[]>(dr, fileContentField);
24             file.Comment = GetColumnValue<string>(dr, commentField);
25             file.UploadTime = GetColumnValue<DateTime>(dr, updateTimeField);
26             return file;
27         }
28         /// <summary>
29         /// 根据类型或DataRow列
30         /// </summary>
31         /// <typeparam name="T"></typeparam>
32         /// <param name="dr"></param>
33         /// <param name="name"></param>
34         /// <returns></returns>
35         private static T GetColumnValue<T>(DataRow dr, string name)
36         {
37             try
38             {
39                 if (dr[name] == DBNull.Value)
40                 {
41                     return GetDefault<T>();
42                 }
43                 else
44                 {
45                     return (T)dr[name];
46                 }
47             }//如果不存在这一列
48             catch (ArgumentException ex)
49             {
50                 throw new ArgumentException(string.Format("{0}列不存在。", name));
51             }
52         }
53         private const string emptyStr = "";
54         /// <summary>
55         /// 根据类型获取默认值
56         /// </summary>
57         /// <typeparam name="T"></typeparam>
58         /// <returns></returns>
59         private static T GetDefault<T>()
60         {
61             T t = default(T);
62             if (emptyStr is T)
63                 return (T)(object)emptyStr;
64             return t;
65         }

设计通过接口和反射来实现程序模块之间的解耦关系的一种机制,实现者将接口的实现类的Type和标记注册的程序集中,程序启动,或者用户更换dll到数据库时,更新全局静态注册字典,将类型更新到字典中。

使用者根据与实现者沟通好的标记,创建接口实例,最终可以在不同的模块调用接口方法。

程序集属性类

Assembly.ExtensionAttribute.Code
 1     public class RegisterImplAttribute : Attribute
 2     {
 3         public Type InterfaceType { get; private set; }
 4 
 5         public string ImplFlag { get; private set; }
 6 
 7         public Type ImplType { get; private set; }
 8 
 9         public RegisterImplAttribute(Type implType, string implFlag)
10         {
11             this.ImplType = implType;
12             this.ImplFlag = implFlag;
13         }
14 
15         public RegisterImplAttribute(Type iType, Type implType, string implFlag)
16         {
17             this.InterfaceType = iType;
18             this.ImplType = implType;
19             this.ImplFlag = implFlag;
20         }
21     }

重要的一步在程序集中添加接口实现类和实现类的标记,打开工程下.Properties/Assemboy.cs

1 在文件中添加程序集属性。
2 [assembly: Dynamic.RegisterImpl(typeof(AppendixFileController), "CRCC.Appendixs.1")]
3 "CRCC.Appendixs.1"是接口实现类的标记,用于与其他接口实现类区分。通过这个标记最终才能找到实现类的。

设计一个静态服务类,用于保存dll,同时动态加载程序集和程序集中的接口实现类,最终提供给用于一个接口实例。

DynamicDllService.Code
  1  public static class DynamicDllService
  2     {
  3         private static IDictionary<string, Type> IInstances = new Dictionary<string, Type>();
  4         /// <summary>
  5         /// 动态dll存放目录
  6         /// </summary>
  7         private static readonly string folderDir = System.AppDomain.CurrentDomain.BaseDirectory + "\\DyBin";
  8 
  9         /// <summary>
 10         /// 加载所有动态dll表中的dll、并注册
 11         /// </summary>
 12         public static void InitAllInstance(IContext context)
 13         {
 14             DynamicDllDao dllDao = new DynamicDllDao(context);
 15             ICollection<DllFile> files = dllDao.SelectAll();
 16             if (null != files && files.Count > 0)
 17             {
 18                 DllStreamLocalize dllReader = new DllStreamLocalize();
 19                 foreach (var file in files)
 20                 {
 21                     dllReader.SaveFileToLocal(file.Content, folderDir, file.Name);
 22                     string filePath = string.Format("{0}{1}", dllReader.VerifyPath(folderDir), dllReader.GetDllFullName(file.Name));
 23                     RegisterDllImpl(filePath);
 24                 }
 25             }
 26         }
 27 
 28         /// <summary>
 29         /// 保存dll并注册到系统中
 30         /// </summary>
 31         /// <param name="context">上下文</param>
 32         /// <param name="userId">用户id</param>
 33         /// <param name="fileName">文件名</param>
 34         /// <param name="filebit">二进制文件</param>
 35         /// <param name="comment">文件描述</param>
 36         public static void SaveFile(IContext context, string userId, string fileName, byte[] filebit, string comment)
 37         {
 38             if (null == context)
 39                 throw new ArgumentNullException("context");
 40             if (string.IsNullOrEmpty(fileName))
 41                 throw new ArgumentNullException("fileName");
 42             if (string.IsNullOrEmpty(userId))
 43                 throw new ArgumentNullException("userId");
 44             DynamicDllDao dllDao = new DynamicDllDao(context);
 45             DllFile? file = dllDao.SearchByFileName(fileName);
 46             if (file != null)
 47                 dllDao.Update(userId, fileName, filebit, comment);
 48             else
 49                 dllDao.Insert(userId, fileName, filebit, comment);
 50 
 51             //实例化到本地
 52             DllStreamLocalize dllReader = new DllStreamLocalize();
 53             dllReader.SaveFileToLocal(filebit, folderDir, fileName);
 54             string filePath = string.Format("{0}{1}", dllReader.VerifyPath(folderDir), dllReader.GetDllFullName(fileName));
 55             RegisterDllImpl(filePath);
 56         }
 57 
 58         private static void RegisterDllImpl(string filePath)
 59         {
 60             object o = new object();
 61             lock (o)
 62             {
 63                 IDictionary<string, Type> implTypes = GetInstanceTypes(filePath);
 64                 foreach (var item in implTypes)
 65                 {
 66                     if (IInstances.ContainsKey(item.Key))
 67                         IInstances[item.Key] = item.Value;
 68                     else
 69                         IInstances.Add(item);
 70                 }
 71             }
 72         }
 73 
 74         private static IDictionary<string, Type> GetInstanceTypes(string filePath)
 75         {
 76             if (string.IsNullOrEmpty(filePath))
 77                 throw new ArgumentNullException("filePath");
 78 
 79             if (!File.Exists(filePath))
 80                 throw new FileNotFoundException(string.Format("加载:{0},失败。", filePath));
 81             Assembly assmbly = Assembly.LoadFile(filePath);
 82             object[] assAttrs = assmbly.GetCustomAttributes(typeof(RegisterImplAttribute), false);
 83 
 84             IDictionary<string, Type> result = new Dictionary<string, Type>();
 85             if (assAttrs.Length > 0)
 86             {
 87                 for (int i = 0; i < assAttrs.Length; i++)
 88                 {
 89                     RegisterImplAttribute reg = assAttrs[i] as RegisterImplAttribute;
 90                     if (result.ContainsKey(reg.ImplFlag))
 91                         result[reg.ImplFlag] = reg.ImplType;
 92                     else
 93                         result.Add(reg.ImplFlag, reg.ImplType);
 94                 }
 95             }
 96             return result;
 97         }
 98 
 99         /// <summary>
100         /// 根据接口实现标记获取,当前泛型接口实例
101         /// </summary>
102         /// <typeparam name="T">传入的泛型接口</typeparam>
103         /// <param name="implFlag">接口实现类实现标记</param>
104         /// <param name="initArgType">构造函数参数类型数组</param>
105         /// <param name="initArgVal">构造函数参数值数组</param>
106         /// <returns>接口实例</returns>
107         public static T GetInterfaceImpl<T>(string implFlag, Type[] initArgType, object[] initArgVal)
108         {
109             T instance = default(T);
110             Type implType;
111             if (IInstances.TryGetValue(implFlag, out implType))
112             {
113                 try
114                 {
115                     ConstructorInfo construct = implType.GetConstructor(initArgType);
116                     if (construct != null)
117                         instance = (T)construct.Invoke(initArgVal);
118                 }
119                 catch (ArgumentException e)
120                 {
121                     throw new ArgumentException("反射生成实例失败,清检查构造函数参数信息。");
122                 }
123             }
124             return instance;
125         }
126 
127         /// <summary>
128         /// 根据接口实例标记,获取接口实现,无构造函数参数
129         /// </summary>
130         /// <typeparam name="T">泛型接口</typeparam>
131         /// <param name="implFlag">实现标记</param>
132         /// <returns>接口实例</returns>
133         public static T GetInterfaceImpl<T>(string implFlag)
134         {
135             T instance = default(T);
136             Type implType;
137             if (IInstances.TryGetValue(implFlag, out implType))
138             {
139                 try
140                 {
141                     instance = (T)System.Activator.CreateInstance(implType);
142                 }
143                 catch (ArgumentException e)
144                 {
145                     throw new ArgumentException("反射创建实例失败,请核实参数类型是否正确。");
146                 }
147             }
148             return instance;
149         }
150     }

DynamicDllService有三个公开方法,

InitAllInstance:用于在程序启动时,将所有数据中的dll加InitAllInstance中。

SaveFile:是保存dlll并同时动态加载dll中接口实现类和标记,这里注册到该类的静态私有字典(IInstances)中

static T GetInterfaceImpl<T>(string implFlag):最终通过翻新方法返回泛型实例接口,T为所需要到的泛型接口,implFlag:实现类标记。

原文地址:https://www.cnblogs.com/lovey/p/2994184.html