将数据与基本抽象类型中的具体子类相关联(Associate data with concrete subclasses from a base abstract type)

编程入门 行业动态 更新时间:2024-10-28 12:26:52
将数据与基本抽象类型中的具体子类相关联(Associate data with concrete subclasses from a base abstract type)

我最近偶然发现需要用一些较低级别的框架类型来做这件事,我想看看是否有更好/更清晰的方法来实现这一点,即如果我遗漏了明显或聪明的东西就像我发现[ThreadStatic]将字典查找替换为线程ID以便与Threads关联数据一样。

我有一个基础抽象类,我们称之为Entity 。 每个Entity需要在构造函数中执行一组初始化操作,这些操作取决于实例化的实际具体类。 有没有办法我可以在不进行字典查找并调用this.GetType()情况下完成此操作?

这是一些类似于我现在的代码:

public abstract class Entity { private static Dictionary<Type, Action<EntityData>> _initActions = new Dictionary<Type, Action<EntityData>>(); private EntityData _data = new EntityData(); protected Entity() { _initActions[this.GetType()].Invoke(_data); } } public class Employee : Entity { public string Name { get; set; } } public class Manager : Employee { public List<Employee> Subordinates { get; set; } }

Employee构造函数和Manager构造函数需要以不同的类型初始化它们的_data字段。 _initActions集合在任何实例新建之前都会在另一个方法中初始化,我认为这个讨论没有任何意义。

我希望类的使用对于框架的用户保持尽可能简单,所以我不能使用奇怪的黑客,比如要求用户以某种特殊或不直观的方式覆盖每种具体类型的Init方法。

泛型几乎可以工作,在某种意义上我可以做一些像Entity<TEntity>来获取一个特定于TEntity的静态字段来存储init方法,如果我没有任何继承,但是需要支持继承,所以我需要一个字典无论如何,对于TEntity的子类的所有init方法。

此代码在一些非常低级别的数据库引擎类型场景中以1m迭代的紧密循环运行,因此摆脱字典查找确实在某些情况下提供了一些显着的加速(通过替换为hacky Init覆盖实现来测试)。

有任何想法吗?

编辑:

我想说清楚一些事情。 实体引擎自动设置_initAction以执行初始化其_data容器所需的操作。 库的“用户”对此过程一无所知,也不需要。 我所询问的是一种避免字典查找以从基类获取特定于类型的运行时信息的方法,但这可能是不可能的。

是的,这是微优化,但我们已经使用真实查询对此进行了测试,并且对需要实例化大型数据集的某些查询的查询时间缩短了15-20%。

更快的代码看起来像这样:

public class Employee : Entity { private static EntityInitializer _initMethod = Entity.GetInitMethod(typeof(Employee)); public string Name { get; set; } public Employee() { _initMethod.Invoke(this); } }

这样,对Employee类型执行一次字典查找。 它并不可怕,但它需要a)每个类中的样板,我不喜欢和b)略有错误,因为你必须将类型参数与当前类匹配,否则会发生时髦的事情,有点像你的时候在WPF中为依赖项属性键入错误的所有者类名称。 有时候有点工作,但随后出现了奇怪的错误,很难追溯。

它归结为:除了使用Dictionary之外,还有更好的方法将任意运行时数据附加到Type,考虑到所有这些附加了这些数据的类型都实现了公共基类吗?

I've stumbled upon the need to do this a few times recently with some lower level framework type stuff and I'd like to see if there is a better/cleaner way to accomplish this, i.e. if I'm missing something obvious or clever, like the time I discovered [ThreadStatic] to replace dictionary lookups against thread IDs for associating data with Threads.

I have a base abstract class, lets call it Entity. Every Entity needs to perform a set of initialization actions in the constructor that depends on the actual concrete class being instantiated. Is there a way I can accomplish this without doing a dictionary lookup and calling this.GetType()?

Here is some code similar to what I have now:

public abstract class Entity { private static Dictionary<Type, Action<EntityData>> _initActions = new Dictionary<Type, Action<EntityData>>(); private EntityData _data = new EntityData(); protected Entity() { _initActions[this.GetType()].Invoke(_data); } } public class Employee : Entity { public string Name { get; set; } } public class Manager : Employee { public List<Employee> Subordinates { get; set; } }

The Employee constructor and Manager constructor need to initialize their _data fields differently as they are different types. The _initActions collection gets initialized in another method prior to any instances being new'd up, which I don't think has any significance on this discussion.

I want usage of the class to remain as simple as possible for the user of the framework, so I can't use strange hacks like requiring users to override an Init method in each concrete type in some peculiar or unintuitive way.

Generics almost work, in the sense that I could do something like Entity<TEntity> to get a TEntity specific static field to store the init method if I didn't have any inheritance, but inheritance needs to be supported so I would need a dictionary of all init methods for the subclasses of TEntity anyway.

This code runs in some pretty low level database engine type scenarios in tight loops with 1m iterations, so getting rid of the dictionary lookup does provide some significant speedups in certain situations (tested by replacing with a hacky Init override implementation).

Any ideas?

EDIT:

I want to make a few things clear. The entity engine automatically sets up _initAction to do what it needs to to initialize its _data container. The "user" of the library knows nothing about this process and doesn't need to. All I was inquiring about is a way to avoid a dictionary lookup to get type-specific runtime information from a base class, but that may not be possible.

Yes, this is micro-optimization, but we have tested this with real queries and gotten 15-20% query time reductions on some queries that need to instantiate large datasets.

The faster code looked like this:

public class Employee : Entity { private static EntityInitializer _initMethod = Entity.GetInitMethod(typeof(Employee)); public string Name { get; set; } public Employee() { _initMethod.Invoke(this); } }

This way, the dictionary lookup is done once for the Employee type. It's not horrible, but it requires a) boilerplate in every single class, which I don't like and b) slightly error prone as you have to match up the type parameter with the current class otherwise funky things happen, kind of like when you type in the wrong owner class name for a dependency property in WPF. Kinda sometimes works, but then wierd bugs pop up and its hard to trace back.

What it comes down to is this: is there was a better way to attach arbitrary runtime data to a Type besides using a Dictionary, considering that all these types that will have this data attached to them all implement a common base class?

最满意答案

你能不能创建一个你传递类型的ctor?

protected Entity(Type type) { _initActions[type].Invoke(_data); } } public class Employee : Entity { private static Type mytype = typeof(Employee); public string Name { get; set; } public Employee(): base(mytype) { } }

查找导致性能问题? 字典查找是0(1)和几毫秒。 一个程序只能有这么多的类。 实体仍然需要创建对象,创建新的EntityData并运行Invoke。 除了初始化实现Entity的类之外。

Could you not just create a ctor that you pass the type to?

protected Entity(Type type) { _initActions[type].Invoke(_data); } } public class Employee : Entity { private static Type mytype = typeof(Employee); public string Name { get; set; } public Employee(): base(mytype) { } }

The lookup is causing performance issues? Dictionary lookup is 0(1) and few milliseconds. A program can only have so many classes. Entity still needs to create the object, create a new EntityData, and run Invoke. In addition to initialization of the classes that implement Entity.

更多推荐

本文发布于:2023-07-27 14:03:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1291472.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:子类   相关联   抽象   类型   数据

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!