服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C# - C#中增强类功能的几种方式详解

C#中增强类功能的几种方式详解

2022-03-07 13:25Alvin.Lee C#

这篇文章主要给大家介绍了关于C#中增强类功能的几种方式的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧

前言

本文主要讲解如何利用C#语言自身的特性来对一个类的功能进行丰富与增强,便于拓展现有项目的一些功能。

拓展方法

扩展方法被定义为静态方法,通过实例方法语法进行调用。方法的第一个参数指定该方法作用于哪个类型,并且该参数以 this 修饰符为前缀。仅当使用 using 指令将命名空间显式导入到源代码中之后,扩展方法才可使用。

?
1
2
3
4
5
6
7
8
9
10
11
12
namespace Extensions
{
 
 public static class StringExtension
 {
 public static DateTime ToDateTime(this string source)
 {
  DateTime.TryParse(source, out DateTime result);
  return result;
 }
 }
}

注意:

  • 如果扩展方法与该类型中定义的方法具有相同的签名,则扩展方法永远不会被调用。
  • 在命名空间级别将扩展方法置于相应的作用范围内。例如,在一个名为 Extensions 的命名空间中具有多个包含扩展方法的静态类,则在使用这些拓展方法时,必须引用其命名空间 using Extensions

继承

继承 面向对象的一个特性,属于Is a 关系,比如说Student继承Person,则说明Student is a Person。子类可以通过重写父类的方法或添加新的方法来实现对父类的拓展。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
namespace Inherit
{
 public class Persion
 {
 public string Name { get; set; }
 
 public int Age { get; set; }
 
 public void Eat()
 {
  Console.WriteLine("吃饭");
 }
 
 public void Sleep()
 {
  Console.WriteLine("睡觉");
 }
 }
 
 public class Student : Persion
 {
 public void Study()
 {
  Console.WriteLine("学习");
 }
 
 public new void Sleep()
 {
  Console.WriteLine("做作业,复习功课");
  base.Sleep();
 }
 }
}

继承的缺点:

  • 父类的内部细节对子类是可见的
  • 子类与父类的继承关系在编译阶段就确定下来了,无法在运行时动态改变从父类继承方法的行为
  • 如果父类方法做了修改,所有的子类都必须做出相应的调整,子类与父类是一种高度耦合,违反了面向对象的思想。

组合

组合就是在设计类的时候把需要用到的类作为成员变量加入到当前类中。

组合的优缺点:

优点:

  • 隐藏了被引用对象的内部细节
  • 降低了两个对象之间的耦合
  • 可以在运行时动态修改被引用对象的实例

缺点:

  • 系统变更可能需要不停的定义新的类
  • 系统结构变复杂,不再局限于单个类

建议多使用组合,少用继承

装饰者模式

装饰者模式指在不改变原类定义及继承关系的情况跟下,动态的拓展一个类的功能,就是利用创建一个包装类(wrapper)来装饰(decorator)一个已有的类。

包含角色:

被装饰者:

  • Component 抽象被装饰者,
  • ConcreteComponent 具体被装饰者,Component的实现,在装饰者模式中装饰的就是这货。

装饰者:

  • Decorator 装饰者 一般是一个抽象类并且作为Component的子类,Decorator必然会有一个成员变量用来存储Component的实例
  • ConcreateDecorator 具体装饰者 Decorator的实现

在装饰者模式中必然会有一个最基本,最核心,最原始的接口或抽象类充当component和decorator的抽象组件

实现要点:

  • 定义一个类或接口,并且让装饰者及被装饰者的都继承或实现这个类或接口
  • 装饰者中必须持有被装饰者的引用
  • 装饰者中对需要增强的方法进行增强,不需要增强的方法调用原来的业务逻辑
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
namespace Decorator
{
 
 /// <summary>
 /// Component 抽象者装饰者
 /// </summary>
 public interface IStudent
 {
  void Learn();
 }
 
