C# 不带公共基类的泛型的访问属性

C# 不带公共基类的泛型的访问属性,c#,generics,C#,Generics,我有两个独立的类库,它们没有相同的基类,我也不能更改这些类的实现 想象一下这些类是这样的: public class A { public int X { get; } = 1; } public class B { public int X { get; } = 2; } 现在我想创建一个泛型类,它要么依赖于a要么依赖于B并访问其中的X值 所以我做了: public class GenericClass<T> /*where T : ?*/ {

我有两个独立的类库,它们没有相同的基类,我也不能更改这些类的实现

想象一下这些类是这样的:

public class A {
     public int X { get; } = 1;
}

public class B {
     public int X { get; } = 2;
}
现在我想创建一个泛型类,它要么依赖于
a
要么依赖于
B
并访问其中的
X

所以我做了:

public class GenericClass<T> 
    /*where T : ?*/
{
    void Foo(T t) {
        int x = t.X; // is this possible and how? 
    }
}
公共类GenericClass
/*T:在哪里*/
{
void Foo(T){
int x=t.x;//这可能吗?如何可能?
}
}
如果我自己实现
A
B
,我会定义一个接口来实现属性
X
,但我不能这样做。在不改变类别
A
B
的情况下,是否有其他方法可以说泛型
T
具有属性
X


另一个想法是创建
A
B
的子类,然后实现上述接口,但我想避免这种情况。

您可以重载
Foo
以获取
A
B

void Foo(A t)
{
  int x = t.X;
}

void Foo(B t)
{
  int x = t.X;
}
如果您想为每个可能具有
X
属性的类执行此操作,那么您需要一个基于反射的解决方案。例如:

void Foo(object obj)
{
  var property = obj.GetType().GetProperty("X");
  if(property == null) throw new Exception();

  int x = (int)property.GetValue(obj);
}
interface IMyStuff
{
  int X{get;}
}

class MyA : A, IMyStuff
{
}

class MyB : B, IMyStuff
{
}
注意:我已经最小化了这里的错误处理。您需要处理属性可能没有getter(罕见)或不返回
int

如果类的数量是可管理的,那么您可以使用属性创建一个接口,派生一个新类并实现该接口,而不需要进行更改。例如:

void Foo(object obj)
{
  var property = obj.GetType().GetProperty("X");
  if(property == null) throw new Exception();

  int x = (int)property.GetValue(obj);
}
interface IMyStuff
{
  int X{get;}
}

class MyA : A, IMyStuff
{
}

class MyB : B, IMyStuff
{
}
不是,您可以让Foo接受接口:

void Foo(IMyStuff stuff)
{
  int x = stuff.X
}

另一个选项是使用
dynamic

dynamic d;
d = t;         // here t can be an instance of A, or or B, or of anything that has X
int x = d.X;

dynamic
基本上实现了“duck typing”:如果
dynamic
对象
g
具有属性
X
,则
g.X
将检索该属性。这是手动实现反射的一种替代方法。

我正要发布几乎相同的答案:-)+1。但我必须为每一个可能的类都这样做。Foo在我能通过的每门课上都保持不变(现在)。我的例子很糟糕。我有时会创建模板的实例,too@RoQuOTriX“但我必须为每一个可能的类都这样做。”这是明确地将问题限制在两个(或更多)类之间没有设置任何共享祖先的问题上的结果。为了可重用,您需要定义这些类的共同点。@Flater我同意您的看法,但如果我可以说泛型必须具有共同的属性,例如在我的where语句中,这是我通常使用接口来实现的,但有时我不能。现在,我要么对我的库的每个类进行子类化,并创建一个公共基类,要么使用基于反射的解决方案来实现这样一个“简单的”problem@RoQuOTriX:前提(不改变现有的类)总是会导致你方付出额外的(不太理想的)努力。不过你可以把这些类包装起来。这至少允许您将问题包含到现有库中,并在代码中提供更干净的解决方案。如果X未实现,会发生什么?它仍将正确编译,但会导致运行时异常:
Microsoft.CSharp.RuntimeBinder.RuntimeBinderException:“t”不包含“X”的定义。
。我会让您的答案正确,因为它“解决”了我的问题。我知道这不是一个好的解决方案,因为异常的危险性等等。好吧,我们必须保护和捕获这些异常,并适当地处理它们。还要注意的是,
dynamic
通常被认为相当慢,但它有它的用途。