有没有办法避免 FieldAccessException?

发布于 2024-10-17 02:54:32 字数 867 浏览 1 评论 0原文

我们有一个类库,它执行一些类似于 ORM 的基本操作,基本上我们可以执行以下操作:

conn.Query<EntityType>("select * from table");

并返回一个 List。由于从列名到实体类型属性的映射存储在实体类型内部,因此当我们需要时,只需使用属性的子集,我们就可以轻松构造基本对象。

问题是,这段代码严重依赖反射,我们刚刚发现我们知道的开销远远大于我们的预期。

与“select * from table”相关的各种操作的示例时序:

  1. IDataReader,循环遍历所有行,178ms
  2. IDataReader,调用 GetValues 获取 object[] 数组,对于所有行,260ms
  3. IDataReader,调用 GetValues,构造新对象并添加到列表,对于所有行,356ms
  4. 新对象,使用反射将值复制到属性,~10.500ms(29x 步骤 3)。

IDataReader,调用 GetValues,构造 缓存涉及的反射,但仍然有太多的开销。

由于涉及的 99% 的对象都是带有(1 或 2 个支持字段)的简单属性,我想我可以通过 IL/DynamicMethod 生成以下代码:

instance._Id = (int)value;

这会失败并出现 FieldAccessException,我认为这是因为这些字段是私有的。有什么方法可以让我生成这段代码,或者我只是在安全方面树错了树?

We have a class library that does some basic operations similar to an ORM, basically we can do something like this:

conn.Query<EntityType>("select * from table");

and get back a List<EntityType>. Since the mapping from column names to properties on the entity type is stored inside the entity type, we can easily construct basic objects when we need to with only a subset of the properties.

The problem is, this code relies heavily on reflection, and we just discovered that the overhead, which we knew we had, was far bigger than what we anticipated.

example timings of various operations related to a "select * from table":

  1. IDataReader, loop through all the rows, 178ms
  2. IDataReader, call GetValues to get the object[] array, for all rows, 260ms
  3. IDataReader, call GetValues, construct new object and add to list, for all rows, 356ms
  4. IDataReader, call GetValues, construct new object, use reflection to copy values to properties, ~10.500ms (29x step 3.)

We cache the reflection involved, but still there's too much overhead.

Since 99% of the objects involved are simple properties with (1 or 2 backing fields), I thought I could just generate the following code through IL/DynamicMethod:

instance._Id = (int)value;

This fails with FieldAccessException, and I assume this is because the fields are private. Is there any way for me to generate this code at all, or am I just barking up the wrong tree security-wise?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

层林尽染 2024-10-24 02:54:32

是的;在您的DynamicMethod中,您需要告诉它将自身与EntityType关联起来;然后访问问题就消失了。使用将 owner 设置为 typeof(EntityType) 并将 skipVisibility 设置为 true 的重载。

然而,在大多数情况下,您应该能够像访问字段一样快速地访问属性。因此,除非有充分的理由选择字段,否则更喜欢属性。当然,如果使用属性,您可以让用户通过装饰最合适的来决定。

Yes; in your DynamicMethod you need to tell it to associate itself with EntityType; then the access problem goes away. Use the overload that sets owner to typeof(EntityType), and skipVisibility to true.

However, in most cases you should be able to go the the properties virtually as quickly as the fields. So prefer the properties unless there is a good reason to choose fields. Of course, if using attributes you can let the user decide, by decorating the most appropriate.

少女七分熟 2024-10-24 02:54:32

为什么不使属性读/写并调用“设置属性”方法,而不是尝试直接写入支持属性?

这还有一个优点,如果实现类使用自动生成的属性(例如 string Name{get;set;}),那么您的代码生成解决方案仍然可以工作,因为它不会对如何进行任何假设该属性已实施。

Why not make the property read/write and call the "set property" method instead of trying to write directly to the backing property?

This also has the advantage that if the implementing class used auto generated properties (eg string Name{get;set;} then your code-gen solution will still work as it doesn't make any assumptions about how the property is implemented.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文