C# 以编程方式检索多个类的静态成员

C# 以编程方式检索多个类的静态成员,c#,.net,class,reflection,C#,.net,Class,Reflection,我不确定解决这个问题的最佳方法,无论是通过反思、重新设计我的类,还是做一些简单的事情 基本上我有一个基类,我可以有任意数量的子类从中继承。让我们将基类Shape和子类CircleShape、RectangleShape等称为 基类本身从未实例化,只有子类。有些从未被实例化,有些在程序的整个生命周期中被多次实例化 有时,在实例化子类之前,我需要特定于该子类的信息。现在我使用枚举来区分所有子类类型。我在switch语句中基于enum实例化每个子类,如下所示: switch (shapeType) {

我不确定解决这个问题的最佳方法,无论是通过反思、重新设计我的类,还是做一些简单的事情

基本上我有一个基类,我可以有任意数量的子类从中继承。让我们将基类Shape和子类CircleShape、RectangleShape等称为

基类本身从未实例化,只有子类。有些从未被实例化,有些在程序的整个生命周期中被多次实例化

有时,在实例化子类之前,我需要特定于该子类的信息。现在我使用枚举来区分所有子类类型。我在switch语句中基于enum实例化每个子类,如下所示:

switch (shapeType)
{
case CircleShape:
    shape = new CircleShape();

case SquareShape:
    shape = new RectangleShape();
}
但是,我不必使用这种硬编码的switch语句,而是要枚举所有的子类。是否有一种方法可以自动检索子类列表并访问其静态成员以获取有关它们的信息(在实例化它们之前)?或者,手动实例化每个类一次并将它们添加到数组中,这样我就可以枚举它们(但不会将这些实例绑定到任何实际数据),这样会更容易吗


或者我应该做一些完全不同的事情吗?

您可以使用反射来枚举所有类,但这不是一种非常有效的方法,因为它有点慢

如果它们都在同一个程序集中,您可以执行以下操作:

   class Shape
   {
      /* ... */
   }

   class CircleShape : Shape
   {
      public static string Name
      {
         get
         {
            return "Circle";
         }
      }
   }

   class RectangleShape : Shape
   {
      public static string Name 
      {
         get
         {
            return "Rectangle";
         }
      }
   }

   class Program
   {
      static void Main(string[] args)
      {
         var subclasses = Assembly.GetExecutingAssembly().GetTypes().Where(type => type.IsSubclassOf(typeof(Shape)));
         foreach (var subclass in subclasses)
         {
            var nameProperty = subclass.GetProperty("Name", BindingFlags.Public | BindingFlags.Static);
            if (nameProperty != null)
            {
               Console.WriteLine("Type {0} has name {1}.", subclass.Name, nameProperty.GetValue(null, null));
            }
         }
      }
   }

当然,您也可以使用属性而不是静态成员,如果您想用希望在运行时查找的信息来装饰类,这可能更可取。有许多关于属性如何在internet上工作的示例。

您可以使用属性定义类上的元数据,然后在运行时使用反射来读取此元数据,以决定如何处理此类,而无需实例化它

以下是有关使用属性的一些信息(您也可以创建自己的自定义属性)

下面是一个快速的示例,它看起来像什么:

类防御:

   // ********* assign the attributes to the class ********

   [BugFixAttribute(121,"Jesse Liberty","01/03/05")]
   [BugFixAttribute(107,"Jesse Liberty","01/04/05", Comment="Fixed off by one errors")]
   public class MyMath
   {
   ...
// get the member information and use it to retrieve the custom attributes
System.Reflection.MemberInfo inf = typeof(MyMath);
object[] attributes;
attributes = inf.GetCustomAttributes(typeof(BugFixAttribute), false);

// iterate through the attributes, retrieving the properties
foreach(Object attribute in attributes)
{
    BugFixAttribute bfa = (BugFixAttribute) attribute;
    Console.WriteLine("\nBugID: {0}", bfa.BugID);
    Console.WriteLine("Programmer: {0}", bfa.Programmer);
    Console.WriteLine("Date: {0}", bfa.Date);
    Console.WriteLine("Comment: {0}", bfa.Comment);
}
使用反射读取属性:

   // ********* assign the attributes to the class ********

   [BugFixAttribute(121,"Jesse Liberty","01/03/05")]
   [BugFixAttribute(107,"Jesse Liberty","01/04/05", Comment="Fixed off by one errors")]
   public class MyMath
   {
   ...
// get the member information and use it to retrieve the custom attributes
System.Reflection.MemberInfo inf = typeof(MyMath);
object[] attributes;
attributes = inf.GetCustomAttributes(typeof(BugFixAttribute), false);

// iterate through the attributes, retrieving the properties
foreach(Object attribute in attributes)
{
    BugFixAttribute bfa = (BugFixAttribute) attribute;
    Console.WriteLine("\nBugID: {0}", bfa.BugID);
    Console.WriteLine("Programmer: {0}", bfa.Programmer);
    Console.WriteLine("Date: {0}", bfa.Date);
    Console.WriteLine("Comment: {0}", bfa.Comment);
}

注意:不过,在大量对象的大量迭代中使用反射时要小心,因为它会带来巨大的性能成本。

有一种方法可以检索类的静态字段,而不必先创建它们,请参见此处的问题和答案: