2017-09-14 144 views
-1

我有以下列表,其中包含字段名稱和值。.NET - 將/映射列表轉換爲對象,反之亦然

public class FormField 
{ 
    public string FieldName { get; set;} 
    public string FieldValue { get; set;} 
} 

var formData = new List<FormField>(); 
formData.Add(new FormField { FieldName = "Date", FieldValue = "2017-09-14" }); 
formData.Add(new FormField { FieldName = "Name", FieldValue = "Job blogs" }); 
formData.Add(new FormField { FieldName = "IsEnabled", FieldValue = "true" }); 

如何將列表轉換或映射到以下類中?注意FieldNames映射到類的屬性。

public class MyViewModel 
{ 
    [Required] 
    public DateTime Date { get; set; } = DateTime.now; 

    [Required] 
    public string Name { get; set; } 

    public boolean IsEnabled { get; set; } 

    public IEnumerable<SelectListItem> Titles 
    { 
     get 
     { 
      var options = new List<SelectListItem> 
      { 
       new SelectListItem(){ Value = "Mr", Text = "Mr" }, 
       new SelectListItem(){ Value = "Mrs", Text = "Mrs" }      
      }; 

      return options; 
     } 
    } 
} 

任何幫助表示讚賞。我需要以某種方式序列化列表嗎? automapper能做到這一點嗎?

* UPDATE *

我嘗試以下,但儘管automapper文檔它不工作,說明你可以從字典直接去反對:

public class MappingProfile : Profile 
{ 
    public MappingProfile() 
    { 
     CreateMap<Dictionary<string, object>, MyViewModel>(); 
    } 
} 

var viewModel = Mapper.Map<MyViewModel>(formData.ToDictionary(x => x.FieldName, x => (object) x.FieldValue)) 

注:記錄我m使用automapper v 5.0.2

我也需要從對象返回到字典,但能夠排除屬性,如public IEnumerable<SelectListItem> Titles {get;}

+2

是Automapper可以執行此操作,或者如果您希望避免開銷,則可以通過傳遞FormField的對象作爲參數,手動映射MyViewModel的構造函數中的值Automapper。 – TechGirl

+0

@TechGirl任何代碼來協助?在構造函數中映射將不是理想的。 – adam78

+0

@TechGirl,真的嗎?我非常懷疑這一點。 –

回答

0

你可以使用反射來獲取和好像你正試圖創建一個包含字段的動態數字,就像ViewBag對象模型

var formData = new List<FormField>(); 
formData.Add(new FormField { FieldName = "Date", FieldValue = "2017-09-14" }); 
formData.Add(new FormField { FieldName = "Name", FieldValue = "Job blogs" }); 
formData.Add(new FormField { FieldName = "IsEnabled", FieldValue = "true" }); 

// Initialize a new instance of the model 
MyViewmodel model = new MyViewmodel(); 
// Get its property info 
PropertyInfo[] properties = model.GetType().GetProperties(); 
// Loop through your form field data 
foreach(var field in formData) 
{ 
    // Get the matching property name 
    PropertyInfo pi = properties.FirstOrDefault(x => x.Name == field.FieldName); 
    if (pi == null) 
    { 
     continue; 
    } 
    // Convert the value to match the property type 
    object value = Convert.ChangeType(field.FieldValue, pi.PropertyType); 
    // Set the value of the property 
    pi.SetValue(model, value); 
} 
+0

