是否可以使用 C# 实现早期绑定接口和后期绑定实现
Is an early bound interface and a late bound implementation possible with C#
我正在尝试创建本质上是项目的插件框架。我正在尝试在全面开发之前解决这些问题,但我 运行 遇到了问题。我正在构建一个消息处理器。消息的来源决定了消息的处理方式。由于无论消息来自哪里,检索消息和发送消息都是一样的,我觉得插件框架将是一个很好的实现方式。
我构建了一个接口,所有实现都可以针对该接口构建。
IIPInterfaces.cs:
using System;
using System.Xml;
namespace IIPInterfaces
{
public interface IInterfaceProcessor
{
IIPResult ProcessRequest(XmlDocument xdoc, String processType);
}
public class IIPResult
{
public XmlDocument ResponseDocument { get; set;}
Boolean IsSuccessful { get; set; }
String Error { get; set; }
}
}
我为接口创建了一个实现来测试它。
原型IIP
using IIPInterfaces;
using System;
using System.Xml;
namespace PrototypeIIP
{
public class IIPImplimentation : IInterfaceProcessor
{
public IIPResult ProcessRequest(XmlDocument xdoc, String requestType)
{
IIPResult result = new IIPResult();
Console.WriteLine("In interface {0}", requestType);
return result;
}
}
}
然后我在运行的时候创建了一个测试工程尝试绑定实现文件然后使用接口
控制台程序
using IIPInterfaces;
using System;
using System.IO;
using System.Reflection;
using System.Xml;
namespace LateBindingPrototype
{
class Program
{
static void Main(string[] args)
{
String filePath = "C:\XMLConfig\PrototypeIIP.dll";
// Try to load a copy of PrototypeIIP
Assembly a = null;
try
{ a = Assembly.LoadFrom(filePath); }
catch(FileNotFoundException e)
{
Console.WriteLine(e.Message);
Console.ReadKey();
return;
}
if (a != null)
{ CreateUsingLateBinding(a); }
Console.ReadKey();
InvokeProcessMessage(a);
Console.ReadKey();
}
static void InvokeProcessMessage(Assembly asm)
{
try
{
Type processor = asm.GetType("PrototypeIIP.IIPImplimentation");
IInterfaceProcessor myProcessor = Activator.CreateInstance(processor) as IInterfaceProcessor;
XmlDocument xdoc = new XmlDocument();
myProcessor.ProcessRequest(xdoc, "test");
}
catch (Exception e)
{
Console.WriteLine(e.Message);
Console.ReadKey();
}
}
static void CreateUsingLateBinding(Assembly asm)
{
try
{
Type processor = asm.GetType("PrototypeIIP.IIPImplimentation");
object obj = Activator.CreateInstance(processor);
Console.WriteLine("Created a {0} using late finding!", obj);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
Console.ReadKey();
}
}
}
}
CreateUsingLateBinding 方法工作正常,但是当我尝试在 InvokeProcessMessage 方法中的 IInterfaceProcessor 实例中创建该对象时,该对象为空。
我想做的事情可行吗?我知道我可以通过绕过接口并直接从实现 dll 调用方法来做到这一点,但我希望让代码比这更干净,因为我们开发组中的其他人需要支持这一点,而且越简单越好其中一些。
谢谢!
对您描述的问题最明显的解释是,您在声明实现接口的类型时在 DLL 中使用的接口类型 IInterfaceProcessor
与接口类型不同(也命名为 IInterfaceProcessor
) 尝试创建实例时在程序中使用。
即Activator.CreateInstance()
实际上 returns 是一个非空引用(它总是会,除非抛出异常),但该类型没有实现您尝试使用 [=13 将其转换为的接口=]运算符。
我见过这种情况发生的最常见原因是在某个 .cs 文件中声明了一个类型,而不是将该 .cs 文件编译成单个 DLL 并通过该 DLL 引用该类型,该文件是链接到两个或多个项目中,分别编译到每个项目中。这会产生一个新类型,每个程序集一个,当然这些类型是不兼容的。
当然,缺少 a good, complete code example 我不能肯定地说这实际上是您代码中的问题。这只是一个有根据的猜测。
综上所述,对于您似乎要尝试做的事情类型,使用 Managed Extensibility Framework 可能更好。它提供了一个有用的 API 来构建这种功能。
除此之外,我假设您程序中的硬编码类型名称仅用于测试目的。当然,对于真正的插件架构,您可能希望简单地枚举程序集中的所有类型,寻找实现您感兴趣的接口的类型。
在 Peter 做出回应后,我返回并尝试更具体一些。
在PrototypeIIP.cs
public class IIPImplimentation : IInterfaceProcessor
到
public class IIPImplimentation : IIPInterfaces.IInterfaceProcessor
并且在控制台程序中
IInterfaceProcessor myProcessor = Activator.CreateInstance(processor) as IInterfaceProcessor;
到
IIPInterfaces.IInterfaceProcessor myProcessor = Activator.CreateInstance(processor) as IIPInterfaces.IInterfaceProcessor;
它纠正了这个问题。我不确定为什么将它们视为两种不同的类型,但确实如此。
谢谢彼得。
我正在尝试创建本质上是项目的插件框架。我正在尝试在全面开发之前解决这些问题,但我 运行 遇到了问题。我正在构建一个消息处理器。消息的来源决定了消息的处理方式。由于无论消息来自哪里,检索消息和发送消息都是一样的,我觉得插件框架将是一个很好的实现方式。
我构建了一个接口,所有实现都可以针对该接口构建。
IIPInterfaces.cs:
using System;
using System.Xml;
namespace IIPInterfaces
{
public interface IInterfaceProcessor
{
IIPResult ProcessRequest(XmlDocument xdoc, String processType);
}
public class IIPResult
{
public XmlDocument ResponseDocument { get; set;}
Boolean IsSuccessful { get; set; }
String Error { get; set; }
}
}
我为接口创建了一个实现来测试它。
原型IIP
using IIPInterfaces;
using System;
using System.Xml;
namespace PrototypeIIP
{
public class IIPImplimentation : IInterfaceProcessor
{
public IIPResult ProcessRequest(XmlDocument xdoc, String requestType)
{
IIPResult result = new IIPResult();
Console.WriteLine("In interface {0}", requestType);
return result;
}
}
}
然后我在运行的时候创建了一个测试工程尝试绑定实现文件然后使用接口
控制台程序
using IIPInterfaces;
using System;
using System.IO;
using System.Reflection;
using System.Xml;
namespace LateBindingPrototype
{
class Program
{
static void Main(string[] args)
{
String filePath = "C:\XMLConfig\PrototypeIIP.dll";
// Try to load a copy of PrototypeIIP
Assembly a = null;
try
{ a = Assembly.LoadFrom(filePath); }
catch(FileNotFoundException e)
{
Console.WriteLine(e.Message);
Console.ReadKey();
return;
}
if (a != null)
{ CreateUsingLateBinding(a); }
Console.ReadKey();
InvokeProcessMessage(a);
Console.ReadKey();
}
static void InvokeProcessMessage(Assembly asm)
{
try
{
Type processor = asm.GetType("PrototypeIIP.IIPImplimentation");
IInterfaceProcessor myProcessor = Activator.CreateInstance(processor) as IInterfaceProcessor;
XmlDocument xdoc = new XmlDocument();
myProcessor.ProcessRequest(xdoc, "test");
}
catch (Exception e)
{
Console.WriteLine(e.Message);
Console.ReadKey();
}
}
static void CreateUsingLateBinding(Assembly asm)
{
try
{
Type processor = asm.GetType("PrototypeIIP.IIPImplimentation");
object obj = Activator.CreateInstance(processor);
Console.WriteLine("Created a {0} using late finding!", obj);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
Console.ReadKey();
}
}
}
}
CreateUsingLateBinding 方法工作正常,但是当我尝试在 InvokeProcessMessage 方法中的 IInterfaceProcessor 实例中创建该对象时,该对象为空。
我想做的事情可行吗?我知道我可以通过绕过接口并直接从实现 dll 调用方法来做到这一点,但我希望让代码比这更干净,因为我们开发组中的其他人需要支持这一点,而且越简单越好其中一些。
谢谢!
对您描述的问题最明显的解释是,您在声明实现接口的类型时在 DLL 中使用的接口类型 IInterfaceProcessor
与接口类型不同(也命名为 IInterfaceProcessor
) 尝试创建实例时在程序中使用。
即Activator.CreateInstance()
实际上 returns 是一个非空引用(它总是会,除非抛出异常),但该类型没有实现您尝试使用 [=13 将其转换为的接口=]运算符。
我见过这种情况发生的最常见原因是在某个 .cs 文件中声明了一个类型,而不是将该 .cs 文件编译成单个 DLL 并通过该 DLL 引用该类型,该文件是链接到两个或多个项目中,分别编译到每个项目中。这会产生一个新类型,每个程序集一个,当然这些类型是不兼容的。
当然,缺少 a good, complete code example 我不能肯定地说这实际上是您代码中的问题。这只是一个有根据的猜测。
综上所述,对于您似乎要尝试做的事情类型,使用 Managed Extensibility Framework 可能更好。它提供了一个有用的 API 来构建这种功能。
除此之外,我假设您程序中的硬编码类型名称仅用于测试目的。当然,对于真正的插件架构,您可能希望简单地枚举程序集中的所有类型,寻找实现您感兴趣的接口的类型。
在 Peter 做出回应后,我返回并尝试更具体一些。
在PrototypeIIP.cs
public class IIPImplimentation : IInterfaceProcessor
到
public class IIPImplimentation : IIPInterfaces.IInterfaceProcessor
并且在控制台程序中
IInterfaceProcessor myProcessor = Activator.CreateInstance(processor) as IInterfaceProcessor;
到
IIPInterfaces.IInterfaceProcessor myProcessor = Activator.CreateInstance(processor) as IIPInterfaces.IInterfaceProcessor;
它纠正了这个问题。我不确定为什么将它们视为两种不同的类型,但确实如此。
谢谢彼得。