【问题标题】:Is there any simple method for assigning values from inside to list to a model?是否有任何简单的方法可以从内部分配值以列出模型?
【发布时间】:2021-12-25 18:07:44
【问题描述】:

我有两个这样的模型

public class ModelA
{
 public string Name{get;set;}
 public string Value{get;set;}
}

public class B
{
 public List<ModelA>Items{get;set;}
}

下面的输入将被反序列化到class B

{
  "Items":[
    {
      "Name":"Food Name"
      "Value":"Fries"
    },
    {
      "Name":"Weapon Name"
      "Value":"Gun"
    },
    {
      "Name":"Vehicle Name"
      "Value":"Car"
    }
  ]
}

我还有如下第三个模型

public class ModelValues
{
 public string FoodName{get;set;}
 public string WeaponName{get;set;}
 public string VehicleName{get;set;}
}

我想将 model A 的相应值添加到 ModelValues 类中,就像 FoodName 属性的值应该是 Fries。是否有任何简单的方法可以将该 class A 的值分配给 ModelValues。 我知道我们可以使用类似的东西

public void AssignValues(B products)
{
 ModelValues values=new ModelValues();
 values.FoodName=products.Find(x=>x.Name=="Food Name").Value;
 values.WeaponName=products.Find(x=>x.Name=="Weapon Name").Value;
}

在实际实现中,由于 ModelValues 中的项目和输入会很大,我希望避免这种逐行分配值。有没有什么办法只用几行代码就可以完成这项工作

【问题讨论】:

  • 您可以尝试使用AutoMapper库并创建类型之间的映射配置
  • 您可以使用自动映射器。或者,为了好玩,你可以做你自己的事。可以说,声明MappingPropertyAttribute。然后在所有模型上,您可以列出属性映射到的所有名称 - MappingProperty("prop1", "prop2")。然后有任何型号的扩展名,如model1.HydrateTo(model2)。您的代码将填充匹配名称和数据类型的属性。或者你甚至可以尝试转换一些数据类型。
  • 你能把json数据比如Food Name改成FoodName吗?
  • 既然B 旨在用作查找,请将其设为Dictionary&lt;Tkey,TValue&gt; 以使查找更快更自然。
  • @Saeed Esmaeelinejad 无法更改 json 数据,因为我是从外部来源获取的

标签: c# .net


【解决方案1】:

我会质疑你目前的做法。当您最终可以添加任意数量的属性时,集合可能是更好的选择。甚至可能是一本字典。

但是,以下方法将按照您想要的方式复制值。这不是最快的方法。但即使您添加其他名称和属性,它仍会继续工作。

void Convert(B items, ModelValues values)
{
    Type type = typeof(ModelValues);
    
    foreach (ModelA item in items.Items)
    {
        string name = item.Name.Replace(" ", string.Empty);
        PropertyInfo info = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public);
        if (info != null)
            info.SetValue(values, item.Value);
    }
}

【讨论】:

  • 如果 ModelValues 是一个具有无限数量的未知属性的动态对象,这可能会有一些意义。但是对于 3 个属性,具体代码会更有效。您可以为 2 行代码节省几分钟,但这与此无关。 OP 已经浪费了一整天了,他可以在这段时间内为一百个属性创建一个具体的、非常有效的代码
  • @Serge:是的,但他说房产的数量可能会更多。对于处理任意数量属性的单个方法,这种方法可以工作。就个人而言,我会审查设计并考虑另一种方法。
  • 不管你有多少个属性,具体的代码总是更有效。仅当您没有其他选择时才需要动态代码,因为您不知道属性的名称。但据我了解, ModelValues 属性始终是已知的。编译器总是将动态属性转换为具体属性。您只能节省编写代码的时间,但在此之后您将在运行时损失更多。
  • @Serge:我不认为我的方法是最有效的,但它会总是在添加属性时工作。它不需要保持最新。许多库都使用反射,就像您的示例中的 JsonConvert 调用一样。是的,ModelValues 属性是已知的。但它仍然需要有人在每次添加新值时保持最新状态。因此,它更容易出错。我不明白你为什么如此反对这种方法。你是否同样​​担心JsonConvert 使用这样的反射?
  • 是的,我同意,我可以使用解析而不是转换。我使用它只是因为 OP 使用它并且他已经为此创建了类。但是,如果它已经由 OP 创建,那么类型化对象总是更好。
【解决方案2】:

Newtonsoft.Json 用法的另一种变体:

public class ModelValues
{
    [JsonProperty("Food Name")]
    public string FoodName { get; set; }

    [JsonProperty("Weapon Name")]
    public string WeaponName { get; set; }

    [JsonProperty("Vehicle Name")]
    public string VehicleName { get; set; }
}

var items = JsonConvert.DeserializeObject<B>(json)
                       .Items
                       .ToDictionary(x => x.Name, x => x.Value);

JObject obj = JObject.FromObject(items);
var values = obj.ToObject<ModelValues>();

或者不改变 ModelValues:

var items = JsonConvert.DeserializeObject<B>(json)
                       .Items
                       .ToDictionary(x => x.Name.Replace(" ", ""), x => x.Value);

JObject obj = JObject.FromObject(items);
var values = obj.ToObject<ModelValues>();

【讨论】:

  • 这假设他可以从 JSON 直接序列化到 ModelValues 类。我没看到他在哪里说的。
【解决方案3】:

您的代码进行了 3 次列表迭代。这段代码只有一个

var items = Newtonsoft.Json.JsonConvert.DeserializeObject<B>(json);
var values = AssignValues(items);

public ModelValues AssignValues(B products)
{
    ModelValues values = new ModelValues();
    foreach (var item in products.Items)
    {
        if (item.Name == "Food Name") values.FoodName = item.Value;
        else if (item.Name == "Weapon Name") values.WeaponName = item.Value;
        else values.VehicleName = item.Value;
    }
    return values;
}

我认为这不是一个好主意,但您可以使用反射来做同样的事情

public ModelValues AssignValues(B products)
{
   var dict=products.Items.ToDictionary(i => i.Name, i=> i.Value );

   var values = new ModelValues();
    var properties = values.GetType().GetProperties();
    
    foreach (var prop in properties)
    {
         var name=prop.Name.Replace("Name"," Name");
         prop.SetValue(values,dict[name] );
    }
    return values;
}

【讨论】:

  • 这段代码的问题是,随着我在 ModelValues 模型中的项目和输入的增加,这段代码会变得更大。我将不得不处理大量具有更大数据的 if 条件。所以我正在寻找一些东西来优化这段代码。
  • @ANK 您的代码进行了 3 次列表迭代。这段代码只有一个
  • 确实如此。有什么办法可以避免 if 条件?只是当我的课程中的项目增加时,我将不得不放置很多 if 条件,这是我希望尽可能避免的事情
  • @ANK 如果条件非常快速和简单并且不占用马赫资源。 Linq 也会将代码转换为 foreach 循环。所以最好从一开始就使用循环。但是如果您考虑使用映射器,那么您应该知道使用反射的映射器和您的代码会慢一千倍。
  • @ANK:很难想象你为什么需要这个设计。随着 ModelValues 的增长,您将继续向其添加属性。收藏不是更好的方法吗? Dictionary&lt;&gt; 可能吗?
猜你喜欢
  • 1970-01-01
  • 2015-07-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多