使用中間序列化,請參閱以下內容。在這個例子中,我會將列表轉換成字典 - (https:// stackoverflow。com/questions/7310533/dictionary-string-string-map-to-an-object-using-automapper) – adam78

+0

以及Darin所說的 - _你可以作弊,並且會涉及額外的開銷代碼和開銷 –

+0

實際上額外的開銷只會如果使用AutoMapper,可能不需要。 –

0

如果屬性名稱匹配,AM可以默認從IDictionary<string, object>(或DynamicObject)映射到任何目標。所以你需要從你的結構映射到字典,LINQ可能最適合,然後到你的目的地。 docstests

+0

類似於https://stackoverflow.com/questions/45618005/automapper-list-to-members/45618145#45618145。 –

+0

以下不起作用:'var viewModel = Mapper.Map ,MyViewmodel>(formData.ToDictionary(x => x.FieldName,x => x.FieldValue))' – adam78

+0

錯誤。 '''IDictionary '''。 –

1

設置了匹配屬性。你不需要映射這個。這已經由.NET提供,通過ExpandoObject,DynamicObject類和dynamic關鍵字提供。

相反建設領域和值的列表,創建一個ExpandoObject和字段添加到它,就像你會與ViewBag:

dynamic formData=new ExpandoObject(); 
formData.Name = "Job blogs"; 
formData.Date = DateTime.Today; 
formData.IsEnabled = true; 
formData.Titles = new []{ 
          new SelectedListeItem{Text="Mr",Value="Mr"}, 
          new SelectedListeItem{Text="Mrs",Value="Mrs"} 
         }; 

您可以使用該對象爲您的視圖模型,就像ViewBag。

// Controller 

public ActionResult Index(..) 
{ 
    .... 
    View(formData); 
} 


//View 
@model dynamic 

<h1>@Model.Name</h1> 

更新 - 爲Expando從字段列表

ExpandoObject工具IDictionary<string, object>明確,這意味着可以在不知道自己的號碼或者在運行時的名稱,如性質:

var fields = new (string name,object value) [] 
      { 
         ("Name","Job blogs"), 
         ("Date", DateTime.Today), 
         ("IsEnabled",true) 
      }; 

dynamic viewModel=new ExpandoObject(); 
var dict=(IDictionary<string,object>)viewModel; 
foreach(var field in fields) 
{ 
    dict.Add(field.name,field.value); 
} 

我m使用tuple syntaxt只是爲了避免重複輸入FormField

UPDATE 2 - 帶字典存儲的強類型化

正如Stephen Muecke所評論的那樣,使用動態類進行綁定和驗證比較困難。另一方面,如果事先知道這些字段,爲什麼要使用映射或反射呢?

可以創建一個ViewModel類,它接受一些文件,將它們轉換爲字典(類似於ExpandoObject所做的),並將該字典用作屬性的後備存儲。

有一點像CallMemberName屬性的C#魔法,額外的代碼是最小的。有運行時罰字典查找,只如果有很多讀取/的寫道變得很明顯:

class MyViewModel 
{ 
    Dictionary<string,object> _dict=new Dictionary<string,object>(); 

    //Get helper 
    private T getter<T>([CallerMemberName]string name=null) 
    { 
     return _dict.TryGetValue(name,out object value) 
      ? (T)Convert.ChangeType(value,typeof(T)) 
      : default(T);    
    } 

    private void setter(object value,[CallerMemberName]string name=null) 
    { 
     _dict[name]=value; 
    } 

    public DateTime Date { 
     get => getter<DateTime>();    
     set => setter(value); 
    }    
    public string Name { 
     get => getter<string>();    
     set => setter(value); 
    } 
    public bool IsEnabled { 
     get => getter<bool>();    
     set => setter(value); 
    } 

    public MyViewModel(IEnumerable<FormField> fields) 
    { 
     _dict=fields.ToDictionary(
         field=>field.FieldName, 
         field=>(object)field.FieldValue); 
    } 

} 

.... 

var formData = new [] { 
    new FormField { FieldName = "Date", FieldValue = "2017-09-14" }, 
    new FormField { FieldName = "Name", FieldValue = "Job blogs" }, 
    new FormField { FieldName = "IsEnabled", FieldValue = "true" } 
}; 

var myViewModel = new MyViewModel(formData); 

每個屬性的setter方法只是將使用屬性的名稱作爲一個字典值鍵。獲取者使用CallerMemberName獲取屬性的名稱並將其用作關鍵字

+0

字段名稱和值的列表實際上是通過webservice作爲數組檢索的,因此我無權創建expando對象 – adam78

+0

@ adam78爲什麼不呢?您可以在循環中添加名稱。通過從DynamicObject派生,你可以添加一個實際讀取數組 –

+0

@adam78的構造函數,重要的是你不需要映射。您只需構建一個動態對象。 –

相關問題