为我不拥有的类声明对C#接口的一致性

时间:2018-06-19 16:46:35

标签: c# interface

比方说,我正在第三方库中使用多个类,所有这些类都包含一个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#做到这一点的方法。引用共享属性的不相关类的最近方法是什么?

5 个答案:

答案 0 :(得分:6)

否,目前无法执行此操作。您可以:

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

可能有时会将此功能添加到C#中。有关详细信息,请参见Mads Torgersen的issue about shapes-但我认为这还有很长的路要走。

答案 1 :(得分: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>Func<B, int>

答案 2 :(得分: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;
    }
}

答案 3 :(得分: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方法。

答案 4 :(得分:0)

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

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

我不太喜欢这种解决方案,但是无论如何我都将其包括在内,因为它是一种选择...