通过 JsonProperty 属性值将对象列表投影到另一种类型
Projecting list of objects into another type by JsonProperty attribute value
我有以下型号:
class CheckResponse
{
public ICollection<CheckModel> Checks { get; set; }
}
public class CheckModel
{
[JsonConverter(typeof(StringEnumConverter))]
public CheckCodes CheckCode { get; set; }
[JsonConverter(typeof(StringEnumConverter))]
public ResultCode ResultCode { get; set; }
}
public enum CheckCodes
{
FirstCheck,
SecondCheck,
ThirdCheck,
}
public enum ResultCode
{
Failure,
Success,
Warning
}
我需要将 Checks
转换成 CheckList
:
class CheckList
{
[JsonProperty(nameof(CheckCodes.FirstCheck))]
public bool FirstCheckPassed { get; set; }
[JsonProperty(nameof(CheckCodes.SecondCheck))]
public bool SecondCheckPassed { get; set; }
[JsonProperty(nameof(CheckCodes.ThirdCheck))]
public bool ThirdCheckPassed { get; set; }
}
示例:
class Program
{
static void Main(string[] args)
{
var response = GetResponse();
var checkResponse = JsonConvert.DeserializeObject<CheckResponse>(response);
// var checkList = ?
}
static string GetResponse() => @"{
'checks': [
{
'checkCode': 0,
'resultCode': 1
},
{
'checkCode': 1,
'resultCode': 2
},
{
'checkCode': 2,
'resultCode': 0
}
]}";
}
如果 resultCode
等于 2 (ResultCode.Warning
) 则应该通过检查。
因此,checkList
应具有以下属性值:
FirstCheckPassed = true
SecondCheckPassed = true
ThirdCheckPassed = false
更新:
我的解决方案如下:
static void Main(string[] args)
{
Test();
}
static IEnumerable<string> Yield(ICollection<CheckModel> checks)
{
foreach (var check in checks)
{
var success = check.ResultCode == ResultCode.Success || check.ResultCode == ResultCode.Warning;
yield return "'" + check.CheckCode.ToString() + "': '" + success.ToString() + "'";
}
}
static void Test()
{
var response = GetResponse();
var checkResponse = JsonConvert.DeserializeObject<CheckResponse>(response);
var o = "{" + string.Join(",", Yield(checkResponse.Checks)) + "}";
var checkList = JsonConvert.DeserializeObject<CheckList>(o);
}
但我不确定这是最好的(实际上,我认为它有点丑)。有没有更好的方法?
您可以像这样向您的 CheckResponse
class 添加一个方法(请注意,这也可以是一个扩展方法,或者通常移动到其他地方以将代码排除在您的模型之外)
public bool CheckPassed(CheckCodes check)
{
//default to failure if there isn't a matching check
var result = Checks.FirstOrDefault(x => x.CheckCode == check)?.ResultCode ?? ResultCode.Failure;
return result != ResultCode.Failure;
}
然后您可以在创建 CheckList
时使用该方法
static void Main()
{
var response = GetResponse();
var checkResponse = JsonConvert.DeserializeObject<CheckResponse>(response);
var checkList = new CheckList
{
FirstCheckPassed = checkResponse.CheckPassed(CheckCodes.FirstCheck),
SecondCheckPassed = checkResponse.CheckPassed(CheckCodes.SecondCheck),
ThirdCheckPassed = checkResponse.CheckPassed(CheckCodes.ThirdCheck)
};
}
您可以创建自己的 JsonConverter,通过对 POCO 进行额外更改,您可以反序列化为您想要的确切对象。
小改成CheckResponse
class CheckResponse
{
[JsonConverter(typeof(CheckModelConverter))]
public CheckList Checks { get; set; }
}
添加自定义转换器
public class CheckModelConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
throw new NotImplementedException();
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var obj = serializer.Deserialize<CheckModel[]>(reader);
var result = new CheckList();
foreach (var item in obj)
{
bool resultValue = item.ResultCode != ResultCode.Failure;
switch (item.CheckCode)
{
case CheckCodes.FirstCheck:
result.FirstCheckPassed = resultValue;
break;
case CheckCodes.SecondCheck:
result.SecondCheckPassed = resultValue;
break;
case CheckCodes.ThirdCheck:
result.ThirdCheckPassed = resultValue;
break;
default:
throw new Exception("No checkcode of " + item.CheckCode);
}
}
return result;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
披露:我更喜欢将其实际反序列化为确切的模型,然后才将其(或其中的一部分)映射到我想要的类型,这为我提供了更多的未来灵活性并保留了实际的模型结构。
编辑: 修复了 Disclosure 中的拼写问题。
我有以下型号:
class CheckResponse
{
public ICollection<CheckModel> Checks { get; set; }
}
public class CheckModel
{
[JsonConverter(typeof(StringEnumConverter))]
public CheckCodes CheckCode { get; set; }
[JsonConverter(typeof(StringEnumConverter))]
public ResultCode ResultCode { get; set; }
}
public enum CheckCodes
{
FirstCheck,
SecondCheck,
ThirdCheck,
}
public enum ResultCode
{
Failure,
Success,
Warning
}
我需要将 Checks
转换成 CheckList
:
class CheckList
{
[JsonProperty(nameof(CheckCodes.FirstCheck))]
public bool FirstCheckPassed { get; set; }
[JsonProperty(nameof(CheckCodes.SecondCheck))]
public bool SecondCheckPassed { get; set; }
[JsonProperty(nameof(CheckCodes.ThirdCheck))]
public bool ThirdCheckPassed { get; set; }
}
示例:
class Program
{
static void Main(string[] args)
{
var response = GetResponse();
var checkResponse = JsonConvert.DeserializeObject<CheckResponse>(response);
// var checkList = ?
}
static string GetResponse() => @"{
'checks': [
{
'checkCode': 0,
'resultCode': 1
},
{
'checkCode': 1,
'resultCode': 2
},
{
'checkCode': 2,
'resultCode': 0
}
]}";
}
如果 resultCode
等于 2 (ResultCode.Warning
) 则应该通过检查。
因此,checkList
应具有以下属性值:
FirstCheckPassed = true
SecondCheckPassed = true
ThirdCheckPassed = false
更新:
我的解决方案如下:
static void Main(string[] args)
{
Test();
}
static IEnumerable<string> Yield(ICollection<CheckModel> checks)
{
foreach (var check in checks)
{
var success = check.ResultCode == ResultCode.Success || check.ResultCode == ResultCode.Warning;
yield return "'" + check.CheckCode.ToString() + "': '" + success.ToString() + "'";
}
}
static void Test()
{
var response = GetResponse();
var checkResponse = JsonConvert.DeserializeObject<CheckResponse>(response);
var o = "{" + string.Join(",", Yield(checkResponse.Checks)) + "}";
var checkList = JsonConvert.DeserializeObject<CheckList>(o);
}
但我不确定这是最好的(实际上,我认为它有点丑)。有没有更好的方法?
您可以像这样向您的 CheckResponse
class 添加一个方法(请注意,这也可以是一个扩展方法,或者通常移动到其他地方以将代码排除在您的模型之外)
public bool CheckPassed(CheckCodes check)
{
//default to failure if there isn't a matching check
var result = Checks.FirstOrDefault(x => x.CheckCode == check)?.ResultCode ?? ResultCode.Failure;
return result != ResultCode.Failure;
}
然后您可以在创建 CheckList
static void Main()
{
var response = GetResponse();
var checkResponse = JsonConvert.DeserializeObject<CheckResponse>(response);
var checkList = new CheckList
{
FirstCheckPassed = checkResponse.CheckPassed(CheckCodes.FirstCheck),
SecondCheckPassed = checkResponse.CheckPassed(CheckCodes.SecondCheck),
ThirdCheckPassed = checkResponse.CheckPassed(CheckCodes.ThirdCheck)
};
}
您可以创建自己的 JsonConverter,通过对 POCO 进行额外更改,您可以反序列化为您想要的确切对象。
小改成CheckResponse
class CheckResponse
{
[JsonConverter(typeof(CheckModelConverter))]
public CheckList Checks { get; set; }
}
添加自定义转换器
public class CheckModelConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
throw new NotImplementedException();
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var obj = serializer.Deserialize<CheckModel[]>(reader);
var result = new CheckList();
foreach (var item in obj)
{
bool resultValue = item.ResultCode != ResultCode.Failure;
switch (item.CheckCode)
{
case CheckCodes.FirstCheck:
result.FirstCheckPassed = resultValue;
break;
case CheckCodes.SecondCheck:
result.SecondCheckPassed = resultValue;
break;
case CheckCodes.ThirdCheck:
result.ThirdCheckPassed = resultValue;
break;
default:
throw new Exception("No checkcode of " + item.CheckCode);
}
}
return result;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
披露:我更喜欢将其实际反序列化为确切的模型,然后才将其(或其中的一部分)映射到我想要的类型,这为我提供了更多的未来灵活性并保留了实际的模型结构。
编辑: 修复了 Disclosure 中的拼写问题。