部分类构造函数和事件处理程序注册

JTe*_*ech 2 c# partial-classes event-handling

我需要为一个由模板生成的类注册一个事件处理程序 - 在EntityFramework中的T4模板.

目前,我们编辑了生成的代码,以在生成的类(模型上下文)的构造函数中注册处理程序.

当前代码:

    public MyAppContext(string connectionString)
        : base(connectionString, ContainerName)
    {
        this.ContextOptions.LazyLoadingEnabled = true;
        // Register the event handler
        this.Connection.StateChange += Connection_StateChange;
    }
Run Code Online (Sandbox Code Playgroud)

问题是,如果将来重新生成代码,那么上面的代码将被破坏,事件处理程序将不再被连接......

代码重新生成从最小的事情自动发生,例如打开EF Designer并在画布上移动表格!因此,我们不要依赖于将自定义代码留在生成的类中.

无论如何我们可以将注册放在一个部分类中,并保持生成的代码不变?

EG是否存在某种事件,一旦调用构造函数,它将始终被触发?

JTe*_*ech 5

这个问题的答案是编辑T4模板以在构造函数的末尾放入方法调用.

在由模板生成的部分类的上下文中,此方法需要是部分方法.

模板需要包含partial方法的定义.

然后你的自定义部分类可以实现该方法,它将由生成的部分类中定义的构造函数调用 - 现在您可以根据需要多次重新生成该部分类,并保证将始终调用部分方法 - 假设没有人编辑模板.

如果有人编辑模板并删除了部分方法的定义,那么您将收到编译器错误 - 易于修复.

如果有人编辑模板并从构造函数中删除对partial方法的调用,那么很遗憾,编译器无法帮助您 - 需要注意的事项!

这是我在tid-bits中的解决方案:

T4模板代码'MyApp.Context.tt'中的构造函数和部分方法定义的片段(有关T4语法及其在EntityFramework中的使用的详细解释,请参见此处):

public <#=code.Escape(container)#>(string connectionString)
    : base(connectionString, ContainerName)
{
<#
    WriteLazyLoadingEnabled(container);
#>
    // Call the OnContextCreated() method to perform any necessary 'post creation' setup
    OnContextCreated();
}

// Define the OnContextCreated partial method so that the accompanying partial Context 
// class can implement this method.
partial void OnContextCreated();
Run Code Online (Sandbox Code Playgroud)

实现partial方法并连接事件处理程序的自定义partial类:

public partial class MyAppContext 
{
    /// <summary>
    /// Performs all 'post creation' operations for the MyAppContext 
    /// 
    /// *********************************
    /// NOTE: If you get a compiler error:
    /// 'No defining declaration found for implementing declaration of partial method 'OnContextCreated()'  
    /// then it is likely that the partial class MyApp.Context.cs does not contain a corresponding
    /// definition for the partial method OnContextCreated().
    /// This can occur if the MyApp.Context.tt template no longer generates the definition.
    /// SOLUTION: Edit the MyApp.Context.tt T4 template to ensure that that partial method is defined AND
    /// that it is called from EACH MyAppContext() constructor.
    /// *********************************
    /// 
    /// </summary>
    partial void OnContextCreated()
    {
        // Register the event handler
        this.Connection.StateChange += Connection_StateChange;
    }
}
Run Code Online (Sandbox Code Playgroud)