每个人都在说使用MEF。就是这样。现在,对于我的生活,我无法弄清楚如何使用它。
我下载了一个示例项目:
public interface ICalculator
{
String Calculate(String input);
}
public interface IOperation
{
int Operate(int left, int right);
}
public interface IOperationData
{
Char Symbol { get; }
}
[Export(typeof(IOperation))]
[ExportMetadata("Symbol", '+')]
class Add : IOperation
{
public int Operate(int left, int right)
{
return left + right;
}
}
[Export(typeof(IOperation))]
[ExportMetadata("Symbol", '-')]
class Subtract : IOperation
{
public int Operate(int left, int right)
{
return left - right;
}
}
[Export(typeof(ICalculator))]
class MySimpleCalculator : ICalculator
{
[ImportMany]
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 < 0) return "Could not parse command.";
try
{
//separate out the operands
left = int.Parse(input.Substring(0, fn));
right = int.Parse(input.Substring(fn + 1));
}
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 = 0; i < s.Length; i++)
{
if (!(Char.IsDigit(s[i]))) return i;
}
return -1;
}
}
class Program
{
private CompositionContainer _container;
[Import(typeof(ICalculator))]
public ICalculator calculator;
private Program()
{
//An aggregate catalog that combines multiple catalogs
var catalog = new AggregateCatalog();
//Adds all the parts found in the same assembly as the Program class
catalog.Catalogs.Add(new AssemblyCatalog(typeof(Program).Assembly));
catalog.Catalogs.Add(new DirectoryCatalog(@"C:\Users\Lee Yi\Desktop\Everything, for the moment\Coding\Simple Calculator MEF Application\C#\SimpleCalculator3\Extensions"));
//Create the CompositionContainer with the parts in the catalog
_container = new CompositionContainer(catalog);
//Fill the imports of this object
try
{
this._container.ComposeParts(this);
}
catch (CompositionException compositionException)
{
Console.WriteLine(compositionException.ToString());
}
}
static void Main(string[] args)
{
Program p = new Program(); //Composition is performed in the constructor
String s;
Console.WriteLine("Enter Command:");
while (true)
{
s = Console.ReadLine();
Console.WriteLine(p.calculator.Calculate(s));
}
}
}
我不明白的是,所有这些都是在同一个文件中定义的。那我怎么能改变像
这样的不同代码元素呢? [Export(typeof(IOperation))]
[ExportMetadata("Symbol", '+')]
class Add : IOperation
{
public int Operate(int left, int right)
{
return left + right;
}
}
以另一个.dll为例?
就我而言,我在System.Windows.Forms.Button类中使用此功能,我有类似这样的内容:
class SpeakButton : Button
{
public SpeakButton()
{ //Constructor that adds the speech handler automatically
this.Click += new EventHandler(Speak_Button);
}
private void Speak_Button(object sender, EventArgs e)
{
Speaking.Speak((sender as Button).Text);
}
}
但是我想让Speaking.Speak()
函数(它实际上调用SpeechSynthesizer的SpeakAsync函数)是可选的,可以作为单独的.dll文件安装吗?
任何人都可以解释我将如何做这件事吗?
Speaking类定义如下:
class Speaking
{
//Private fields (Hiding implementation code)
private static SpeechSynthesizer Speaker = new SpeechSynthesizer();
private static State state = State.Disabled;
//Public properties
public static int Volume
{
get { return Speaker.Volume; }
set { Speaker.Volume = value; }
}
public static int Rate
{
get { return Speaker.Rate; }
set { Speaker.Rate = value; }
}
public static State Speech
{
get { return state; }
set { state = value; }
}
public static VoiceGender Gender
{
get { return Speaker.Voice.Gender; }
set { Speaker.SelectVoiceByHints(value); }
}
public enum State { Enabled = 1, Disabled = 0 };
public static void Speak(object message)
{ //Say stuff
if (state == State.Disabled) { return; }
Speaker.SpeakAsync(message.ToString());
}
public static void Cancel() { Speaker.SpeakAsyncCancelAll(); }
}
答案 0 :(得分:0)
MEF无法正常使用静态类,因此我无法评论您的特定用例。如果要将代码迁移到另一个DLL以获得插件体系结构,则可以使用三个不同的程序集,即主EXE,包含插件接口的程序集和插件程序集。主要EXE和插件程序集引用插件接口程序集。例如:
主要EXE
static class Program
{
static void Main()
{
Controller win = new Controller();
win.ListPlugins();
}
}
public class Controller
{
[System.ComponentModel.Composition.ImportMany]
IEnumerable<Lazy<Interface.IPlugin>> plugins;
System.ComponentModel.Composition.Hosting.CompositionContainer compContainer;
public Controller()
{
var catalog = GetMefCatalogs();
this.compContainer = new System.ComponentModel.Composition.Hosting.CompositionContainer(catalog);
try
{
System.ComponentModel.Composition.AttributedModelServices.ComposeParts(this.compContainer, this);
}
catch (System.Reflection.ReflectionTypeLoadException ex)
{
foreach (Exception inner in ex.LoaderExceptions)
{
Console.WriteLine("Reflection error: {0}", inner.Message);
}
}
catch (System.ComponentModel.Composition.CompositionException ex)
{
Console.WriteLine(ex.ToString());
}
}
public void ListPlugins()
{
foreach (var pv in this.plugins)
{
Console.WriteLine(pv.Value.Name);
}
}
public static System.ComponentModel.Composition.Hosting.AggregateCatalog GetMefCatalogs()
{
var catalog = new System.ComponentModel.Composition.Hosting.AggregateCatalog();
// You should probably use these two lines, or the following lines, but not both. If you use
// this option you will need to ensure that the libs are all in the same directory.
catalog.Catalogs.Add(new System.ComponentModel.Composition.Hosting.DirectoryCatalog(System.IO.Path.GetDirectoryName(System.AppDomain.CurrentDomain.BaseDirectory), "*.dll"));
catalog.Catalogs.Add(new System.ComponentModel.Composition.Hosting.DirectoryCatalog(System.IO.Path.GetDirectoryName(System.AppDomain.CurrentDomain.BaseDirectory), "*.exe"));
//foreach (var assembly in System.AppDomain.CurrentDomain.GetAssemblies())
//{
// if (!assembly.FullName.StartsWith("System", StringComparison.OrdinalIgnoreCase) &&
// !assembly.FullName.StartsWith("Microsoft", StringComparison.OrdinalIgnoreCase) &&
// !assembly.FullName.StartsWith("mscorlib", StringComparison.OrdinalIgnoreCase) &&
// !assembly.FullName.StartsWith("Accessibility", StringComparison.OrdinalIgnoreCase) &&
// !assembly.FullName.StartsWith("vshost32", StringComparison.OrdinalIgnoreCase))
// {
// Console.WriteLine("Found assembly: " + assembly.FullName);
// catalog.Catalogs.Add(new System.ComponentModel.Composition.Hosting.AssemblyCatalog(assembly));
// }
//}
return catalog;
}
}
界面装配
public interface IPlugin
{
string Name { get; }
double GetRandom();
}
插件程序集
[System.ComponentModel.Composition.Export(typeof(Interface.IPlugin))]
public class Plugin : Interface.IPlugin
{
private Random random;
public Plugin()
{
this.random = new Random(DateTime.Now.Ticks.GetHashCode());
}
public string Name
{
get { return "Plugin"; }
}
public double GetRandom()
{
return this.random.NextDouble() * 10;
}
}
当然,您需要在插件和主EXE程序集(但不是插件程序集)中添加对System.ComponentModel.Composition的引用才能使用MEF。