访问派生类中的字段

本文关键字:字段 派生 访问 | 更新日期: 2023-09-27 18:05:34

我正在通过用户界面动态创建一个节点列表。在我的列表中,我可以添加任意数量的对象(AAA, BBB等)到列表中,基于下面的类结构,通过反射实例化这些对象。

public abstract class Node : IDisposable
{ 
    protected int x;
}
public class AAA : Node
{ 
    public int iA;
}
public class BBB : Node
{ 
    public int iB;
}

创建List后,我想访问派生对象中的扩展字段。我知道我必须向下强制转换才能访问扩展字段,但为了做到这一点,目前我必须执行显式强制转换。

foreach (Node nn in MyList)                   //assume the first node in the list is AAA
{
    int m = ((namespace.AAA) nn).iA;          //this works
    int n = (AAA) nn).iA;                     //this works
}

我想知道我是否可以使用字符串来创建实际的向下转换。也许这是不可能的。也许我遗漏了什么。我想做的事情是行不通的,就像下面这样:

foreach (Node nn in MyList)       //assume the first node in the list is AAA
{
    Type t2 = nn.GetType();       //{Name = AAA; FullName = namespace.AAA} (*debugger*)
    string str = t2.FullName;     //namespace.AAA
    int m = ((str) nn).iA;         //this DOESN'T work
}

当我在调试器中查看nn的值时,FullName代表我想用于向下转换的类。

我可以通过使用基于表示类的字符串和强制转换语句中的硬代码的switch语句来解决这个问题,但是因为我有超过100个不同的节点,并且我将在将来添加更多的节点,所以每次添加节点时我都必须修改switch语句。这是我尽可能不愿意做的事。

提前感谢您的回复。

感谢Douglas指出我可以使用FieldInfo来获取iA的值。我只是想在这个话题上再扩展一点。如果我想使用类AAA并通过组合扩展它,我是否也能够通过FieldInfo访问这些类中的字段?

public class AAA : Node
{ 
    public int iA;
    public X[] XArray;   //where X is some other random class with pubic fields
    public Y[] YArray;   //where Y is some other abstract class
 }

访问派生类中的字段

你所做的似乎是你设计中某个错误想法的产物。

在你的类中没有iA和iB,为什么基本节点没有一个你在AAA或BBB的构造函数中设置的名为iNodeImplementation的属性?那么你就不需要做这些花哨的类型转换了。

我有一种感觉,你试图太可爱,错过了一些基本的好原则。考虑如何重构你的类,使你的代码更简单。

不讨论这个是否应该的优点,这里有一些示例代码,展示了如何使用反射来完成:

Type aaaType = Type.GetType("namespace.AAA");
FieldInfo iAField = aaaType.GetField("iA", BindingFlags.Public | 
                                           BindingFlags.Instance);
int m = (int)iAField.GetValue(nn);

为什么不尝试在Node类中设置抽象属性,然后在AAA和BBB中实现呢?

public abstract class Node : IDisposable
{ 
    protected int x;
    public abstract int i;
}
public class AAA : Node
{ 
    public override int i;
}
public class BBB : Node
{ 
    public override int i;
}

然后像这样使用foreach:

foreach (Node nn in MyList)       
{
    int m = nn.i;         
}

对我来说,这是你的对象设计的问题,而不是c#的问题。

你有很多节点,你想要一般地处理(很好),但你希望能够以独特的方式从它们获得专门的数据。这在具有(可能)无限数量的唯一数据的上下文中就不是那么好了。

问题是您想要两全其美:唯一封装的数据和对该数据的自由通用访问。

我想说的是,您需要仔细考虑您的Node设计,并仔细考虑节点的一般消费者应该使用什么样的操作/访问,并在抽象基类或提供该访问的少量接口中提供这些操作/访问。

否则,你会在代码的某个地方看到很多向下转换,或者使用反射来最好地猜测事情,或者使用标准接口来描述和获得你想要的值。