SRP Single Responsibility Principle 单一职责原则(站在服务提供者的角度来看)
ISP Interface Segregation Principle 接口隔离原则(站在服务调用者的角度来看):把本质不同的接口隔离开,服务调用者不会多要。
胖接口ITank,违反了接口隔离原则
using System;
namespace ISP_InterfaceSegregationPrinciple_
{
class Program
{
static void Main(string[] args)
{
var driver = new Driver(new Car());
driver.Drive();
}
}
class Driver
{
private IVehicle _vehicle;
public Driver(IVehicle vehicle)
{
_vehicle = vehicle;
}
public void Drive()
{
_vehicle.Run();
}
}
interface IVehicle
{
void Run();
}
class Car : IVehicle
{
public void Run()
{
Console.WriteLine("Car is runnning");
}
}
class Truck : IVehicle
{
public void Run()
{
Console.WriteLine("Truck is runnning");
}
}
interface ITank //胖接口
{
void Fire(); //隶属于武器
void Run(); //隶属于机动车辆
}
class LightTank : ITank
{
public void Fire()
{
Console.WriteLine("Boom");
}
public void Run()
{
Console.WriteLine("Ka ka ka...");
}
}
class MediumTank : ITank
{
public void Fire()
{
Console.WriteLine("Medium Boom");
}
public void Run()
{
Console.WriteLine("Ka!ka! ka!...");
}
}
class HeavyTank : ITank
{
public void Fire()
{
Console.WriteLine("Heavy Boom");
}
public void Run()
{
Console.WriteLine("Ka!! ka!! ka!!...");
}
}
}
重构:实现多个基接口
using System;
namespace ISP_InterfaceSegregationPrinciple_
{
class Program
{
static void Main(string[] args)
{
var driver = new Driver(new HeavyTank());
driver.Drive();
}
}
class Driver
{
private IVehicle _vehicle;
public Driver(IVehicle vehicle)
{
_vehicle = vehicle;
}
public void Drive()
{
_vehicle.Run();
}
}
interface IVehicle
{
void Run();
}
class Car : IVehicle
{
public void Run()
{
Console.WriteLine("Car is runnning");
}
}
class Truck : IVehicle
{
public void Run()
{
Console.WriteLine("Truck is runnning");
}
}
interface IWeapon
{
void Fire();
}
interface ITank:IWeapon,IVehicle //胖接口
{
}
class LightTank : ITank
{
public void Fire()
{
Console.WriteLine("Boom");
}
public void Run()
{
Console.WriteLine("Ka ka ka...");
}
}
class MediumTank : ITank
{
public void Fire()
{
Console.WriteLine("Medium Boom");
}
public void Run()
{
Console.WriteLine("Ka!ka! ka!...");
}
}
class HeavyTank : ITank
{
public void Fire()
{
Console.WriteLine("Heavy Boom");
}
public void Run()
{
Console.WriteLine("Ka!! ka!! ka!!...");
}
}
}
1 显示接口实现
1.1 隐式实现
using System;
namespace IspExample
{
class Program
{
static void Main(string[] args)
{
var Albert = new WarmKiller();
Albert.Kill();
Albert.Love();//两个方法都能被看见,不符合现实世界中的逻辑
}
}
interface IGentleman
{
void Love();
}
interface IKiller
{
void Kill();
}
class WarmKiller : IGentleman,IKiller
{
public void Kill()
{
Console.WriteLine("Let me kill the enemy..");
}
public void Love()
{
Console.WriteLine("i will love you for ever..");
}
}
}
1.2 显示实现
using System;
namespace IspExample
{
class Program
{
static void Main(string[] args)
{
var Albert = new WarmKiller();
Albert.Love();//只能看见Love
IKiller killer = Albert;
killer.Kill();//只能看见Kill,两种方法:强制类型转换,as
var wk = (IGentleman)killer;
wk.Love();
}
}
interface IGentleman
{
void Love();
}
interface IKiller
{
void Kill();
}
class WarmKiller : IGentleman,IKiller
{
public void Love()
{
Console.WriteLine("i will love you for ever..");
}
void IKiller.Kill() //显示实现其接口
{
Console.WriteLine("Let me kill the enemy..");
}
}
}
2 反射(.Net框架特有的功能)Reflection与依赖注入
C#托管类型的语言
- 反射:以不变应万变(更松的耦合)
- 反射与接口的结合
- 反射与特性的结合
- 依赖注入:此DI非彼DI,但没有彼DI被没有此DI….
反射有什么用:程序的逻辑有时候不是我们写程序的时候能确定的,程序处于动态状态。以不变应万变的能力。
2.1 反射的原理以及与反射相关的重要技能依赖注入
.NETFramework和.NETCore 反射的API不同
反射的实现
using System;
using System.Reflection;
namespace ISP_InterfaceSegregationPrinciple_
{
class Program
{
static void Main(string[] args)
{
ITank tank = new HeavyTank();
// =========反射=========
var t = tank.GetType(); //获得类型信息
object o = Activator.CreateInstance(t);//激活创建一个实例,不通过new创建
MethodInfo fileMi = t.GetMethod("Fire");
MethodInfo runMi = t.GetMethod("Run"); //获得方法的信息
fileMi.Invoke(o, null);
runMi.Invoke(o, null);//方法必须依托一个实例,第二个值为函数的参数
}
}
class Driver
{
private IVehicle _vehicle;
public Driver(IVehicle vehicle)
{
_vehicle = vehicle;
}
public void Drive()
{
_vehicle.Run();
}
}
interface IVehicle
{
void Run();
}
class Car : IVehicle
{
public void Run()
{
Console.WriteLine("Car is runnning");
}
}
class Truck : IVehicle
{
public void Run()
{
Console.WriteLine("Truck is runnning");
}
}
interface IWeapon
{
void Fire();
}
interface ITank:IWeapon,IVehicle //胖接口
{
}
class LightTank : ITank
{
public void Fire()
{
Console.WriteLine("Boom");
}
public void Run()
{
Console.WriteLine("Ka ka ka...");
}
}
class MediumTank : ITank
{
public void Fire()
{
Console.WriteLine("Medium Boom");
}
public void Run()
{
Console.WriteLine("Ka!ka! ka!...");
}
}
class HeavyTank : ITank
{
public void Fire()
{
Console.WriteLine("Heavy Boom");
}
public void Run()
{
Console.WriteLine("Ka!! ka!! ka!!...");
}
}
}
依赖注入Dependency injection(DI)应用
借助依赖注入框架:NuGet Package Manager—Dependency injection—Microsoft.Extensions.DenpendencyInjection.
using System;
using System.Reflection;
using Microsoft.Extensions.DependencyInjection;
namespace ISP_InterfaceSegregationPrinciple_
{
class Program
{
static void Main(string[] args)
{
//容器,向容器要的时候new一个还是单例模式给同一个
var sc = new ServiceCollection();
sc.AddScoped(typeof(ITank), typeof(HeavyTank));//一对类型放进了容器
var sp = sc.BuildServiceProvider();
// ======== 华丽的分割线 =======
ITank tank = sp.GetService<ITank>();
tank.Fire();
tank.Run();
}
}
class Driver
{
private IVehicle _vehicle;
public Driver(IVehicle vehicle)
{
_vehicle = vehicle;
}
public void Drive()
{
_vehicle.Run();
}
}
interface IVehicle
{
void Run();
}
class Car : IVehicle
{
public void Run()
{
Console.WriteLine("Car is runnning");
}
}
class Truck : IVehicle
{
public void Run()
{
Console.WriteLine("Truck is runnning");
}
}
interface IWeapon
{
void Fire();
}
interface ITank:IWeapon,IVehicle //胖接口
{
}
class LightTank : ITank
{
public void Fire()
{
Console.WriteLine("Boom");
}
public void Run()
{
Console.WriteLine("Ka ka ka...");
}
}
class MediumTank : ITank
{
public void Fire()
{
Console.WriteLine("Medium Boom");
}
public void Run()
{
Console.WriteLine("Ka!ka! ka!...");
}
}
class HeavyTank : ITank
{
public void Fire()
{
Console.WriteLine("Heavy Boom");
}
public void Run()
{
Console.WriteLine("Ka!! ka!! ka!!...");
}
}
}
依赖链
注入到构造器中
using System;
using System.Reflection;
using Microsoft.Extensions.DependencyInjection;
namespace ISP_InterfaceSegregationPrinciple_
{
class Program
{
static void Main(string[] args)
{
//容器,向容器要的时候new一个还是单例模式给同一个
var sc = new ServiceCollection();
sc.AddScoped(typeof(ITank), typeof(HeavyTank));//一对类型放进了容器
sc.AddScoped(typeof(IVehicle), typeof(Car));//另一对类型放进了容器
sc.AddScoped<Driver>();//放一个Driver进入到容器中
var sp = sc.BuildServiceProvider();
// ======== 华丽的分割线 =======
ITank tank = sp.GetService<ITank>();
tank.Fire();
tank.Run();
var driver = sp.GetService<Driver>();//找是否有Driver这个实例,找到后继续查找
//是否有构造器里面需要的IVehicle,有,IVehicle绑定的是Car,则Driver驾驶Car
driver.Drive();//依赖链
}
}
class Driver
{
private IVehicle _vehicle;
public Driver(IVehicle vehicle)
{
_vehicle = vehicle;
}
public void Drive()
{
_vehicle.Run();
}
}
interface IVehicle
{
void Run();
}
class Car : IVehicle
{
public void Run()
{
Console.WriteLine("Car is runnning");
}
}
class Truck : IVehicle
{
public void Run()
{
Console.WriteLine("Truck is runnning");
}
}
interface IWeapon
{
void Fire();
}
interface ITank:IWeapon,IVehicle //胖接口
{
}
class LightTank : ITank
{
public void Fire()
{
Console.WriteLine("Boom");
}
public void Run()
{
Console.WriteLine("Ka ka ka...");
}
}
class MediumTank : ITank
{
public void Fire()
{
Console.WriteLine("Medium Boom");
}
public void Run()
{
Console.WriteLine("Ka!ka! ka!...");
}
}
class HeavyTank : ITank
{
public void Fire()
{
Console.WriteLine("Heavy Boom");
}
public void Run()
{
Console.WriteLine("Ka!! ka!! ka!!...");
}
}
}
反射—更松的耦合
更松的耦合一般应用在插件式编程。插件:不与主体程序一起编译,但可以与主体程序一起工作的组件,第三方来提供。以主体程序为中心,变成一个生态圈。
SDK里面的API来约束一下开发者,避免犯不必要的错误。
3 特性
特性是一种类,继承自Attribute,提供一些特殊的信息,本身并没有价值,只有在动态编程利用反射的时候才会体现出强大。
3.1 特性的简单使用
这里自定义了TestInfoAttribute特性,修饰了Student类,能够通过student实例通过反射获取到原数据。在编译过程中会有.custom的自定义实例产生,那一串01 00 06…就是“Albert”。不破坏封装,AOP面向切面编程。
namespace AttributeExample {
class Program {
static void Main(string[] args) {
Student student = new Student() { Age = 24, ID = 1 };
Type type = student.GetType();
if (type.IsDefined(typeof(TestInfoAttribute), true)) {
TestInfoAttribute testInfoAttribute =(TestInfoAttribute) type.GetCustomAttribute(typeof(TestInfoAttribute));
testInfoAttribute.PrintTestInfo();
}
}
}
[TestInfo("Albert")]
public class Student {
public int ID { get; set; }
public int Age { get; set; }
}
[AttributeUsage(AttributeTargets.Class)]
public class TestInfoAttribute : Attribute {
private string _testInfo;
public TestInfoAttribute(string testInfo) {
_testInfo = testInfo;
}
public void PrintTestInfo() {
Console.WriteLine(_testInfo);
}
}
}
3.2 Student转换为StudentDTO几种方式
首先是硬编码的方式效率是最高的,但是没办法做成通用的方法,代码后期可维护性和扩展性变低。选择低一点的版本使用,不然可能找不到一些常用的方法。
- Json序列化、反序列化
- AutoMapper 类映射
- 静态字典缓存+表达式目录树
- 泛型缓存+表达式目录树 ```csharp using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using AutoMapper; using System.Linq.Expressions; using DynamicExpresso; using Gremlin.Net.Process.Traversal;
namespace DTOExample {
class Program {
public static Dictionary
static void Main(string[] args) {
Student student = new Student() { Age = 24, ID = 1, Name = "Albert" };
//FirstMethod 使用Newtonsoft.Json序列号反序列化 此种方法效率很低
string sStudent = JsonConvert.SerializeObject(student); //先序列化为字符串
StudentDTO studentDTO = JsonConvert.DeserializeObject<StudentDTO>(sStudent);//反序列化
//SecondMethod 使用automapper映射 专属的类型映射工具,为ORM而生 效率高
Mapper.Initialize(x => x.CreateMap<Student, StudentDTO>());
StudentDTO studentDTO1 = Mapper.Map<Student, StudentDTO>(student);
//不同名称的映射
//Mapper.Initialize(config=> {
// config.CreateMap<Student, StudentDTO>().
// ForMember(dest => dest.DickName, options => options.MapFrom(sou => sou.Name));
//});
//StudentDTO studentDTO2 = Mapper.Map<Student, StudentDTO>(student);
//ThirdMethod 表达式目录树+静态缓存字典
//表达式目录树+静态字典
StudentDTO studentDTO3 = Trans<Student, StudentDTO>(student);
//效率较高,表达式目录树+泛型缓存
StudentDTO studentDTO4 = ExpressionGenericMapper<Student, StudentDTO>.Trans(student);
}
//表达式+静态字典
public static TOut Trans<TIn,TOut>(TIn tIn) {
TOut tOut = Activator.CreateInstance<TOut>();
string key = string.Format("funckey_{0}_{1}", tIn.GetType().Name, tOut.GetType().Name);
if (!_Dictionary.ContainsKey(key)) {
ParameterExpression parameterExpression = Expression.Parameter(typeof(TIn), "p");
List<MemberBinding> memberBindingsList = new List<MemberBinding>();
foreach (var item in typeof(TOut).GetProperties()) {
MemberExpression property = Expression.Property(parameterExpression, typeof(TIn).GetProperty(item.Name));
MemberBinding memberBinding = Expression.Bind(item, property);
memberBindingsList.Add(memberBinding);
}
foreach (var item in typeof(TOut).GetFields()) {
MemberExpression filed = Expression.Field(parameterExpression, typeof(TIn).GetField(item.Name));
MemberBinding memberBinding = Expression.Bind(item, filed);
memberBindingsList.Add(memberBinding);
}
MemberInitExpression memberInitExpression = Expression.MemberInit(Expression.New(typeof(TOut)), memberBindingsList.ToArray());
Expression<Func<TIn, TOut>> lambda = Expression.Lambda<Func<TIn, TOut>>(memberInitExpression, new ParameterExpression[]
{
parameterExpression
});
Func<TIn, TOut> func = lambda.Compile();
_Dictionary[key] = func;
}
return ((Func<TIn, TOut>)_Dictionary[key]).Invoke(tIn);
}
}
class Student {
public int ID { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public void PrintAge() {
Console.WriteLine(Age);
}
}
class StudentDTO {
public int ID { get; set; }
public string Name { get; set; }
//public string DickName { get; set; }
public int Age { get; set; }
public void PrintAge() {
Console.WriteLine(Age);
}
}
//表达式目录树+泛型缓存
public class ExpressionGenericMapper<TIn, TOut> {
private static Func<TIn, TOut> _FUNC = null;
static ExpressionGenericMapper() {
ParameterExpression parameterExpression = Expression.Parameter(typeof(TIn), "p");
List<MemberBinding> memberBindingsList = new List<MemberBinding>();
foreach (var item in typeof(TOut).GetProperties()) {
MemberExpression property = Expression.Property(parameterExpression, typeof(TIn).GetProperty(item.Name));
MemberBinding memberBinding = Expression.Bind(item, property);
memberBindingsList.Add(memberBinding);
}
foreach (var item in typeof(TOut).GetFields()) {
MemberExpression property = Expression.Field(parameterExpression, typeof(TIn).GetField(item.Name));
MemberBinding memberBinding = Expression.Bind(item, property);
memberBindingsList.Add(memberBinding);
}
MemberInitExpression memberInitExpression = Expression.MemberInit(Expression.New(typeof(TOut)), memberBindingsList.ToArray());
Expression<Func<TIn, TOut>> lambda = Expression.Lambda<Func<TIn, TOut>>(memberInitExpression, new ParameterExpression[]
{
parameterExpression
});
_FUNC = lambda.Compile();//拼装是一次性的
}
public static TOut Trans(TIn tIn) {
return _FUNC(tIn);
}
}
}
<a name="JreM5"></a>
## 3.3 BS/CS开发 信息校验特性应用
BS-用户提交信息-页面JS检查-提交到后端-后端还得校验一下,前端不可信-入库<br />CS-用户提交信息-后端校验-入库
```csharp
namespace ExtendMethod {
class Program {
static void Main(string[] args) {
int a = 5;
int result = a.CalcAdd(5, 5);
UserModel userModel = new UserModel();
userModel.Account = "dfa";
bool valid1 = userModel.Validate<UserModel>(); //扩展方法
bool valid2 = AttributeExtend.Validate<UserModel>(userModel);
Console.WriteLine(result);
Console.WriteLine(valid1);
Console.WriteLine(valid2);
}
//public static string GetName<T>(this T t) where T : MemberInfo {
// if (t.IsDefined(typeof(T), true)) {
// }
//}
}
public static class Calc {
public static int CalcAdd(this int a, int b, int c) {
return a + b + c;
}
}
public static class AttributeExtend {
//一个方法完成不同类型的数据校验--泛型方法
//得想办法知道,要检查的实体有啥属性,属性有啥规则
//可以检查全部属性、可以为多个类型服务
public static bool Validate<T>(this T input) {
Type type = typeof(T);
foreach (var item in type.GetProperties()) {
if (item.IsDefined(typeof(AttributeBase), true)) {
object oValue = item.GetValue(input);
object[] oAttributeArray = item.GetCustomAttributes(typeof(AttributeBase), true);
foreach (AttributeBase attribute in oAttributeArray) {
if (attribute.Validate(oValue)) {
return false;
}
}
}
}
//foreach (var item in type.GetProperties()) {
// if (item.IsDefined(typeof(ElevenRequiredAttribute), true)) {
// object oValue = item.GetValue(input);//从input实例中获取属性值
// ElevenRequiredAttribute el = (ElevenRequiredAttribute)item.GetCustomAttribute(typeof(ElevenLengthAttribute), true);
// if (el.Validate()) {
// Console.WriteLine("不合法");
// return false;
// }
// }
// if (item.IsDefined(typeof(ElevenLengthAttribute), true)) {
// object oValue = item.GetValue(input);//从input实例中获取属性值
// //可以获取属性item上特性的实例
// ElevenLengthAttribute el = (ElevenLengthAttribute)item.GetCustomAttribute(typeof(ElevenLengthAttribute), true);
// if (el.Validate()) {
// Console.WriteLine("长度不对");
// return false;
// }
// }
//}
return true;
}
}
public class UserModel {
public string ShortName { get; set; }
[ElevenRequired]
[ElevenLength(10, 20)]
public string Account { get; set; }
public string Password { get; set; }
public string Email { get; set; }
}
/// <summary>
/// 校验属性的基类
/// </summary>
public abstract class AttributeBase : Attribute {
public abstract bool Validate(object oValue);
}
/// <summary>
/// 非空特性
/// </summary>
public class ElevenRequiredAttribute : AttributeBase {
public override bool Validate(object oValue) {
if (oValue == null || string.IsNullOrWhiteSpace(oValue.ToString())) {
Console.WriteLine("为空");
return false;
}
else
return true;
}
}
public class ElevenLengthAttribute : AttributeBase {
private int _Min = 0;
private int _Max = 0;
public ElevenLengthAttribute(int min, int max) {
_Min = min;
_Max = max;
}
public override bool Validate(object oValue) {
if (oValue.ToString().Length <= _Min && oValue.ToString().Length >= _Max) {
Console.WriteLine("长度不对");
return false;
}
else
return true;
}
}
}