 /// <summary>
 /// ConcreteComponent 具体被装饰者
 /// </summary>
 public class Student : IStudent
 {
  private string _name;
  public Student(string name)
  {
   this._name = name;
  }
  public void Learn()
  {
   System.Console.WriteLine(this._name + "学习了以上内容");
  }
 }
 /// <summary>
 /// Decorator 装饰者
 /// </summary>
 public abstract class Teacher : IStudent
 {
  private IStudent _student;
  public Teacher(IStudent student)
  {
   this._student = student;
  }
  public virtual void Learn()
  {
   this.Rest();
   this._student.Learn();
  }
 
  public virtual void Rest()
  {
   Console.WriteLine("课间休息");
  }
 }
 
 /// <summary>
 /// ConcreteDecorator 具体装饰者
 /// </summary>
 public class MathTeacher : Teacher
 {
  private String _course;
  public MathTeacher(IStudent student, string course) : base(student)
  {
   this._course = course;
  }
  public override void Learn()
  {
   System.Console.WriteLine("学习新内容:" + this._course);
   base.Learn();
  }
  public override void Rest()
  {
   System.Console.WriteLine("课间不休息,开始考试");
  }
 }
 
 /// <summary>
 /// ConcreteDecorator 具体装饰者
 /// </summary>
 public class EnlishTeacher : Teacher
 {
  private String _course;
  public EnlishTeacher(IStudent student, string course) : base(student)
  {
   this._course = course;
  }
 
  public override void Learn()
  {
   this.Review();
   System.Console.WriteLine("学习新内容:" + this._course);
   base.Learn();
  }
 
  public void Review()
  {
   System.Console.WriteLine("复习英文单词");
  }
 }
 
 public class Program
 {
  static void Main(string[] args)
  {
   IStudent student = new Student("student");
   student = new MathTeacher(student, "高数");
   student = new EnlishTeacher(student, "英语");
   student.Learn();
  }
 }
}

装饰者模式优缺点:

优点:

  • 装饰者与被装饰者可以独立发展,不会互相耦合
  • 可以作为继承关系的替代方案,在运行时动态拓展类的功能
  • 通过使用不同的装饰者类或不同的装饰者排序,可以得到各种不同的结果

缺点:

  • 产生很多装饰者类
  • 多层装饰复杂

代理模式

代理模式就是给一个对象提供一个代理对象,并且由代理控制原对象的引用。

包含角色:

  • 抽象角色:抽象角色是代理角色和被代理角色的所共同继承或实现的抽象类或接口
  • 代理角色:代理角色是持有被代理角色引用的类,代理角色可以在执行被代理角色的操作时附加自己的操作
  • 被代理角色:被代理角色是代理角色所代理的对象,是真实要操作的对象

静态代理

动态代理涉及到反射技术相对静态代理会复杂很多,掌握好动态代理对AOP技术有很大帮助

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
namespace Proxy
{
 /// <summary>
 /// 共同抽象角色
 /// </summary>
 public interface IBuyHouse
 {
  void Buy();
 }
 
 /// <summary>
 /// 真实买房人,被代理角色
 /// </summary>
 public class Customer : IBuyHouse
 {
  public void Buy()
  {
   System.Console.WriteLine("买房子");
  }
 }
 
 /// <summary>
 /// 中介-代理角色
 /// </summary>
 public class CustomerProxy : IBuyHouse
 {
  private IBuyHouse target;
  public CustomerProxy(IBuyHouse buyHouse)
  {
   this.target = buyHouse;
  }
  public void Buy()
  {
   System.Console.WriteLine("筛选符合条件的房源");
   this.target.Buy();
  }
 }
 
 public class Program
 {
  static void Main(string[] args)
  {
   IBuyHouse buyHouse = new CustomerProxy(new Customer());
   buyHouse.Buy();
   System.Console.ReadKey();
  }
 }
}

动态代理

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
namespace DynamicProxy
{
 using Microsoft.Extensions.DependencyInjection;
 using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Linq.Expressions;
 using System.Reflection;
 
 /// <summary>
 /// 方法拦截器接口
 /// </summary>
 public interface IMethodInterceptor
 {
  /// <summary>
  /// 调用拦截器
  /// </summary>
  /// <param name="targetMethod">拦截的目标方法</param>
  /// <param name="args">拦截的目标方法参数列表</param>
  /// <returns>拦截的目标方法返回值</returns>
  object Interceptor(MethodInfo targetMethod, object[] args);
 }
 
