[英]How to handle multiple identical classes in C#
我正在使用一個具有多個不同“服務”(到目前為止大約有10個)的客戶端API,每個服務都作為自己的命名空間導入。 他們的標准API調用模式的一部分涉及返回錯誤消息數組:
public class Error {
public String ErrorMessage {get;set}
public int errorNumber {get;set}
..etc
}
我一直在嘗試清理並統一我們對這些消息的處理。 我試圖使一個功能來處理它們,例如:
void CheckErrors(List<Error> errors) {
if(errors != null && errors.Count() > 0)
throw new Exception(errors.First().ErrorMessage);
}
(實際功能更復雜,但這給出了總體思路)
但是,事實證明,它們的每個服務都對此Error類有其自己的(相同)定義。 在C ++中,我只能對該函數進行模板化,並且可以正常工作,或者在動態語言中,它可以正常工作,但是在C#中,我無法找到一種方法來制作相同功能的10個以上的副本,每個錯誤類型的錯誤名稱空間均不同。
在我自己的代碼中,我可以僅向這些類添加接口,但是由於不是我的代碼,所以我不認為您可以在C#中做到這一點? 我可以創建一個從每個類繼承並實現接口的包裝器類,但是我仍然對每個名稱空間/服務都重復使用代碼。
有沒有更清潔的方法來解決這個問題?
您可以考慮使用后期綁定解決方案,既可以使用反射也可以使用dynamic
。 兩者都有相同的缺點:您會松散編譯時類型的安全性,但是如果它是一個非常孤立且包含一部分的代碼,則應該可以接受:
反射
void CheckErrors(List<object> errors) { if(errors != null && errors.Count() > 0) { var firstError = errors.First(); throw new Exception( firstError.GetType() .GetProperty("ErrorMessage") .GetValue(firstError) .ToString()); }
動態
void CheckErrors(List<dynamic> errors) { if(errors != null && errors.Count() > 0) throw new Exception(errors.First().ErrorMessage); }
忍受...您可能還需要另一個Error
類,該類的屬性與其Error
類相同,但是您在名稱空間中定義。
您的方法CheckErrors
使用Error
的定義。
最后,您可以使用AutoMapper在它們的Error
類型和您的Error
類型之間進行映射。 這幾乎就是AutoMapper設計的目的。 由於所有合同都是相同的,因此AutoMapper配置應該很簡單。 當然,您會花費一些映射的運行時開銷,但是我認為這將導致最干凈的靜態類型的解決方案,因為您不能更改它們的接口。
AutoMapper的配置和用法如下所示:
//See AutoMapper docs for where to put config, it shouldn't happen on every call
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<TheirApi.Error, MyNamespace.MyErrorDefinition>();
}
var mapper = config.CreateMapper();
MyErrorDefinition myErrors = mapper.Map<List<MyErrorDefinition>>(listOfTheirErrorObjects);
CheckErrors(myErrors);
另一種方法是使用lambda:
void CheckErrors<T>(IEnumerable<T> errors, Func<T,string> getMessage)
{
if (errors?.Count() > 0) throw new Exception(getMessage(errors.First()));
}
然后這樣稱呼它:
CheckErrors(errors, (e) => e.ErrorMessage);
我將定義自己的Error類,該類具有一個構造函數,該構造函數可以接受供應商提供的任何錯誤對象並將其轉換。 例如:
public class Error
{
public string Message { get; private set; }
public int ErrorNumber { get; private set; }
public Error(object vendorError)
{
var t = vendorError.GetType();
foreach (var source in t.GetProperties(BindingFlags.Instance | BindingFlags.Public))
{
foreach (var dest in typeof(Error).GetProperties(BindingFlags.Instance | BindingFlags.Public))
{
if (dest.Name != source.Name) continue;
if (dest.PropertyType != source.PropertyType) continue;
dest.SetValue(this, source.GetValue(vendorError, null));
}
}
}
}
然后,當您有第三方庫中的錯誤列表時,可以使用LINQ進行轉換:
var myErrorList = vendorErrorList.Select( e => new Error(e) );
現在,您可以按常規訪問屬性。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.