基于枚举值获取公共变量的类型(C#)

6

我有一个从逗号分隔文本文件中解析数据的类。我有一个枚举用于帮助我更容易地解析数据字段。解析所有记录的类包含每个字段的公共变量,当然还有它们的变量类型。我需要根据给定的枚举获取这些变量的类型。

public enum DatabaseField : int
    {
        NumID1 = 1,
        NumID2 = 2,
        NumID3 = 3,
    };

public class DataBaseRecordInfo
    {
        public long NumID1 { get; set; }
        public int NumID2 { get; set; }
        public short NumID3 { get; set; }

        public static Type GetType(DatabaseField field)
        {
           Type type;

           switch (field)
           {
               case DatabaseField.NumID1:
                   type = typeof(long);
                   break;
               case DatabaseField.NumID2:
                   type = typeof(int);
                   break;
               case DatabaseField.NumID3:
                   type = typeof(short);
                   break;
               default:
                   type = typeof(int);
                   break;
           }

           return type;
        }
     };

NumID1、NumID2和NumID3都在我的构造函数中被赋值。但是,我想在不创建DataBaseRecordInfo实例的情况下获取这些类型。目前,我的上面的静态方法可以工作,但是,如果我想要更改变量类型,我就必须在两个地方进行更改。有没有办法避免在两个地方进行更改,并将其保留为静态方法?


我不明白这个问题。你能再清楚一点吗?“但是,我想在不创建DataBaseRecordInfo实例的情况下获取这些类型”——这是什么意思? - hackerhasid
这意味着我有一些情况需要获取变量的类型,但不想实例化该类来获取类型。 - jsmith
4个回答

4
如果名称总是完全匹配,您可以使用反射来实现此目的。
return typeof(DataBaseRecordInfo)
    .GetProperty(field.ToString(), BindingFlags.Public | BindingFlags.Instance)
    .PropertyType;

你甚至可以将这些值缓存到一个字典中,所以如果找到了,只需返回字典条目,否则使用反射来确定并缓存结果。

+1 我也考虑过使用字典的方法,但我更喜欢反射的方式。 - SwDevMan81
这种混合方法在我看来完全符合要求。 - David M
哈哈,什么?所有的方面都符合要求,我一定错过了什么......甚至在《新黑客词典》中也找不到这个词条,也许是时候进行修订了? - SwDevMan81

0

是的,您可以使用枚举中的名称以及对DatabaseRecordInfo类型的反射,来获取所需的类型。

可以像这样完成:

public class DataBaseRecordInfo
{
    public long NumID1 { get; set; }
    public int NumID2 { get; set; }
    public short NumID3 { get; set; }

    public static Type GetType(DatabaseField field)
    {
        string name = field.ToString();
        Type recordType = typeof (DataBaseRecordInfo);
        var props = recordType.GetProperties();
        var matchedProperty = props.Where(p => name == p.Name).FirstOrDefault();
        if (matchedProperty == null)
            return null;    // We do not have a matching property.
        return matchedProperty.PropertyType;
    }
};

由于反射在性能方面可能会很昂贵,因此您可能希望将结果缓存到字典中。


0

这样怎么样:

public static Type GetType(DatabaseField field)
{
  DataBaseRecordInfo dbri = new DataBaseRecordInfo();

  switch (field)
  {
    case DatabaseField.NumID1:
      return dbri.NumID1.GetType(); 
    case DatabaseField.NumID2:
      return dbri.NumID2.GetType(); 
    case DatabaseField.NumID3:
     return dbri.NumID3.GetType(); 
    default:
      return typeof(int);
  }
}

我知道你说过不需要创建 DataBaseRecordInfo 的实例,但我假设你是指在静态方法之外创建实例。没有人会看到这个实例。


每次调用该方法都会创建一个实例。它也无法解决在两个地方维护内容的问题。 - David M
我有这样的印象,即“在两个地方维护东西”的问题仅限于类型,而这个解决方案解决得非常好。它甚至为您提供了使用不匹配名称的灵活性。 - Sapph
David,你可以在静态构造函数中创建一个单一的静态实例,以避免在每次调用时创建一个实例。此外,我不确定这不是DRY -- 你能解释一下吗? - rusty
@jsmith - 哪些是...?它能用,但我认为这不是解决问题的好方法。 - David M
@David M 我认为反射是我正在寻找的。出于设计原因,我宁愿不要默认构造函数,这意味着我将另一个类传递给这个类进行解析,因此无法使用默认构造函数声明实例。当然,我可以创建一个默认构造函数,但我宁愿不这样做,因为这似乎很松散。所以它确实有效,但这不是我正在寻找的。 - jsmith
好的,我也更喜欢反射,只是没看出这段代码有什么问题 - 但默认构造函数的问题是一个公正的评论。 - David M

0
如果您想将枚举值与一些附加信息绑定,可以使用自己的CustomAttribute。
也许您需要像这样的东西:
public class DatabaseTypeAttribute : Attribute
{
    public DatabaseTypeAttribute(Type type)
    {
        Type = type;
    }
    public Type Type { get; private set; }
}

public enum DatabaseField : int
{
    [DatabaseType(typeof(long))]
    NumID1 = 1,
    [DatabaseType(typeof(int))]
    NumID2 = 2,
    [DatabaseType(typeof(short))]
    NumID3 = 3,
    NumID4 = 4,
};

public static class DatabaseFieldHelper
{
    public static Type GetDatabaseType(this DatabaseField field)
    {
        var attributes = (DatabaseTypeAttribute[])typeof(DatabaseField).GetField(Enum.GetName(typeof(DatabaseField), field))
            .GetCustomAttributes(typeof(DatabaseTypeAttribute), false);
        if (attributes.Length == 0)
            return typeof(int); //returns default type
        return attributes[0].Type;

    }
}

//prints: NumID1 database type: System.Int64
Console.WriteLine("NumID1 database type: {0}", DatabaseField.NumID1.GetDatabaseType());

//prints: NumID2 database type: System.Int32
Console.WriteLine("NumID2 database type: {0}", DatabaseField.NumID2.GetDatabaseType());

//prints: NumID3 database type: System.Int16
Console.WriteLine("NumID3 database type: {0}", DatabaseField.NumID3.GetDatabaseType());

//prints: NumID4 database type: System.Int32
Console.WriteLine("NumID4 database type: {0}", DatabaseField.NumID4.GetDatabaseType());

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接