【问题标题】:Is an early bound interface and a late bound implementation possible with C#是否可以使用 C# 实现早期绑定接口和后期绑定实现
【发布时间】:2015-02-04 00:52:04
【问题描述】:

我正在尝试为项目创建本质上是插件框架的东西。我正在尝试在全面开发之前解决这些问题,但我遇到了问题。我正在构建一个消息处理器。消息的来源决定了应该如何处理消息。因为无论消息来自哪里,获取消息和发送消息都是一样的,所以我觉得插件框架是实现这一点的好方法。

我构建了一个可以构建所有实现的接口。

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 调用方法来做到这一点,但我希望保持代码比这更干净,因为我们开发组中的其他人将需要支持这一点,并且在涉及到时越简单越好其中一些。

谢谢!

【问题讨论】:

  • 基本上你想要 IoC(控制反转)。看看 Unity (msdn.microsoft.com/en-us/library/ff647202.aspx) 或 MEF (msdn.microsoft.com/en-us/magazine/ee291628.aspx)。
  • 我认为您在这里尝试的内容没有明显错误。但是,我目前没有运行 VS,所以希望其他人会介入并查明您的错误。
  • 您在哪里定义了接口,您是否使用相同的参考程序集在实现 dll 和运行您的示例代码的程序中定义接口文件。 (如果你有A.dll和B.exe是IInterfaceProcessor在A和B中定义,只是B,或者A和B都有引用的C.dll)
  • 运行您的代码并从这两种方法创建实例都没有问题,我看到的唯一问题是ProcessRequest 的返回类型在您的界面中是string,但IIPResult在您的实施中。
  • Prestion - 两者都是 IIPResult。字符串来自于思考一件事并输入另一件事。

标签: c# reflection interface


【解决方案1】:

对您描述的问题最明显的解释是,您在声明实现该接口的类型时在 DLL 中使用的接口类型 IInterfaceProcessor 与您在您的尝试创建实例时的程序。

Activator.CreateInstance() 实际上返回一个非空引用(它总是会返回,除非抛出异常),但该类型没有实现您尝试使用 as 运算符将其转换为的接口。

我看到发生这种情况的最常见原因是在某个 .cs 文件中声明了一个类型,但不是将该 .cs 文件编译为单个 DLL 并通过该 DLL 引用该类型,而是将该文件链接到两个或多个项目,分别编译到每个项目中。这会产生一个新类型,每个程序集一个,当然这些类型是不兼容的。

当然,缺少a good, complete code example 我不能肯定这实际上是您代码中的问题。这只是一个有根据的猜测。


综上所述,对于您似乎想要做的事情,最好使用Managed Extensibility Framework。它提供了一个有用的 API,可在此基础上构建此类功能。

除此之外,我假设您程序中的硬编码类型名称仅用于测试目的。当然,对于真正的插件架构,您可能希望简单地枚举程序集中的所有类型,寻找那些实现您感兴趣的接口的类型。

【讨论】:

  • 虽然我不确定我发布的内容如何缺乏完整性,但我已经在我的帖子中添加了一些以前没有的 using 语句和文件名。这是三个独立的项目。实现项目(PrototypeIIP)和控制台项目都引用了接口项目(IInterfaceProcessor.dll)。是的,硬编码类型名称仅用于测试。我只是想先把基本结构弄下来。
【解决方案2】:

在彼得做出回应后,我回去尝试更具体一点。

在 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;

它纠正了问题。我不确定为什么将它们视为两种不同的类型,但确实如此。

谢谢彼得。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-05-11
    • 2016-12-15
    • 1970-01-01
    • 2011-08-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多