44

我在关系数据库中有一个自定义实体,我已通过域模型映射到 CLR。因此,通过使用以下语句,我可以通过域模型上的 LINQ 查询将数据库中的实体拉入内存,如下所示;

var inspection = (from i in dbContext.New_testinspectionExtensionBases
              where i.New_testinspectionId == currentInspection   
              select i).First();                         

我需要访问此实体上的属性/字段,我需要能够确定属性/字段名称及其值。我想遍历内存中的这些项目,并将它们的名称和值写到控制台。

我尝试使用这种方法,但无法弄清楚如何更正语法(我也不确定 GetProperties 是正确使用的方法,GetFields 出于某种原因没有返回任何内容,所以我认为这是要走的路)但这并不重要,因为我需要的只是对该值的读取权限;

var inspectionReportFields = inspection.GetType().GetProperties(); 
// I called this inspectionReportfields because the entity properties correspond to 
// form/report fields I'm generating from this data.

foreach (var reportField in inspectionReportFields)
{
    var value = reportField.GetValue();
    Console.WriteLine(reportField.Name);
    Console.WriteLine(value);
}

在使用 EF 或 openaccess 之类的域模型时,是否有更简单的方法来获取属性/字段值?如果没有,我会以正确的方式去做吗?最后,如果是这样,我该如何修复值变量声明中的语法?

以下是域模型生成的代码中的一些示例字段/属性,供参考;

    private int? _new_systemGauges;
    public virtual int? New_systemGauges 
    { 
        get
        {
            return this._new_systemGauges;
        }
        set
        {
            this._new_systemGauges = value;
        }
    }

    private int? _new_systemAlarm ;
    public virtual int? New_systemAlarm 
    { 
        get
        {
            return this._new_systemAlarm;
        }
        set
        {
            this._new_systemAlarm = value;
        }
    }
4

3 回答 3

82

我假设您正在尝试定义一种通用方法来“转储”对象,而无需对其结构一无所知。如果是这样,那么您正在以正确的方式处理事情。您使用反射(GetType()和相关的Type类方法)来检查对象并返回其信息。

没有返回任何内容的原因GetFields()是您可能没有提供正确的绑定标志。特别是,如果你调用不带任何参数的重载,你只会得到public字段;如果您想要私有字段,则需要专门询问它们。

在您的情况下,GetFields(BindingFlags.NonPublic)会返回_new_systemGauges_new_systemAlarm字段,而 GetProperties() 会返回New_systemAlarmNew_systemAlarm属性。

您错过的另一个关键元素是您返回的数据是类型元数据;它定义了 的结构class,而不是任何特定的实例。如果您想知道特定实例的属性值是什么,您需要询问:

foreach (var prop in obj.GetType().GetProperties())
{
  Console.WriteLine("{0} = {1}", prop.Name, prop.GetValue(obj, null));
}

如果您拥有PropertyInfo类型元数据中的一个元素,则可以在该类型的任何实例上请求该属性值。它不必与您最初使用的实例相同。例如:

var objs = somelist.Where(x => x.Id == 1);
foreach (var prop in objs.First().GetType().GetProperties())
{
  int x = 0;
  foreach (var obj in objs)
  {        
    if (prop.PropertyType.Name.Equals("Int32"))
    {
      int val = (int)prop.GetValue(obj, null);
      Console.WriteLine("Obj #{0}: {1} = 0x{2:x8}", x++, prop.Name, val);
    }
    else if (prop.PropertyType.Name.Equals("Decimal"))
    {
      int val = (decimal)prop.GetValue(obj, null);
      Console.WriteLine("Obj #{0}: {1} = {2:c2}", x++, prop.Name, val);
    }
    else
    {
      Console.WriteLine("Obj #{0}: {1} = '{2}'", x++, prop.Name, prop.GetValue(obj, null));
    }
  }
}

从技术上讲,您应该检查结果GetIndexParameters以查看属性是否被索引;null参数 toGetValue实际上是一个索引值数组。

要转换您返回的值,您可以使用类型转换,或者如果您想要更灵活一点,请使用 Convert 类的方法。不同之处在于,例如,如果您有一个short属性,GetValue()将返回一个装箱短,然后您不能将其类型转换为int; 您必须先将其拆箱short。Using将执行所有需要的步骤,以从任何可转换为整数的属性中Convert.ToInt32()获取值。int

引用类型之间的转换更容易,因为您可以使用isand as;这些工作就像您对“反射”属性值所期望的那样。

于 2012-03-15T17:11:20.807 回答
2

GetProperties确实是正确的方法。

要摆脱编译器错误,请将您的代码更改为:

var value = reportField.GetValue(inspection, null);

您需要传递要从中获取值的实例,因为PropertyInfo对象未绑定到任何特定的类实例。


请考虑遵循标准的 .NET 命名规则。

这将导致以下结果:

NewSystemAlarm代替New_systemAlarm
newSystemAlarm_newSystemAlarm代替_new_systemAlarm
NewTestInspectionExtensionBases代替 代替New_testinspectionExtensionBases
NewTestInspectionId代替New_testinspectionId

于 2012-03-15T17:10:38.377 回答
0

如果您使用的是 OpenAccess,您始终可以使用有关您的模型类的完整信息。那里的信息是从您的映射中检索到的,这意味着您不需要反映您的类(没有开销)。

只需通过 context.Metadata.PersistentTypes 浏览所有类映射信息。

于 2012-03-15T18:20:47.043 回答