2013-02-08 80 views
0

我試圖代碼幹,我有以下的設置,其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實現。

儘量避免代碼重複,但Microsoft建議我不應該在基類構造函數中調用overrideable函數,即使沒有任何重寫實現依賴於運行時設置的值(它們可以,從技術上講,如果c#允許我們覆蓋靜態,那麼它們就被標記爲靜態)。

我想知道的是,讓基類派生類在其構造函數中調用其自己派生的函數派生實現的可接受方式是什麼?或者我只是需要複製和過去一些代碼,並減少系統的可維護性?

回答

4
  1. 可以忽略Visual Studio的代碼分析,如果你100%肯定它不會是你的情況的問題。但是,這可能不是很安全,我個人不建議這樣做。

  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()) 
        { 
        } 
    } 
    
+0

Shoudn't它是:公共類TextureShader:ShaderBase? – Random 2014-01-30 03:33:44

1

你不必複製任何東西。如你所說,這些方法可能是靜態的。因此,讓他們將結果傳遞給基類構造函數。

你現在使用的代碼並不是簡單的,因爲MakeInputLayout依賴於在基類的構造函數中創建的值。雖然你可以以某種方式提取,但我認爲這會變得混亂。

因此,我提出了不同的方法:

與其實現方式沿着創建IInputLayoutProvider接口並傳遞給基類。

相關問題