我有以下列表,其中包含字段名称和值。
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文档说明你可以直接从字典转到对象:
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))
注意:对于记录我使用的是automapper v 5.0.2
我还需要从对象返回到字典,但能够排除public IEnumerable<SelectListItem> Titles {get;}
答案 0 :(得分:1)
您似乎正在尝试创建一个包含动态数量字段的对象,例如ViewBag。您不需要为此进行映射。这已经由.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"}
};
您可以将该对象用作ViewModel,就像ViewBag一样。
// Controller
public ActionResult Index(..)
{
....
View(formData);
}
//View
@model dynamic
<h1>@Model.Name</h1>
更新 - 从字段列表中展开
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);
}
我正在使用元组syntaxt来避免重复输入FormField
更新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只使用属性的名称作为键来设置字典值。 getter使用CallerMemberName
获取属性的名称并将其用作键
答案 1 :(得分:0)
AM可以默认从IDictionary<string, object>
(或DynamicObject)映射到任何目标。所以你需要从你的结构映射到字典,LINQ可能最适合,然后到你的目的地。 docs和tests。
答案 2 :(得分:0)
您可以使用反射来获取和设置模型中的匹配属性
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);
}