声明与类I don'的C#接口的一致性;t拥有

声明与类I don'的C#接口的一致性;t拥有,c#,interface,C#,Interface,假设我在第三方库中处理多个类,所有这些类都包含intid{get;}属性。例如: class A { ... int ID {get;} ... } class B { ... int ID {get;} ... } ID是我正在编写的方法中唯一需要使用的属性,该方法需要引用a或B。我声明了一个接口: interface IHasID { int ID {get;} } 但是调用我的方法时,我不能将A或B视为IHasID 例如,在Sw

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

不,目前没有这样做的方法。你可以:

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

有可能在某个时候将此功能添加到C#。有关详细信息,请参见Mads Torgersen’s,但我怀疑这还有很长的路要走。

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

public void MyMethod<T>(T value, Func<T, int> selectId)
{
    var id = selectId(value);
}
请注意,尽管它们看起来相同,但两个lambda并不相同


Func
vs
Func

如果您想编写适配器作为解决方案,这是我将类型加入层次结构的典型实现

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
转换为
hasidapter
,但这可以通过将
hasidapter
作为方法参数来实现,或者将
A
B
实例分配给
hasidapter
类型的变量,然后再将其传递给
IHasID
方法

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

  • IHasID
    接口的实现
  • 使用
    T
    Func
    获取ID的构造函数,以及
  • 包装值的getter
以下是一个例子:

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;
    }
}
类HasId:IHasId{
私有只读函数idGetter;
公共值{get;}
public Id=>idGetter(值);
公共HasId(T val,Func idGetter){
价值=价值;
this.idGetter=idGetter;
}
}
另一个(并非最佳)解决方案是使用反射:

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

我真的不喜欢这个解决方案,但我还是加入了它,因为它是一个选项…

为什么不让你的方法重载呢?我想到的第一件事是围绕
a
B
创建一个包装类,就像
IHasID
的适配器一样。你甚至可以有一个类,每个类型都有一个方法,并使用方法组转换,让类型推断处理它:
Foo(newa(),IdExtractor.ExtractId);Foo(新的B(),IdExtractor.ExtractId)您可以展开您的评论吗?我不确定
ExtractId
是什么类型。它将是
IdExtractor
类中的一组重载方法,例如
public int-ExtractId(A){…}public int-ExtractId(B){…}
等。
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;
    }
}
static int IdOf<T>(T t)
{
    return (int)typeof(T).GetProperty("ID").GetValue(t);
}