声明符合C#接口的类我不拥有

问题描述 投票:2回答:5

假设我正在使用第三方库中的多个类,所有这些类都包含int ID {get;}属性。例如:

class A {
    ...
    int ID {get;}
    ...
}

class B {
    ...
    int ID {get;}
    ...
}

ID是我需要在我正在编写的方法中使用的唯一属性,它需要引用A或B.我已经声明了一个接口:

interface IHasID
{
    int ID {get;}
}

但是在调用我的方法时,我无法将AB视为IHasID

例如,在Swift中,我可以声明一个符合“协议”(Swift的接口版本)的扩展。我没有看到用C#做到这一点的方法。引用共享属性的不相关类的最接近方式是什么?

c# interface
5个回答
6
投票

不,目前没办法做到这一点。你可以:

  • 只需使用动态类型并以这种方式使用ID,而无需在编译时进行类型检查
  • 在您自己的类中包装每个实现接口的库类
  • 要求维护者添加一个接口

此功能可能会在某个时间添加到C#中。有关细节,请参阅Mads Torgersen的issue about shapes - 但我怀疑它还有很长的路要走。


5
投票

您可以使用通用方法以及ID的选择器,而不是包装类。这里的用法很简单,但在某些情况下这种模式很有用。

public void MyMethod<T>(T value, Func<T, int> selectId)
{
    var id = selectId(value);
}

MyMethod<A>(a, value => value.ID);
MyMethod<B>(b, value => value.ID);

可以缩短为

MyMethod(a, value => value.ID);
MyMethod(b, value => value.ID);

请注意,即使它们看起来相同,但两个lambda不完全相同。

Func<A, int> vs Func<B, int>


1
投票

创建一个具有以下所有内容的通用包装类:

  • IHasID接口的实现,
  • 一个构造函数,它使用TFunc<T,int>来获取ID,以及
  • 包裹值的吸气剂。

这是一个例子:

class HasId<T> : IHasId {
    private readonly Func<T,int> idGetter;
    public Value {get;}
    public Id => idGetter(Value);
    public HasId(T val, Func<T,int> idGetter) {
        Value = value;
        this.idGetter = idGetter;
    }
}

0
投票

如果您想将编写适配器作为解决方案,那么这是将类型连接到层次结构中的典型实现。

public abstract class HasIDAdapter : IHasID {
    public abstract int ID {get;}

    private class AAdapter : HasIDAdapter {
        A _a;
        public AAdapter(A a) {
            _a = a;
        }

        public override int ID { get => _a.ID; }
    }

    private class BAdapter : HasIDAdapter {
        B _b;
        public BAdapter(B b) {
            _b = b;
        }

        public override int ID {get => _b.ID;}
    }

    public static implicit operator HasIDAdapter(A a) => new AAdapter(a);
    public static implicit operator HasIDAdapter(B b) => new BAdapter(b);
}

这种推动问题,你仍然需要在使用界面之前从AB转换为HasIDAdapter,但这可以通过将HasIDAdapter作为方法参数,或通过将AB实例分配给HasIDAdapter类型的变量在传递给IHasID方法之前。


0
投票

另一种(不那么优化)的解决方案是使用反射:

static int IdOf<T>(T t)
{
    return (int)typeof(T).GetProperty("ID").GetValue(t);
}

我真的不喜欢这个解决方案,但我还是把它包括在内,因为它是一个选择......

© www.soinside.com 2019 - 2024. All rights reserved.