之前面试有问道依赖注入,因为一直是做客户端的发开发,没有接触这个,后边工作接触到了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的更多相关文章

  1. Asp.Net Mvc3.0(MEF依赖注入实例)

    前言 在http://www.cnblogs.com/aehyok/p/3386650.html前面一节主要是对MEF进行简单的介绍.本节主要来介绍如何在Asp.Net Mvc3.0中使用MEF. 准 ...

  2. Asp.Net Mvc3.0(MEF依赖注入理论)

    前言 Managed Extensibility Framework(MEF)是.NET平台下的一个扩展性管理框架,它是一系列特性的集合,包括依赖注入(DI)等.MEF为开发人员提供了一个工具,让我们 ...

  3. 基于DDD的.NET开发框架 - ABP依赖注入

    返回ABP系列 ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)”的简称. ASP.NET Boilerplate是一个用最佳实践和流行技术开发现代WEB应 ...

  4. TypeC一个微软开发的超简单.NET依赖注入/IoC容器

    控制反转(IoC,Inversion of Control)是由Martin Fowler总结出来的一种设计模式,用来减少代码间的耦合.一般而言,控制反转分为依赖注入(Dependency Injec ...

  5. ASP.NET 5:依赖注入

    ASP.NET 5:依赖注入 1.背景 如果某个具体的(或类)对象被客户程序所依赖,通常把它们抽象成抽象类或接口.简单说,客户程序摆脱所依赖的具体类型,称之为面向接口编程. 那么问题来了?如何选择客户 ...

  6. [.net 面向对象程序设计深入](26)实战设计模式——使用Ioc模式(控制反转或依赖注入)实现松散耦合设计(1)

    [.net 面向对象程序设计深入](26)实战设计模式——使用IoC模式(控制反转或依赖注入)实现松散耦合设计(1) 1,关于IOC模式 先看一些名词含义: IOC: Inversion of con ...

  7. [.net 面向对象程序设计深入](31)实战设计模式——使用Ioc模式(控制反转或依赖注入)实现松散耦合设计(1)

    [.net 面向对象程序设计深入](31)实战设计模式——使用IoC模式(控制反转或依赖注入)实现松散耦合设计(1) 1,关于IOC模式 先看一些名词含义: IOC: Inversion of con ...

  8. asp.net core 系列 3 依赖注入服务

    一. 依赖注入概述 在软件设计的通用原则中,SOLID是非常流行的缩略语,它由5个设计原则的首字母构成:单一原则(S).开放封闭原则(O).里氏替换原则(L).接口分离原则(I).依赖反转原则(D). ...

  9. 007.ASP.NET MVC控制器依赖注入

    原文链接:http://www.codeproject.com/Articles/560798/ASP-NET-MVC-Controller-Dependency-Injection-for-Be 前 ...

随机推荐

  1. [maven] 实战笔记 - maven 安装配置

    1.下载地址http://maven.apache.org/download.html 2.windows下安装maven(1)下载 apache-maven-3.0-bin.zip 解压到任意目录下 ...

  2. Introduction to Spring Data MongoDB

    Introduction to Spring Data MongoDB I just announced the new Spring 5 modules in REST With Spring: & ...

  3. 实现一个最简单的plot函数调用:

    实现一个最简单的plot函数调用: 1 import matplotlib.pyplot as plt 2 3 y=pp.DS.Transac_open # 设置y轴数据,以数组形式提供 4 5 x= ...

  4. selenium+python在mac环境上的搭建

    前言 mac自带了python2.7的环境,所以在mac上安装selenium环境是非常简单的,输入2个指令就能安装好 需要安装的软件: 1.pip 2.selenium2.53.6 3.Firefo ...

  5. upstream prematurely closed connection while reading response header from upstream

    upstream prematurely closed connection while reading response header from upstream nginx配置uwsgi的时候  ...

  6. JAVA 操作Excel工具类

    Bean转Excel对象 /* * 文件名:BeanToExcel.java */ import java.util.ArrayList; import java.util.List; import ...

  7. clientX,offsetX,screenX,pageX 区别!

    先总结下区别: event.clientX.event.clientY 鼠标相对于浏览器窗口可视区域的X,Y坐标(窗口坐标),可视区域不包括工具栏和滚动条.IE事件和标准事件都定义了这2个属性 eve ...

  8. query简洁弹出层代码

    <!DOCTYPE HTML><html><head><meta http-equiv="Content-Type" content=&q ...

  9. JavaWeb--过滤器Filter (二)

    上一小节简单介绍了过滤器的概念和基本结构以及新建过滤器的步骤,本节使用过滤器设计一个小案例 -- 使用过滤器统一处理Post方式下参数值中文乱码的问题. 1.分析 对于有汉字信息处理的Servlet或 ...

  10. oracle 导入导出指定表

    导出 exp username/password@127.0.0.1/orcl file=D:\xxx.dmp tables(tablename,tablename) 导入 imp username/ ...