簡體   English   中英

如何在C#中處理多個相同的類

[英]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) );

現在,您可以按常規訪問屬性。

參見我在DotNetFiddle上的示例

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM