Fork me on GitHub

通过另类的泛型约束将两个输入输出参数不同的方法合并成一个方法的实现

 其实我也不知道如何定义这个标题,词乏,姑且先这样定义吧。

看了本文章的朋友,如果有更好标题,请告诉我,谢谢。

 

有个项目使用SDK时遇到这样一个情况。

该SDK有个BtPrinterManager类,拥有两个方法:ServerPrint和ClientPrint,这两个方法有一部分参数是一样的,一部分参数不一样

现在我们要对这个类进行封装,把这两个方法合并成一个方法,并且使其拥有相同的输入参数和输出参数

比较粗糙的做法是,把这两个方法的输入参数合并成一个输入模型类,把两个方法的输出参数也合并成一个输出模型类。

通过增加一个参数或(判断某个方法专属参数是否有值)在方法内部决定应该调用ServerPrint还是ClientPrint,以及应该从输入模型类里取哪些参数,应该赋哪些值给输出模型类。

如果不按照上面的做法写,还有什么办法可以做到呢?

答案是有的,泛型约束+方法内对泛型实际类型判断。

 

以下是实现代码:

  1 using System;
  2 
  3 namespace Test
  4 {
  5     internal class Program
  6     {
  7         private static void Main(string[] args)
  8         {
  9             Run();
 10             
 11             Console.ReadKey();
 12         }
 13 
 14         private static void Run()
 15         {
 16             PrinterManager clientManager = new ClientPrinterManager();
 17             ClientInputModel clientInputModel = new ClientInputModel();
 18             //clientInputModel对象赋值....
 19             Action<ClientOutputModel> clientAction = info => { Console.WriteLine(info.PrinterName + info.ClientName); };
 20             clientManager.Print(clientInputModel, clientAction);
 21 
 22             PrinterManager serverManager = new ServerPrinterManager();
 23             ClientInputModel serverInputModel = new ClientInputModel();
 24             //serverInputModel对象赋值....
 25             Action<ServerOutputModel> serverAction = info => { Console.WriteLine(info.PrinterName + info.ServerName); };
 26             serverManager.Print(serverInputModel, serverAction);
 27         }
 28     }
 29 
 30     /// <summary>
 31     /// 打印管理类
 32     /// </summary>
 33     public abstract class PrinterManager
 34     {
 35         /// <summary>
 36         /// 打印文件
 37         /// </summary>
 38         /// <typeparam name="TInputModel"></typeparam>
 39         /// <typeparam name="TOutputModel"></typeparam>
 40         /// <param name="model"></param>
 41         /// <param name="action"></param>
 42         /// <returns></returns>
 43         public abstract string Print<TInputModel, TOutputModel>(TInputModel model, Action<TOutputModel> action) where TInputModel : InputModelBase, new() where TOutputModel : OutputModelBase, new();
 44     }
 45 
 46     /// <summary>
 47     /// 客户端打印管理类
 48     /// </summary>
 49     public class ClientPrinterManager : PrinterManager
 50     {
 51         public override string Print<TInputModel, TOutputModel>(TInputModel model, Action<TOutputModel> action)
 52         {
 53             string message = string.Empty;
 54 
 55             #region 泛型类型校验
 56             if (typeof(TInputModel) != typeof(ClientInputModel))
 57             {
 58                 throw new ArgumentException($"{nameof(TInputModel)} generic types must be of type {nameof(ClientInputModel)}", nameof(ClientInputModel));
 59             }
 60 
 61             if (typeof(TOutputModel) != typeof(ClientOutputModel))
 62             {
 63                 throw new ArgumentException($"{nameof(TOutputModel)} generic types must be of type {nameof(ClientOutputModel)}", nameof(ClientOutputModel));
 64             }
 65             #endregion
 66 
 67             #region 这里假装是调用某SDK方法获取的结果
 68 
 69             //BtPrinter printer = new BtPrinter();
 70             //string message;
 71             //var info = printer.ClientPrint(model.Param1, model.Param2, model.Param1, model.ClientParam1, out message);
 72 
 73             var info = new ClientOutputModel
 74             {
 75                 PrinterName = "Test Printer",
 76                 ClientName = "Test Client"
 77             };
 78             message = "ClientPrint Success";
 79 
 80             #endregion
 81 
 82             TOutputModel result = (TOutputModel)Convert.ChangeType(info, typeof(TOutputModel));
 83             action(result);
 84 
 85             return message;
 86         }
 87     }
 88 
 89     /// <summary>
 90     /// 服务器端打印管理类
 91     /// </summary>
 92     public class ServerPrinterManager : PrinterManager
 93     {
 94         public override string Print<TInputModel, TOutputModel>(TInputModel model, Action<TOutputModel> action)
 95         {
 96             string message = string.Empty;
 97 
 98             #region 泛型类型校验
 99             if (typeof(TInputModel) != typeof(ServerInputModel))
100             {
101                 throw new ArgumentException($"{nameof(TInputModel)} generic types must be of type {nameof(ServerInputModel)}", nameof(ServerInputModel));
102             }
103 
104             if (typeof(TOutputModel) != typeof(ServerOutputModel))
105             {
106                 throw new ArgumentException($"{nameof(TOutputModel)} generic types must be of type {nameof(ServerOutputModel)}", nameof(ServerOutputModel));
107             }
108             #endregion
109 
110             #region 这里假装是调用某SDK方法获取的结果
111 
112             //BtPrinter printer = new BtPrinter();
113             //string message;
114             //var info = printer.ServerPrint(model.Param1, model.Param2, model.ServerParam1, model.ServerParam2, out message);
115 
116             var info = new ServerOutputModel
117             {
118                 PrinterName = "Test Printer",
119                 ServerName = "Test Server"
120             };
121             message = "ServerPrint Success";
122 
123             #endregion
124 
125             TOutputModel result = (TOutputModel)Convert.ChangeType(info, typeof(TOutputModel));
126             action(result);
127 
128             return message;
129         }
130     }
131 
132     #region 输入模型类
133     public class InputModelBase
134     {
135         public string Param1 { get; set; }
136 
137         public string Param2 { get; set; }
138     }
139 
140     public class ClientInputModel : InputModelBase
141     {
142         public string ClientParam1 { get; set; }
143     }
144 
145     public class ServerInputModel : InputModelBase
146     {
147         public string ServerParam1 { get; set; }
148 
149         public string ServerParam2 { get; set; }
150     }
151     #endregion
152 
153     #region 输出模型类
154     public class OutputModelBase
155     {
156         public string PrinterName { get; set; }
157     }
158 
159     public class ClientOutputModel : OutputModelBase
160     {
161         public string ClientName { get; set; }
162     }
163 
164     public class ServerOutputModel : OutputModelBase
165     {
166         public string ServerName { get; set; }
167     }
168     #endregion
169 }

 

如果有更好的方法实现,求指教,谢谢。

posted @ 2017-08-04 12:20  VAllen  阅读(1134)  评论(1编辑  收藏  举报