繁体   English   中英

抽象基类在构造函数中调用派生方法?

[英]Abstract base class which calls derived method in constructor?

我正在尝试对DRY进行编码,并且具有以下设置,Visual Studio的Code Analysis系统告诉我这是不明智的:

public abstract class ShaderBase
{

    protected ShaderBase(Device device, string vertexShaderString, string pixelShaderString)
    {
        ShaderSignature inputSignature;
        using (ShaderBytecode bytecode = ShaderBytecode.CompileFromFile(vertexShaderString, "VShader", "vs_4_0", ShaderFlags.None, EffectFlags.None))
        {
            vertexShader = new VertexShader(device, bytecode);
            inputSignature = ShaderSignature.GetInputSignature(bytecode);
        }

        inputLayout = MakeInputLayout(device,inputSignature);
    }

    protected abstract InputLayout MakeInputLayout(Device device, ShaderSignature inputSignature);
}

public class TextureShader:ShaderBase
{
    public ColourShader(Device device) : base(device,"shaders/colour.fx", "shaders/colour.fx")
    {
    }

    protected override InputLayout MakeInputLayout(Device device, SlimDX.D3DCompiler.ShaderSignature inputSignature)
    {
        return new InputLayout(device, inputSignature, new[] { 
            new InputElement("POSITION", 0, SlimDX.DXGI.Format.R32G32B32_Float, 0), 
            new InputElement("COLOR",0,SlimDX.DXGI.Format.R32G32B32_Float,0)
        });
    }
}

如您所见,我有一个基类,从中有多个派生类。 每个派生类使用不同的InputLayout,因此必须使用MakeInputLayout的不同实现,这就是我重写它的原因。 但是,每个派生类都必须执行我在基类的构造函数中添加的代码,包括对派生类具有的MakeInputLayout的任何实现的调用。

我试图在可能的情况下避免代码重复,但是Microsoft建议我永远不要在基类构造函数中调用可重写函数,即使没有一个重写实现都依赖于运行时设置的值(从技术上讲,它们可以如果c#允许我们覆盖静态值,则标记为静态)。

我想知道的是,让基类强制派生类在其构造函数中调用其自己的派生实现的可接受方法是什么? 还是我只需要复制和粘贴一些代码来减少系统的可维护性?

  1. 如果您100%确保在您的情况下这不是问题,则可以忽略Visual Studio的代码分析。 但是,这可能不是很安全,因此我个人不建议这样做。

  2. 使用辅助接口/类/代理来避免构造函数虚拟方法的调用:

     public interface IInputLayoutMaker { InputLayout MakeInputLayout(Device device, SlimDX.D3DCompiler.ShaderSignature inputSignature); } public abstract class ShaderBase { protected ShaderBase(Device device, string vertexShaderString, string pixelShaderString, IInputLayoutMaker inputLayoutMaker) { ShaderSignature inputSignature; using (ShaderBytecode bytecode = ShaderBytecode.CompileFromFile(vertexShaderString, "VShader", "vs_4_0", ShaderFlags.None, EffectFlags.None)) { vertexShader = new VertexShader(device, bytecode); inputSignature = ShaderSignature.GetInputSignature(bytecode); } inputLayout = inputLayoutMaker.MakeInputLayout(device,inputSignature); } protected abstract InputLayout MakeInputLayout(Device device, ShaderSignature inputSignature); } public class TextureShader:ShaderBase { private class TextureShaderInputLayoutMaker : IInputLayoutMaker { public InputLayout MakeInputLayout(Device device, SlimDX.D3DCompiler.ShaderSignature inputSignature) { return new InputLayout(device, inputSignature, new[] { new InputElement("POSITION", 0, SlimDX.DXGI.Format.R32G32B32_Float, 0), new InputElement("COLOR",0,SlimDX.DXGI.Format.R32G32B32_Float,0) }); } } public ColourShader(Device device) : base(device,"shaders/colour.fx", "shaders/colour.fx", new TextureShaderInputLayoutMaker()) { } } 

您无需复制任何内容。 如您所说,这些方法可能是静态的。 因此,使它们并将结果传递给基类构造函数。

当前的代码并不能使所有事情变得简单,因为MakeInputLayout依赖于在基类的构造函数中创建的值。 尽管您也可以以某种方式提取它,但我认为这会变得混乱。

因此,我提出了另一种方法:

创建一个IInputLayoutProvider接口及其实现,并将其传递给基类。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM