2014-10-02 57 views
3
var _Contact = new ContactLstModel { 
      ContactName="xxxxxx", 
       EmailAddr="yyyyyy", 
       ContactNo="ddddddd", 
       SelectedContactType="dddd" 
      }; 

var _ContactOption= new ContactLstModel{ 
       ContactType= new List<SelectListItem>(){ 
       new SelectListItem{ 
        Text="sss",Value="ddd" 
       } 
       } 
      }; 

正如你可以看到兩者都是相同的型號ContactLstModel。現在我該如何將兩者結合爲一體?在c#中有jQuery的擴展嗎?

像jQuery的,我們有$.extend(dest,source);

有沒有在C#中的等價?

回答

6

在C#和.NET 4.5中沒有內置的$ .extend。

但是,您可以找到許多人在.NET中使用reflection來嘗試實現這種行爲的示例。還有其他人使用序列化(JSON.NET等)來實現類似的行爲。另一種方法是使用IOC容器,如Automapper

下面是一個例子如何將您的第一個對象合併到使用Automapper IOC第二個目的:

var expr = Mapper.CreateMap<ContactLstModel, ContactLstModel>().ForMember("ContactType", (conf) => { conf.Ignore(); }); 
var merged = Mapper.Map<ContactLstModel, ContactLstModel>(_Contact, _ContactOption); 

隨着Automapper您可以控制到每一單財產來源映射到目的地。

如果您不需要外部庫依賴項,並且想要完全控制,則可以使用純粹的反射方法。

例如,您可以使用與此link中的CopyValues方法類似的內容,並使用反射將第二個對象屬性與第一個對象屬性合併。

CopyValues<ContactLstModel>(_Contact, _ContactOption); 

所以這行代碼會將第二個對象的ContactType屬性值複製到第一個對象中。

CopyValues使用反射來循環通過所述對象的屬性:

public static void CopyValues<T>(T target, T source) 
    { 
     Type t = typeof(T); 

     var properties = t.GetProperties().Where(prop => prop.CanRead && prop.CanWrite); 

     foreach (var prop in properties) 
     { 
      var value = prop.GetValue(source, null); 
      if (value != null) 
       prop.SetValue(target, value, null); 
     } 
    } 

當然,這不支持一切jquery的延伸不會(匯合,淺和深克隆到一個新的對象等),但它可以滿足您目前的需求。您可以根據這些原則進行擴展並構建更全面的解決方案。

但是請記住,C#不是像JavaScript這樣的語言,並且在C#中進行反射的成本要高得多,而在Javascript中,原型的屬性可以通過廉價的迭代或通過調用Object.keys()。

+0

反射比(以托馬斯Lycken答案等)專用於特定對象的方法要慢一點,讓較少的控制,但它實現了最通用的方法這個。 – AFract 2014-10-02 08:26:11

+0

是的。 JQuery擴展自動合併屬性而不指定名稱,所以基於反射的方法可能是他可以獲得的最接近這種功能的方法。 – 2014-10-02 08:33:30

+0

這很酷,很容易理解,謝謝你 – Irshu 2014-10-02 14:55:24

3

您可以用擴展方法做到這一點:

public static class ContactModelExtensions { 
    public static ContactModel Extend(this ContactModel first, ContactModel replacement) { 
     if (!replacement.ContactsName.IsNullOrEmpty()) // or whatever criteria you want 
     { 
      first.ContactsName = replacement.ContactsName; 
     } 
     // similar assignment for all other properties 

     return first; // since we return the first one, properties not set in override 
         // will be untouched 
    } 
} 

現在,你可以

var extendedContact = _Contact.Extend(_ContactOptions); 

把它完成。

+0

尼斯的命題,而且比反射快,但這個具體的例子,因爲「覆蓋」肯定不會編譯是保留關鍵字。我建議編輯它。 – AFract 2014-10-02 08:27:41

+0

@理查德:謝謝。這就是我得到沒有測試它輸入代碼了我的頭,我想:P – 2014-10-02 08:32:58

2

你可以使用一些框架來做到這一點。例如與ValueInjecter

public class NoNullsInjection : ConventionInjection 
    { 
     protected override bool Match(ConventionInfo c) 
     { 
      return c.SourceProp.Name == c.TargetProp.Name 
        && c.SourceProp.Value != null; 
     } 
    } 

    class A 
    { 
     public string a { get; set; } 
     public string b { get; set; } 
    } 

    static void Main(string[] args) 
    { 
     A a1 = new A() { a = "123" }; 
     A a2 = new A() { b = "456" }; 
     A c = new A(); 

     c.InjectFrom(new NoNullsInjection(),a1,a2); 
     // "c" now have a="123", b="456"  

    }