[英]Can I override ToString() for classes in a public API?
我正在編寫一個與另一軟件的API接口的工具。 我的工具的一部分將需要生成有關通過API找到的各種對象的報告,並且我希望這些報告包含標識每個對象的簡單字符串。 默認情況下,我計划使用ToString()為每個對象生成字符串。 但是,毫不奇怪,我發現此API中的默認ToString()實現不具有描述性。
最初,我考慮使用長的Switch語句執行類似以下代碼的操作。 盡管這很可能會變得難以控制。
public string GetAPIObjectDescrition(object obj)
{
Type t = obj.GetType();
Switch(t)
{
Case typeof(SomeAPIType):
SomeAPIType x = (SomeAPIType)obj;
return x.SomeProperty;
Case typeof(SomeOtherAPIType):
SomeOtherAPITypex = (SomeOtherAPIType)obj;
return x.SomeOtherProperty;
default:
return x.ToString();
}
}
接下來,我嘗試使用擴展方法(請參見下面的代碼)。 CustomObjectDescription()可以按預期工作,但是當我嘗試調用ToString()時,它僅返回默認的ToString()結果。 我以前從未使用過擴展方法,因此我可能完全以為這樣的想法是根本不可能的。
我不能保證API中遇到的每個Type都將有一個CustomObjectDescription()擴展,因此,如果我采用這種方法,我將不得不每次都不得不使用反射來檢查當前對象是否具有GetObjectDescription()擴展。 。 我想盡可能避免使用反射。
public static class APIObjectDescriptionExtensions
{
public static string ToString(this APIObject element)
{
return "ElementName = " + element.Name + " ElementID =" + element.Id.IntegerValue.ToString();
}
public static string CustomObjectDescription(this APIObject element)
{
return "ElementName = " + element.Name + " ElementID =" + element.Id.IntegerValue.ToString();
}
}
有人對我應該如何解決此問題有其他建議嗎? 我更喜歡一種解決方案,其中每種API類型的代碼彼此獨立(沒有巨大的Switch語句)。
另外,如果可能的話,我希望一種類型的描述字符串代碼可以繼承到子類型,除非這些類型具有自己的唯一描述字符串代碼。
我認為可能會有更好的解決方案,包括創建自定義TypeConverters或覆蓋/擴展System.Convert.ToString()?
更新資料
我認為下面的示例可能有助於闡明我正在嘗試做的事情。 最終,我希望能夠從此API中獲取任意類,並在運行時才知道其Type,然后生成描述字符串。 如果Type具有我的自定義擴展方法,則應使用它,否則代碼應退回到普通的舊ToString()上。
public static string GetDataDescription(object o)
{
//get the type of the input object
Type objectType = o.GetType();
//check to see if a description extension method is defined
System.Reflection.MethodInfo extensionMethod = objectType.GetMethod("MyDescriptionExtensionMethod");
if (extensionMethod != null)
{
//if a description extension method was found returt the result
return (string)extensionMethod.Invoke(o, new object[] { });
}
else
{
//otherwise just use ToString();
return o.ToString();
}
}
上面的這段代碼不起作用,因為GetMethod()找不到擴展方法。
您可以為每個類提供一個包裝,類似於以下內容:
public class SomeAPITypeWrapper : SomeAPIType
{
public override string ToString()
{
return SomeProperty;
}
}
public class SomeOtherAPITypeWrapper : SomeOtherAPIType
{
public override string ToString()
{
return SomeOtherProperty;
}
}
當然,這允許您在問題中使用基類/子類。 它還可以使它保持整潔,並保持在對象模型內部,而不是在switch語句或幫助器類中。
您可以將所有字符串拖延到應用程序的單獨關注中。 StatePrinter( https://github.com/kbilsted/StatePrinter )是這樣一種API,您可以在其中使用默認值或根據要打印的類型進行配置。
var car = new Car(new SteeringWheel(new FoamGrip("Plastic")));
car.Brand = "Toyota";
然后打印
StatePrinter printer = new StatePrinter();
Console.WriteLine(printer.PrintObject(car));
然后您得到以下輸出
new Car() {
StereoAmplifiers = null
steeringWheel = new SteeringWheel()
{
Size = 3
Grip = new FoamGrip()
{
Material = ""Plastic""
}
Weight = 525
}
Brand = ""Toyota"" }
使用IValueConverter抽象,可以定義打印機的類型,使用FieldHarvester,可以定義字符串中要包括的字段。
您是否在擴展類中嘗試使用ToString()以外的其他名稱? 我也不完全知道擴展方法,但是我猜是base.ToString被調用了而不是您的。 可能采用ToDescription()擴展方法會產生更好的結果。
我建議制作一個Dictionary<Type,Converter<object,string>>
。 然后,您可以查找自定義的字符串生成器,如果找不到,則調用ToString
。
請注意,字典將檢查類型是否完全匹配,因此,如果要處理子類,則必須編寫一些其他代碼以查看是否在字典中列出了基類型(提示:如果您匹配基類,或者即使您不這樣做,也可以將實際的派生類型添加到字典中,這樣就不必再次遍歷繼承樹。
請注意,您可以為Object.ToString()
建立一個符合Converter<object,string>
協定的“開放委托”,並將其用作默認協定,甚至將其存儲在字典中,而不是對ToString
進行特殊處理。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.