动态引用 NHibernate 中的属性

本文关键字:属性 NHibernate 引用 动态 | 更新日期: 2023-09-27 18:34:08

我目前正在nHibernate上咬牙切齿,并且有一个关于动态访问持久对象中的属性的问题。

Domain有以下课程:

public class Locations {
    public virtual string CountryCode;
    public virtual string CountryName;
}

现在,假设我有一个对位置对象的引用,有什么方法可以让我做这样的事情吗?

Locations myCountry = new LocationsRepository().GetByCountryCode("US");
myCountry.Set("CountryName", "U.S.A.");

而不是必须做:

myCountry.CountryName = "U.S.A."

没有反思?

动态引用 NHibernate 中的属性

如果避免反射的目标是提高性能,那么一个简单的解决方案是使用以下所有属性对功能进行硬编码:

public class Locations {
    public virtual string CountryCode;
    public virtual string CountryName;
    public void Set(string propertyName, string value) {
        if (propertyName == "CountryCode") this.CountryCode = value;
        else if (propertyName == "CountryName") this.CountryName = value;
        else throw new ArgumentException("Unrecognized property '" + propertyName + "'");
    }
}

通过使用 T4 模板以编程方式为所有域类生成Set方法,可以轻松地使此方法站得住脚。 事实上,我们在自己的代码库中执行类似的事情,使用 T4 模板生成适配器和序列化程序,以避免运行时的反射成本,同时获得在编译时生成代码的反射灵活性。

我知道你说"没有反射",但反射并不全是坏事(当然没有人们想象的那么慢),所以值得一提的是这里的反射解决方案:

using System.Reflection;
typeof(Locations).GetProperty("CountryName").SetValue(myCountry, "U.S.A.", null);

噗,完成了。

您正在寻找的行为类似于具有属性的普通对象并同时具有字典的东西。如果您在 .NET4你可以看看ExpandoObject,它就是这样。

我讨厌在 StackOverflow 上回答我自己的问题,我很欣赏每个人的回答,但他们都没有真正为我做这件事。 经过一些研究,我发现最新版本的NHibernate提供了动态模型。

虽然很方便,但它们的实验性质让我对在生产中使用它们有点怀疑,所以我做了更多的研究。 我发现SE自己的Marc Gravell是他的HyperDescriptor库的继任者,称为Fastmember。 它利用了 DLR 提供的速度增益,并将其与更简单的反射语法混合在一起。 我在我的基实体类中实现了 FastMember 访问作为简单的 GetValue 和 SetValue 方法,我从事商业活动。

没有反思,这可能是一个想法:

public class Locations 
{
  private Dictionary<string, object> _values;
  public Locations() 
  {
    _values = new Dictionary<string, object>();
  }
  public void Set(string propertyName, object value)
  {
     if(!_values.ContainsKey(propertyName))
        _values.Add(propertyName, value);
     else
        _values[propertyName] = value;
  }
  public object Get(string propertyName)
  {
     return _values.ContainsKey(propertyName) ? _values[propertyName] : null;
  }
  public string CountryCode
  {
     get{ return Get("CountryCode"); }
     set{ Set("CountryCode", value); }
  }
}

通过这种方式,您可以在不反射的情况下访问该属性,并使用一种方法更改它们。我还没有测试过这个代码,但我希望这就是你所说的"不能直接访问该物业"的意思。