C# 依赖注入 & MEF
之前面试有问道依赖注入,因为一直是做客户端的发开发,没有接触这个,后边工作接触到了MEF,顺便熟悉一下依赖注入
详细的概念解释就不讲了,网上一大把,个人觉着依赖注入本质是为了解耦,方便扩展
依赖注入的方式:属性注入和构造函数注入,还有接口注入的,看了下跟属性注入差不多·就不展示了
上代码:
public interface ICalc
{
double Calc(double a, double b);
} public class AddCalc:ICalc
{ public double Calc(double a, double b)
{
return a + b;
}
}
public class SubtractCalc:ICalc
{
public double Calc(double a, double b)
{
return a - b;
}
} public class MyClac { ICalc _calc; //属性注入
public ICalc Calc {
get {
return _calc;
}
set {
_calc = value;
}
} //构造函数注入
public MyClac(ICalc calc)
{
_calc = calc;
} public double Calculate(double a, double b)
{
return _calc.Calc(a, b);
}
}
(DI )依赖注入是实现(IOC)控制反转的一种方式,但是使用的时候,比如再扩展的时候还是需要修改调用代码,所以就有了IOC 容器来方便这个调用
.NET 下边 MEF框架就是干这个的, 本质是通过特性和反射在运行的时候程序集动态加载。
//接口声明 //最终调用过程接口
public interface ICalculator
{
string Calculate(String input);
}
//过程中操作接口
[InheritedExport]//这里特性标识子类会被导出,后边子类可以不用表示export导出特性
public interface IOperation
{
int Operate(int left, int right);
}
//这里定义导出操作名称,可以用来在导出的操作中进行筛选识别,这个接口不用实现
public interface IOperationData
{
string Symbol { get; }
}
上边是接口声明,下边实现这些接口
[Export(typeof(IOperation))]
[ExportMetadata("Symbol", '+')]
public class Add : IOperation
{
public int Operate(int left, int right)
{
return left + right;
}
}
[Export(typeof(IOperation))]
[ExportMetadata("Symbol", '-')]
public class Subtract : IOperation
{ public int Operate(int left, int right)
{
return left - right;
}
}
[Export(typeof(IOperation))]
[ExportMetadata("Symbol",'/')]
public class Except : IOperation
{
public int Operate(int left, int right)
{
return left / right;
}
} [Export(typeof(ICalculator))]
class MyCalculator : ICalculator
{ [ImportMany(AllowRecomposition = true)]
IEnumerable<Lazy<IOperation, IOperationData>> operations; public string Calculate(string input)
{
int left;
int right;
char operation;
int fn = FindFirstNonDigit(input); //finds the operator
if (fn < ) return "Could not parse command."; try
{
//separate out the operands
left = int.Parse(input.Substring(, fn));
right = int.Parse(input.Substring(fn + ));
}
catch
{
return "Could not parse command.";
} operation = input[fn]; foreach (Lazy<IOperation, IOperationData> i in operations)
{ if (i.Metadata.Symbol.Equals( operation))
return i.Value.Operate(left, right).ToString();
}
return "Operation Not Found!";
} private int FindFirstNonDigit(String s)
{ for (int i = ; i < s.Length; i++)
{
if (!(Char.IsDigit(s[i])))
return i;
}
return -;
}
}
这里因为加了exportmetadata特性,所以继承类要加上export特性,不然MEF 好像不识别,如果没有exportmetadata,只需要在接口上边加上inheritedExport特性就可以了· MEF会自动导入导出的
这里是导出,下边看怎么导入使用
private CompositionContainer _container; //这个是容器
[Import(typeof(ICalculator))]
public ICalculator calculator; //这个导入的类
private Program()
{
var catalog = new AggregateCatalog();
catalog.Catalogs.Add(new AssemblyCatalog(typeof(Program).Assembly));//这里直接导入本程序集内的类
catalog.Catalogs.Add(new DirectoryCatalog("Extensions", "MEF_Ex.dll"));//这里导入指定目录下的DLL,可以设置筛选项或者不设置,把目录下所有的dll全部导入
_container = new CompositionContainer(catalog);
try
{
this._container.ComposeParts(this);
}
catch (CompositionException ex)
{
Console.WriteLine(ex.ToString());
}
}
这里MEF_Ex.dll是另外一个项目,生成的程序集,放到主程序目录下Extensions目录下即可
实现了一个类:
[Export(typeof(IOperation))]
[ExportMetadata("Symbol", '%')]
public class Mod : MEF_Interface.IOperation
{
public int Operate(int left, int right)
{
return left % right;
}
}
在main函数中直接new program即可调用calc的方法
Program pro = new Program();
Console.WriteLine(pro.calculator.Calculate("1-2"));
还可以单独导出类的方法和属性,以及通过metadata筛选导入的类
完整代码如下:
[InheritedExport]
interface IBookService
{
string BookName { get; set; }
string GetBookName();
} // [Export("MusicBook",typeof(IBookService))]
class MusicBook : IBookService
{
public string BookName { get; set; } [Export(typeof(string))]
public string _publicBookName = "publicBookName";
[Export(typeof(string))]
private string _privateBookName = "privateBookName"; public string GetBookName()
{
return "MusicBook";
} } // [Export("MusicBook", typeof(IBookService))]
class MathBook : IBookService
{
public string BookName { get; set; } [Export(typeof(Func<string>))]
public string GetBookName()
{
return "MathBook";
} [Export(typeof(Func<int,string>))]
private string privateGetName(int count)
{
return $"get {count} MathBook"; } } // [Export("MusicBook", typeof(IBookService))]
class HistoryBook : IBookService
{
public string BookName { get; set; } public string GetBookName()
{
return "HistoryBook";
} }
[InheritedExport]
public interface IPlugin
{
string Caption { get; }
void Do();
}
public interface IPluginMark
{
string Mark { get; }
} [Export(typeof(IPlugin))]
[ExportMetadata("Mark", "Plugin1")]
public class Plugin1 : IPlugin
{
public string Caption { get { return "Plugin1"; } }
public void Do()
{
Console.WriteLine("Plugin1 do");
}
}
[Export(typeof(IPlugin))]
[ExportMetadata("Mark", "Plugin2")]
public class Plugin2 : IPlugin
{
public string Caption { get { return "Plugin2"; } }
public void Do()
{
Console.WriteLine("Plugin2 do");
}
}
[Export(typeof(IPlugin))]
[ExportMetadata("Mark", "Plugin2")]
public class Plugin3 : IPlugin
{
public string Caption { get { return "Plugin3"; } }
public void Do()
{
Console.WriteLine("Plugin3 do");
}
} #endregion class Program
{
#region
[ImportMany]
public IEnumerable<IBookService> Services { get; set; }//导入类 [ImportMany]
public List<string> InputString { get; set; }//导入属性 [Import]
public Func<string> methodWithoutPara { get; set; }//导入方法
[Import]
public Func<int, string> methodWithPara { get; set; }//导入方法 [ImportMany]
public IEnumerable< Lazy<IPlugin, IPluginMark>> Plugins { get; set; } #endregion private CompositionContainer _container; [Import(typeof(ICalculator))]
public ICalculator calculator; private Program()
{ var catalog = new AggregateCatalog();
catalog.Catalogs.Add(new AssemblyCatalog(typeof(Program).Assembly));//导出本程序集
catalog.Catalogs.Add(new DirectoryCatalog("Extensions", "MEF_Ex.dll"));//通过文件导入
_container = new CompositionContainer(catalog); try
{
this._container.ComposeParts(this); }
catch (CompositionException ex)
{
Console.WriteLine(ex.ToString());
} } static void Main(string[] args)
{
Program pro = new Program();
Console.WriteLine(pro.calculator.Calculate("1-2")); var plugins = pro.Plugins;//.Where(v => v.Metadata.Mark == "Plugin2").ToList();//这里可以做筛选 foreach (var p in plugins)
{
p.Value.Do();
} if (pro.Services != null)
{
foreach (var service in pro.Services)
{
Console.WriteLine(service.GetBookName());
} foreach (var str in pro.InputString)
{
Console.WriteLine(str);
} //调用无参数的方法
if (pro.methodWithoutPara != null)
{
Console.WriteLine(pro.methodWithoutPara());
} //调用有参数的方法
if (pro.methodWithPara != null)
{
Console.WriteLine(pro.methodWithPara());
} }
Console.ReadLine(); } }
总结:
1 MEF会自动导入对应的类实现,然后自动初始化,但是具体什么时候初始化以及导入,这里要注意类的初始化方法 以及是不是有可能多线程的问题以及有依赖
2 导入程序集的方式可以直接导入程序集或者通过文件,看了反编译的代码以及.netcore的源码,底层是使用load 以及loadfrom的方法来时间加载程序集的,所以这玩意理论上应该实现不了热插拔把·
3 关于.net实现热插拔,网上有很多玩法,之前有看过通过appdomain 来实现,也就是应用程序域,实现略复杂这里没研究,也可以通过load的方式重新加载程序集·但是这些理论上应该做不到所谓的热插拔吧,起码程序要重启把···
4 之前有面试问MEF 怎么实现热插拔,直接懵逼了,我是搞清楚。后来想了下,可以换一个方式实现,在MEF基础上实现AOP,通过aop实现权限控制,拦截某些操作,或者MEF 加载的时候过滤加载项,这些算热插拔么···
C# 依赖注入 & MEF的更多相关文章
- Asp.Net Mvc3.0(MEF依赖注入实例)
前言 在http://www.cnblogs.com/aehyok/p/3386650.html前面一节主要是对MEF进行简单的介绍.本节主要来介绍如何在Asp.Net Mvc3.0中使用MEF. 准 ...
- Asp.Net Mvc3.0(MEF依赖注入理论)
前言 Managed Extensibility Framework(MEF)是.NET平台下的一个扩展性管理框架,它是一系列特性的集合,包括依赖注入(DI)等.MEF为开发人员提供了一个工具,让我们 ...
- 基于DDD的.NET开发框架 - ABP依赖注入
返回ABP系列 ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)”的简称. ASP.NET Boilerplate是一个用最佳实践和流行技术开发现代WEB应 ...
- TypeC一个微软开发的超简单.NET依赖注入/IoC容器
控制反转(IoC,Inversion of Control)是由Martin Fowler总结出来的一种设计模式,用来减少代码间的耦合.一般而言,控制反转分为依赖注入(Dependency Injec ...
- ASP.NET 5:依赖注入
ASP.NET 5:依赖注入 1.背景 如果某个具体的(或类)对象被客户程序所依赖,通常把它们抽象成抽象类或接口.简单说,客户程序摆脱所依赖的具体类型,称之为面向接口编程. 那么问题来了?如何选择客户 ...
- [.net 面向对象程序设计深入](26)实战设计模式——使用Ioc模式(控制反转或依赖注入)实现松散耦合设计(1)
[.net 面向对象程序设计深入](26)实战设计模式——使用IoC模式(控制反转或依赖注入)实现松散耦合设计(1) 1,关于IOC模式 先看一些名词含义: IOC: Inversion of con ...
- [.net 面向对象程序设计深入](31)实战设计模式——使用Ioc模式(控制反转或依赖注入)实现松散耦合设计(1)
[.net 面向对象程序设计深入](31)实战设计模式——使用IoC模式(控制反转或依赖注入)实现松散耦合设计(1) 1,关于IOC模式 先看一些名词含义: IOC: Inversion of con ...
- asp.net core 系列 3 依赖注入服务
一. 依赖注入概述 在软件设计的通用原则中,SOLID是非常流行的缩略语,它由5个设计原则的首字母构成:单一原则(S).开放封闭原则(O).里氏替换原则(L).接口分离原则(I).依赖反转原则(D). ...
- 007.ASP.NET MVC控制器依赖注入
原文链接:http://www.codeproject.com/Articles/560798/ASP-NET-MVC-Controller-Dependency-Injection-for-Be 前 ...
随机推荐
- 使用GridFsTemplate在Mongo中存取文件
Maven依赖(还有一些springboot需要的) <parent> <groupId>org.springframework.boot</groupId> ...
- VisualStudio2012轻松把JSON数据转换到POCO的代码(转)
VisualStudio2012轻松把JSON数据转换到POCO的代码 在Visual Studio 2012中轻松把JSON数据转换到POCO的代码,首先你需要安装Web Essentials 20 ...
- 决策树与树集成模型(bootstrap, 决策树(信息熵,信息增益, 信息增益率, 基尼系数),回归树, Bagging, 随机森林, Boosting, Adaboost, GBDT, XGboost)
1.bootstrap 在原始数据的范围内作有放回的再抽样M个, 样本容量仍为n,原始数据中每个观察单位每次被抽到的概率相等, 为1/n , 所得样本称为Bootstrap样本.于是可得到参数θ的 ...
- linux img文件 分区挂载
首先是将制作的img文件比如hd5.img和loop设备建立联系. losetup /dev/loop0 hd5.img 然后用fdisk分区:fdisk /dev/loop0 mkfs.ext4 / ...
- Java Web 从入门到精通(明日科技)
目录结构: 第一章:Java Web 应用开发概述 第二章:html与css网页开发基础 第三章:JavaScript脚本语言 第四章:搭建开发环境 第五章:JSP语言基础 第六章:JSP内置对象 第 ...
- filebeat 笔记
认识Beats Beats是用于单用途数据托运人的平台.它们以轻量级代理的形式安装,并将来自成百上千台机器的数据发送到Logstash或Elasticsearch. (画外音:通俗地理解,就是采集数据 ...
- Python divmod() 函数
Python divmod() 函数 Python 内置函数 python divmod() 函数把除数和余数运算结果结合起来,返回一个包含商和余数的元组(a // b, a % b). 在 pyt ...
- leetcode 21 Merge Two Sorted Lists 合并两个有序链表
描述: 合并两个有序链表. 解决: ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) { if (!l1) return l2; if (!l2) ...
- 链表求和12 · Add Two Numbers
反向存储,从左往右加 [抄题]: 你有两个用链表代表的整数,其中每个节点包含一个数字.数字存储按照在原来整数中相反的顺序,使得第一个数字位于链表的开头.写出一个函数将两个整数相加,用链表形式返回和.给 ...
- curl模拟多线程抓取网页(优化)
通过上篇文章清楚了通过curl_multi_*函数可以一次请求多个url,但是也留下了问题,就是结果要等所有数据请求结束一起返回,才能逐个处理数据.优化代码,使先成功请求的url先返回处理结果,而不是 ...