0

私は DRY をコーディングしようとしていますが、次のセットアップがありますが、Visual Studio のコード分析システムは賢明ではないと言っています。

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 の実装への呼び出しも含まれます。

可能な限りコードの重複を避けようとしていますが、オーバーライドされた実装が実行時に設定された値に依存することはありませんが (技術的には、 c# で statics をオーバーライドできる場合は、static というラベルが付けられています)。

私が知りたいのは、基本クラスが派生クラスにコンストラクターで関数の独自の派生実装を呼び出すように強制する許容可能な方法は何ですか? それとも、いくつかのコードをコピー アンド ペーストして、システムの保守性を低下させなければならないのでしょうか?

4

2 に答える 2

4
  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())
        {
        }
    }
    
于 2013-02-08T12:28:49.023 に答える
1

何もコピーする必要はありません。あなたが言ったように、それらのメソッドは静的である可能性があります。したがって、それらを作成し、結果を基本クラスのコンストラクターに渡します。

MakeInputLayout基本クラスのコンストラクターで作成された値に依存するため、現在のコードはすべてを単純にするわけではありません。どうにかしてそれを抽出することもできますが、これは面倒なことになると思います。

したがって、別のアプローチを提案します。

IInputLayoutProvider実装とともにインターフェイスを作成し、それを基本クラスに渡します。

于 2013-02-08T12:20:13.697 に答える