 /// <summary>
 /// 代理类生成器
 /// </summary>
 public class ProxyFactory : DispatchProxy
 {
  private IMethodInterceptor _interceptor;
 
  /// <summary>
  /// 创建代理类实例
  /// </summary>
  /// <param name="targetType">要代理的接口</param>
  /// <param name="interceptor">拦截器</param>
  /// <returns></returns>
  public static object CreateInstance(Type targetType, IMethodInterceptor interceptor)
  {
   object proxy = GetProxy(targetType);
   ((ProxyFactory)proxy).GetInterceptor(interceptor);
   return proxy;
  }
 
  /// <summary>
  /// 创建代理类实例
  /// </summary>
  /// <param name="targetType">要代理的接口</param>
  /// <param name="interceptorType">拦截器</param>
  /// <param name="parameters">拦截器构造函数参数值</param>
  /// <returns>代理实例</returns>
  public static object CreateInstance(Type targetType, Type interceptorType, params object[] parameters)
  {
   object proxy = GetProxy(targetType);
   ((ProxyFactory)proxy).GetInterceptor(interceptorType, parameters);
   return proxy;
  }
 
 
  /// <summary>
  /// 创建代理类实例
  /// </summary>
  /// <typeparam name="TTarget">要代理的接口</typeparam>
  /// <typeparam name="TInterceptor">拦截器</typeparam>
  /// <param name="parameters">拦截器构造函数参数值</param>
  /// <returns></returns>
  public static TTarget CreateInstance<TTarget, TInterceptor>(params object[] parameters) where TInterceptor : IMethodInterceptor
  {
   object proxy = GetProxy(typeof(TTarget));
   ((ProxyFactory)proxy).GetInterceptor(typeof(TInterceptor), parameters);
   return (TTarget)proxy;
  }
 
  /// <summary>
  /// 获取代理类
  /// </summary>
  /// <param name="targetType"></param>
  /// <returns></returns>
  private static object GetProxy(Type targetType)
  {
   MethodCallExpression callexp = Expression.Call(typeof(DispatchProxy), nameof(DispatchProxy.Create), new[] { targetType, typeof(ProxyFactory) });
   return Expression.Lambda<Func<object>>(callexp).Compile()();
  }
 
  /// <summary>
  /// 获取拦截器
  /// </summary>
  /// <param name="interceptorType"></param>
  /// <param name="parameters"></param>
  private void GetInterceptor(Type interceptorType, object[] parameters)
  {
   Type[] ctorParams = parameters.Select(x => x.GetType()).ToArray();
   IEnumerable<ConstantExpression> paramsExp = parameters.Select(x => Expression.Constant(x));
   NewExpression newExp = Expression.New(interceptorType.GetConstructor(ctorParams), paramsExp);
   this._interceptor = Expression.Lambda<Func<IMethodInterceptor>>(newExp).Compile()();
  }
 
  /// <summary>
  /// 获取拦截器
  /// </summary>
  /// <param name="interceptor"></param>
  private void GetInterceptor(IMethodInterceptor interceptor)
  {
   this._interceptor = interceptor;
  }
 
  /// <summary>
  /// 执行代理方法
  /// </summary>
  /// <param name="targetMethod"></param>
  /// <param name="args"></param>
  /// <returns></returns>
  protected override object Invoke(MethodInfo targetMethod, object[] args)
  {
   return this._interceptor.Interceptor(targetMethod, args);
  }
 }
 
 /// <summary>
 /// 表演者
 /// </summary>
 public interface IPerform
 {
  /// <summary>
  /// 唱歌
  /// </summary>
  void Sing();
 
  /// <summary>
  /// 跳舞
  /// </summary>
  void Dance();
 }
 
 /// <summary>
 /// 具体的表演者——刘德华 Andy
 /// </summary>
 public class AndyPerformer : IPerform
 {
  public void Dance()
  {
   System.Console.WriteLine("给大家表演一个舞蹈");
  }
 
  public void Sing()
  {
   System.Console.WriteLine("给大家唱首歌");
  }
 }
 
 /// <summary>
 /// 经纪人——负责演员的所有活动
 /// </summary>
 public class PerformAgent : IMethodInterceptor
 {
  public IPerform _perform;
  public PerformAgent(IPerform perform)
  {
   this._perform = perform;
  }
  public object Interceptor(MethodInfo targetMethod, object[] args)
  {
   System.Console.WriteLine("各位大佬,要我们家艺人演出清闲联系我");
   object result = targetMethod.Invoke(this._perform, args);
   System.Console.WriteLine("各位大佬,表演结束该付钱了");
   return result;
  }
 }
 
 public class Program
 {
  static void Main(string[] args)
  {
   IPerform perform;
 
   //perform = ProxyFactory.CreateInstance<IPerform, PerformAgent>(new AndyPerformer());
   //perform.Sing();
   //perform.Dance();
 
   ServiceCollection serviceDescriptors = new ServiceCollection();
   serviceDescriptors.AddSingleton<IPerform>(ProxyFactory.CreateInstance<IPerform, PerformAgent>(new AndyPerformer()));
   IServiceProvider serviceProvider = serviceDescriptors.BuildServiceProvider();
   perform = serviceProvider.GetService<IPerform>();
   perform.Sing();
   perform.Dance();
 
   System.Console.ReadKey();
  }
 }
 
}

总结

  • 使用拓展方法只能拓展新增方法,不能增强已有的功能
  • 使用继承类或接口,类只能单继承,并且在父类改变后,所有的子类都要跟着变动
  • 使用代理模式与继承一样代理对象和真实对象之间的的关系在编译时就确定了
  • 使用装饰者模式能够在运行时动态地增强类的功能

参考引用

利用.NET Core类库System.Reflection.DispatchProxy实现简易Aop

好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对服务器之家的支持。

原文链接:http://www.cnblogs.com/AlvinLee/p/10180536.html

延伸 · 阅读

精彩推荐
  • C#浅谈C# winForm 窗体闪烁的问题

    浅谈C# winForm 窗体闪烁的问题

    下面小编就为大家带来一篇浅谈C# winForm 窗体闪烁的问题。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧...

    C#教程网7962021-12-21
  • C#c#学习之30分钟学会XAML

    c#学习之30分钟学会XAML

    一个界面程序的核心,无疑就是界面和后台代码,而xaml就是微软为构建应用程序界面而创建的一种描述性语言,也就是说,这东西是搞界面的...

    C#教程网8812021-12-10
  • C#C#基础之泛型

    C#基础之泛型

    泛型是 2.0 版 C# 语言和公共语言运行库 (CLR) 中的一个新功能。接下来通过本文给大家介绍c#基础之泛型,感兴趣的朋友一起学习吧...

    方小白7732021-12-03
  • C#Unity3D UGUI实现缩放循环拖动卡牌展示效果

    Unity3D UGUI实现缩放循环拖动卡牌展示效果

    这篇文章主要为大家详细介绍了Unity3D UGUI实现缩放循环拖动展示卡牌效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参...

    诗远3662022-03-11
  • C#聊一聊C#接口问题 新手速来围观

    聊一聊C#接口问题 新手速来围观

    聊一聊C#接口问题,新手速来围观,一个通俗易懂的例子帮助大家更好的理解C#接口问题,感兴趣的小伙伴们可以参考一下...

    zenkey7072021-12-03
  • C#C#直线的最小二乘法线性回归运算实例

    C#直线的最小二乘法线性回归运算实例

    这篇文章主要介绍了C#直线的最小二乘法线性回归运算方法,实例分析了给定一组点,用最小二乘法进行线性回归运算的实现技巧,具有一定参考借鉴价值,需要...

    北风其凉8912021-10-18
  • C#C# 后台处理图片的几种方法

    C# 后台处理图片的几种方法

    本篇文章主要介绍了C# 后台处理图片的几种方法,非常具有实用价值,需要的朋友可以参考下。...

    IT小伙儿10162021-12-08
  • C#C#实现的文件操作封装类完整实例【删除,移动,复制,重命名】

    C#实现的文件操作封装类完整实例【删除,移动,复制,重命名】

    这篇文章主要介绍了C#实现的文件操作封装类,结合完整实例形式分析了C#封装文件的删除,移动,复制,重命名等操作相关实现技巧,需要的朋友可以参考下...

    Rising_Sun3892021-12-28