我最近几次偶然发现需要用一些较低级别的框架类型的东西来做这件事,我想看看是否有更好/更清洁的方法来完成这个,即如果我遗漏了一些明显或聪明的东西,就像我发现[ThreadStatic]
将字典查找替换为线程 ID 以将数据与线程关联时一样。
我有一个基础抽象类,我们称之为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 方法,但是需要支持继承,所以我需要一个包含所有 init 方法的字典无论如何,对于 TEntity 的子类。
此代码在具有 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 中为依赖项属性键入错误的所有者类名称。Kinda 有时会起作用,但随后会出现奇怪的错误并且很难追溯。
归根结底是:考虑到所有这些将附加此数据的类型都实现一个公共基类,除了使用字典之外,是否有更好的方法将任意运行时数据附加到类型?