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
通常被认为相当慢,但它有它的用途。