我想將一些代碼從Delphi移植到C#,並且我找到了一種我無法以合理方式實現的構造,同時遵守.NET Framework設計準則(我在問題的最後解決了這個問題)。很顯然,C#,Java,C++(以及許多其他語言)提供了方法/構造函數重載的含義,但是Delphi構造函數還可以有多個名稱。這樣,有可能寫一個直接表示的意圖代碼:C#中重載的構造函數類似於Delphi(具有多個名稱)
var
Data, ParI, ParD, Locl: TDataElement;
begin
Data := TDataElement.Create('Element');
ParI := TDataElement.CreateParam('IntElement', 22);
ParD := TDataElement.CreateParam('DblElement', 3.14);
Locl := TDataElement.CreateLocal('LocalElement');
// ... use the above objects ...
end;
下面
簡化代碼:
unit DataManager;
interface
TDataElement = class
FName: string;
FPersistent: Boolean;
public
constructor Create(AName: string);
constructor CreateParam(AName: string; DefaultInt: Integer); overload;
constructor CreateParam(AName: string; DefaultDouble: Double); overload;
constructor CreateLocal(AName: string);
property Name: string read FName;;
property Persistent: Boolean read FPersistent;
end;
implementation
constructor TDataElement.Create(AName: string);
begin
FName := AName;
FPersistent := True;
// ... other initialization ...
end;
constructor TDataElement.CreateParam(AName: string; DefaultDouble: Double);
begin
Create(AName);
// ... use DefaultInt ...
end;
constructor TDataElement.CreateParam(AName: string; DefaultInt: Integer);
begin
Create(AName);
// ... use DefaultDouble...
end;
constructor TDataElement.CreateLocal(AName: string);
begin
Create(AName);
FPersistent := False;
// ... other code for local (non-persistent) elements ...
end;
特別是在C#構造函數必須具有相同的名稱作爲類,所以首先我試圖用枚舉來區分行爲。唉,我偶然發現了幾個問題跌跌撞撞:
-
在每個構造
- 第一個參數是同一類型(ElementKind)
- 構造不容易辨認像德爾福(創建與CreateParam與CreateLocal)
- 格外小心,需要在DataElement 錯誤
- 可能性,如指定ElementKind.DoubleParam並傳遞
- 一個額外的布爾參數是必需的以處理局部元素整數值的子類
第一次嘗試:
public enum ElementKind
{
Regular, IntParam, DoubleParam, Local
}
public class DataElement
{
private string FName;
public string Name { get { return FName; } }
private bool FPersistent;
public bool Persistent { get { return FPersistent; } }
public DataElement(ElementKind kind, string name)
{
FName = name;
// ugly switch :-(
switch (kind)
{
case ElementKind.Regular:
case ElementKind.IntParam:
case ElementKind.DoubleParam:
FPersistent = true;
break;
case ElementKind.Local:
FPersistent = false;
break;
}
// ... other initialization ...
}
public DataElement(ElementKind kind, string name, int defaultInt)
: this(kind, name)
{
// ... use defaultInt ...
}
public DataElement(ElementKind kind, string name, double defaultDouble)
: this(kind, name)
{
// ... use defaultDouble ...
}
// Redundant "bool local" parameter :-(
public DataElement(ElementKind kind, string name, bool local)
: this(kind, name)
{
// What to do when "local" is false ???
// ... other code for local (non-persistent) elements ...
}
}
public class Program
{
public void Run()
{
DataElement data = new DataElement(ElementKind.Regular, "Element");
DataElement parI = new DataElement(ElementKind.IntParam, "IntElement", 22);
DataElement parD = new DataElement(ElementKind.DoubleParam, "DblElement", 3.14);
DataElement locl = new DataElement(ElementKind.Local, "LocalElement");
}
}
然後我試圖更加面向對象的方法來區分的類型構造,同時保持在運行相同的初始化代碼()方法:
public class ElementKind
{
public class RegularElement
{
internal RegularElement() { /* disallow direct creation */ }
}
public class IntParamElement
{
internal IntParamElement() { /* disallow direct creation */ }
}
public class DoubleParamElement
{
internal DoubleParamElement() { /* disallow direct creation */ }
}
public class LocalElement
{
internal LocalElement() { /* disallow direct creation */ }
}
public static readonly ElementKind.RegularElement Regular = new RegularElement();
public static readonly ElementKind.IntParamElement IntParam = new IntParamElement();
public static readonly ElementKind.DoubleParamElement DoubleParam = new DoubleParamElement();
public static readonly ElementKind.LocalElement Local = new LocalElement();
}
public class DataElement
{
private string FName;
public string Name { get { return FName; } }
private bool FPersistent;
public bool Persistent { get { return FPersistent; } }
protected DataElement(string name)
{
FName = name;
// ... other initialization ...
}
public DataElement(ElementKind.RegularElement kind, string name)
: this(name)
{
FPersistent = true;
}
public DataElement(ElementKind.IntParamElement kind, string name, int defaultInt)
: this(name)
{
FPersistent = true;
// ... use defaultInt ...
}
public DataElement(ElementKind.DoubleParamElement kind, string name, double defaultDouble)
: this(name)
{
FPersistent = true;
// ... use defaultDouble ...
}
public DataElement(ElementKind.LocalElement kind, string name)
: this(name)
{
FPersistent = false;
// ... other code for "local" elements ...
}
}
public class Program
{
public void Run()
{
DataElement data = new DataElement(ElementKind.Regular, "Element");
DataElement parI = new DataElement(ElementKind.IntParam, "IntElement", 22);
DataElement parD = new DataElement(ElementKind.DoubleParam, "DblElement", 3.14);
DataElement locl = new DataElement(ElementKind.Local, "LocalElement");
}
}
一切編譯和工作得很好。那麼我的問題在這裏? .NET Framework設計指南以及名爲Microsoft FxCop的工具。通過這個工具運行最後一個代碼後,我得到了多個突破問題(見下文)。
問題是:如何設計我的類以符合.NET設計指南和最佳實踐?
斷裂 - 確定性90% - 嵌套類型應該是不可見 - ElementKind + RegularElement 斷裂 - 確定性90% - 嵌套類型應該是不可見 - ElementKind + IntParamElement 斷裂 - 確定性90% - 嵌套類型應不可見 - ElementKind + DoubleParamElement 斷裂 - 確定性90% - 嵌套類型應該是不可見 - ElementKind + LocalElement
斷裂 - 確定性90% - 靜態成員的類型不應該有構造 - ElementKind
打破 - 確定性75% - 標識符不應包含類型名稱 - DataElement。#。ctor(ElementKind + IntParamElement,System.String,System.Int32)
打破 - 確定性75% - 標識符不應包含類型名稱 - DataElement 。#構造函數(ElementKind + DoubleParamElement,System.String,系統。雙人間)
非斷裂 - 確定性的25% - 不聲明只讀可變引用類型 - ElementKind#普通
非破 - 確定性的25% - 不聲明只讀可變引用類型 - ElementKind#IntParam
非斷裂 - 確定性的25% - 不聲明只讀可變引用類型 - ElementKind#DoubleParam
非斷裂 - 確定性的25% - 不聲明只讀可變引用類型 - ElementKind#本地
。
工廠方法是我在發佈我的問題幾個小時後想到的。非常感謝確認:) 順便說一句。 ElementKind旨在成爲一個枚舉,實際上它是C#代碼的第一個版本。很高興知道我可以回覆它。 –