如何 'sneak' 接口在第 3 方对象后面

How to 'sneak' interface behind 3rd party objects

我正在与 C#.NET 4.5 合作。
我有 2 个对象(实际上更多,但为了简单起见,让我们坚持使用两个),它们是独立的实体,并且都来自第三方库,但是它们确实没有什么共同的属性。

我想做一个可以处理这些属性的抽象机制。如果这些对象是我的,我可以通过添加 interface

轻松完成
class Foo : IFooBar
{
    public string A { get; set; }
    public string B { get; set; }
}

class Bar : IFooBar
{
    public string A { get; set; }
    public string B { get; set; }
}

interface IFooBar
{
    string A { get; set; }
    string B { get; set; }
}

public static class Extensions
{
    public static IFooBar ProcessedFoobars(IFooBar fooBar)
    {
    ...(do things to A and B)
    }
}

然而,由于它们来自第 3 方,我没有(不知道)将它们放在界面后面的方法。

我看到 ATM 的选项:

  1. FooBar 转换为我的内部对象 MyFooMyBar 放置 MyFooMyBar 在界面后面并以这种方式处理它们

  2. 使用仅接受属性作为输入的方法。

    Tuple<string, string> DoThings(string A, string B)
    {
    ...(do things to A and B)
    }
    

这将涉及来自各种类型的第 3 方对象的大量映射。

  1. 目前我倾向于使用反射

    public T FooBarProcessor<T>(T fooBar)
    {
        var type = typeof (T);
        var propertyA = type.GetProperty("A");
        var propertyB = type.GetProperty("B");
        var a = propertyA.GetValue(fooBar, null);
        var b = propertyB.GetValue(fooBar, null);
        ... (do things to A and B)
        propertyA.SetValue(fooBar, a);
        propertyB.SetValue(fooBar, b);
        return fooBar;
    }
    

有没有办法 'sneak' 在第 3 方对象后面进行接口(或其他一些解决方法),让我可以让多个对象看起来好像在接口后面,所以我可以以同样的方式处理它们。

是什么让我希望可以做到这一点 - PostSharp 确实允许 'Aspect Inheritance'(我自己没有尝试过,所以可能有所不同) 在付费版本中,如果他们以某种方式这样做 - 那么就可以做到。

你需要的是adapter pattern.

您可以创建 类 实现您的界面并在后台使用 Foo & Bar:

interface IFooBar
{
    string A { get; set; }
    string B { get; set; }
}

class FooAdapter : IFooBar
{
    private readonly Foo _foo;

    public FooAdapter(Foo foo)
    {
        _foo = foo;
    }

    public string A
    {
        get { return _foo.A; }
        set { _foo.A = value; }
    }

    public string B
    {
        get { return _foo.B; }
        set { _foo.B = value; }
    }
}


class BarAdapter : IFooBar
{
    private readonly Bar _bar;

    public BarAdapter(Bar bar)
    {
        _bar = bar;
    }

    public string A
    {
        get { return _bar.A; }
        set { _bar.A = value; }
    }

    public string B
    {
        get { return _bar.B; }
        set { _bar.B = value; }
    }
}

如果您想要正确或最常见的解决方案,您应该遵循

我的解决方案提供了一种更快的解决问题的方法,但如果要长期使用,则不建议这样做。

当我理解你的问题正确时,你可以尝试使用接受动态对象作为参数的方法。

public static void ChangeCommonProperties(dynamic thirdPartyObject){
  thirdPartyObject.A = "Hello";
  thirdPartyObject.B = "World";
}

ChangeCommonProperties(new Foo());
ChangeCommonProperties(new Bar());

只要传入的对象具有属性并且 属性 类型正确,这就没有问题。否则你会得到一个 RuntimeBinderException 详细说明出了什么问题。

感谢@Jehof,我最终使用了略微修改的解决方案。

public T ProcessFooBars<T>(dynamic anything) 
{ 
    return (T) ChangeCommonProperties(anything); 
}

public dynamic ChangeCommonProperties(dynamic thirdPartyObject)
{
    thirdPartyObject.A = "Hello";
    thirdPartyObject.B = "World";
}

希望这能为您节省一些时间。