比方说,我正在第三方库中使用多个类,所有这些类都包含一个int ID {get;}
属性。例如:
class A {
...
int ID {get;}
...
}
class B {
...
int ID {get;}
...
}
ID
是我正在编写的方法中需要使用的唯一属性,该方法需要引用A或B。我已声明一个接口:
interface IHasID
{
int ID {get;}
}
但是在调用我的方法时,我无法将A
或B
都视为IHasID
。
例如,在Swift中,我可以声明一个符合“协议”(Swift的接口版本)的扩展。我看不到用C#做到这一点的方法。引用共享属性的不相关类的最近方法是什么?
答案 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
接口的实现,T
和Func<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);
}
尽管这种方法可以解决问题,但是在使用该接口之前,您仍然需要将A
或B
转换为HasIDAdapter
,但这可以通过采取以下措施来实现HasIDAdapter
作为方法参数,或者通过将A
或B
实例分配给HasIDAdapter
类型的变量,然后再将其传递给IHasID
方法。
答案 4 :(得分:0)
另一种(不是那么理想)的解决方案是使用反射:
static int IdOf<T>(T t)
{
return (int)typeof(T).GetProperty("ID").GetValue(t);
}
我不太喜欢这种解决方案,但是无论如何我都将其包括在内,因为它是一种选择...