【发布时间】:2020-10-16 07:42:30
【问题描述】:
我正在使用 C# 中的 Post 端点,我想让所有字段都是可选的,但也想将其更新为空/空列表。我知道这是非常奇怪的要求。我可以将 int 和 string 数据类型设置为 -1 或一些默认字符串,但我发现 List 或任何数据列表都有困难。
我可以为条件更新添加任何额外的标志,但这会增加请求正文中的属性数量。
如果有人遇到过类似的问题,谁能建议我解决这种情况。我知道解决方案会很棘手。
【问题讨论】:
我正在使用 C# 中的 Post 端点,我想让所有字段都是可选的,但也想将其更新为空/空列表。我知道这是非常奇怪的要求。我可以将 int 和 string 数据类型设置为 -1 或一些默认字符串,但我发现 List 或任何数据列表都有困难。
我可以为条件更新添加任何额外的标志,但这会增加请求正文中的属性数量。
如果有人遇到过类似的问题,谁能建议我解决这种情况。我知道解决方案会很棘手。
【问题讨论】:
抱歉耽搁了。
让我试着用更多的代码来解释它。
首先,我们使用从 JSON 字符串中提取的数据填充通用对象的通用方法。
public static void FillObjectFromJson<T>(T objectToFill, string objectInJson)
where T : class
{
// Check parameters
if (objectToFill == null) throw new ArgumentNullException(nameof(objectToFill));
if (string.IsNullOrEmpty(objectInJson)) throw new ArgumentNullException(nameof(objectInJson));
// Deserialize in a typed object (helpful for the type converter)
var typed = JsonConvert.DeserializeObject<T>(objectInJson);
// Deserialize in an expando object (for check properties)
var expando = JsonConvert.DeserializeObject<ExpandoObject>(objectInJson);
// Converts the expando to dictionary for check all given properties
var dictionary = (IDictionary<string, object>)expando;
// Read all properties of the given object (the only one you can assign)
foreach (var property in typeof(T).GetProperties().Where(x => x.CanWrite))
{
// If dictionary contains the property, it was in the JSON string,
// so we have to replace it
if (dictionary.ContainsKey(property.Name))
{
var propValue = property.GetValue(typed);
property.SetValue(objectToFill, propValue);
}
}
}
就性能而言,它并不是最好的,因为我们将相同的 JSON 反序列化了两次:
我这样做是因为我们在属性类型方面可能会遇到一些问题。在此示例中,在 ExpandoObject 中,Age 属性的类型为 int64 而不是 int32。因此,如果我们只想反序列化 JSON 一次,那么我们需要转换属性。 随意更改此代码。
现在我们有了一个泛型方法,尝试在示例中使用它。
首先,我们需要一个类来使用:
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
// This method is used only for this example, just for write data to the console
public override string ToString()
{
return $"Name: {Name} - Age: {Age}";
}
}
然后我们需要一种方法来从存储中提取要更新的数据。在本例中,我们将简单地支持一个对象:
public static Person ReadPersonFromStorage()
{
return new Person
{
Name = "Name from storage",
Age = 44
};
}
最后,我们可以编写我们的测试方法了:
// Example of JSON with explicit name (so we have to set it as null)
var personWithNameJson = "{ \"Name\" : null, \"Age\" : 24 }";
// Read the original value from the storage
var person = ReadPersonFromStorage();
Console.WriteLine(person); // We have the name
// Fills from JSON (it will replace the Name since it's in the JSON)
FillObjectFromJson(person, personWithNameJson);
Console.WriteLine(person); // The name is set to null
// Example of JSON without explicit name (so you have to leave it with the original value)
var personWithoutNameJson = "{ \"Age\" : 24 }";
// Read the original value from the storage
var otherPerson = ReadPersonFromStorage();
Console.WriteLine(otherPerson); // We have the name
// Fills from JSON (it won't replace the Name since it's NOT in the JSON)
FillObjectFromJson(otherPerson, personWithoutNameJson);
Console.WriteLine(otherPerson); // We still have the name since it's not in the JSON
我希望我的意思更清楚,更好的是,我会帮助你。
PS:对于这个示例,我使用 Newtonsoft 进行 JSON 反序列化。
【讨论】:
如果您同时控制客户端和服务器,则可以使用请求的格式对其进行管理。
假设你有一个像这样的对象:
public class Customer {
public string Name { get; set; }
public int? Age { get; set; }
}
然后你可以管理两种请求。我将使用 JSON 格式进行解释。
{
"Name": null,
"Age": 12
}
在这种情况下,请求包含值“Name”,因此您将在数据库(或任何其他存储)中将其设置为 null
{
"Age": 12
}
在这种情况下,请求不包含值“名称”,因此 ti 表示它没有被更改。
对于 JSON 格式,两个请求相同(Name = null)。但在您的代码中,它们将以不同的方式工作。
当然:
【讨论】: