如何在 .NET Core 6 中 return <T> 或 List<T>?
How to return either <T> or List<T> in .NET Core 6?
使用泛型和反射做一个 POST,然后处理 JSON,然后 return 正确的类型及其数据。
问题是我无法提前知道类型是单个对象还是对象列表。所以我的通用 return 类型需要是单个事物或单个事物的列表。 (这是 .NET Core 6,所以为什么在某些地方 !
...)
我该如何处理这个难题?
private static async Task<T> ProcessJsonResponse<TX>(HttpResponseMessage response,
string? returnModel = null)
{
var result = await response.Content.ReadAsStringAsync();
if (returnModel != null)
{
var type = Type.GetType(returnModel);
var obj = (T?)Activator.CreateInstance(type!);
var test = type!.GetMethod("FromJson");
object[] parametersArray = { result };
var tim = test!.Invoke(obj, parametersArray);
if (tim is List<T> nowwhat)
{
//can't return List<t> since the return type is T
}
return (T)tim!;
}
//<snip> other non-relevant code ...
}
此解决方案存在一些问题,难以推理。
此方法从动态语言 (JSON) 获取数据并将其转换为静态语言 (C#)。尽管泛型看起来像是动态的,但实际上并非如此。它们需要在编译时知道。
考虑到这一点,returnModel
论点只会让事情变得混乱。该方法最好不要使用它
这里最好的做法是在考虑类型之前弥合动态语言之间的差距。在这种情况下,这很简单,JSON 数组将以 '['
字符开头,因此系统可以根据
做出决定
正如@DiplomacyNotWar 所建议的,您需要一个 return 类型来封装两种类型的输出。 Sum 类型很棒,但我个人喜欢将它们留在函数世界中。相反,您可以 return 一个 List<T>
,它可以处理这两种情况
// 1. Return a List. This type can encapsulate both use cases
private static async Task<List<T>> ProcessJsonResponse<T>(HttpResponseMessage response, bool parseFromJson)
{
var result = await response.Content.ReadAsStringAsync();
// 2: find out what type you will need BEFORE you do anything type based
// this code is inefficient and buggy, but you get the gist
bool isArray = result.TrimStart()[0] == '[';
if (parseFromJson)
{
// 3. Have two completely separate execution paths for two different types
if (isArray)
{
// 4. Different method to original FromJsonList
var test = typeof(T)!.GetMethod("FromJsonList");
object[] parametersArray = { result };
// I am assuming that this will be a static method invoke
return (List<T>)test!.Invoke(null, parametersArray)!;
}
else
{
var obj = (T?)Activator.CreateInstance(typeof(T));
var test = typeof(T)!.GetMethod("FromJson");
object[] parametersArray = { result };
var tim = (T)test!.Invoke(obj, parametersArray)!;
return new List<T> { tim };
}
}
//<snip> other non-relevant code ... SHOLD
}
这就是我的想法 - 我将@Shane 的回答标记为正确,因为它让我走上了正确的轨道,让我看到了我做错了什么。这也不完整,因为需要更多的错误检查,但这比我最初写的要好得多。
private static async Task<List<T>> ProcessJsonResponse<TX>.
(HttpResponseMessage response, string? returnModel = null)
{
var result = await response.Content.ReadAsStringAsync();
if (result == "[]")
{
var obj = (T)Activator.CreateInstance(typeof(T));
return new List<T> { obj };
}
if (returnModel != null)
{
var token = JToken.Parse(result);
switch (token)
{
case JObject:
{
var returnObject = JsonConvert.DeserializeObject<T>(result);
return new List<T> { returnObject };
}
case JArray:
return JsonConvert.DeserializeObject<List<T>>(result);
}
}
var model = JsonConvert.DeserializeObject<T>(result);
Debug.Assert(model != null, nameof(model) + " != null");
return new List<T> { model };
}
使用泛型和反射做一个 POST,然后处理 JSON,然后 return 正确的类型及其数据。
问题是我无法提前知道类型是单个对象还是对象列表。所以我的通用 return 类型需要是单个事物或单个事物的列表。 (这是 .NET Core 6,所以为什么在某些地方 !
...)
我该如何处理这个难题?
private static async Task<T> ProcessJsonResponse<TX>(HttpResponseMessage response,
string? returnModel = null)
{
var result = await response.Content.ReadAsStringAsync();
if (returnModel != null)
{
var type = Type.GetType(returnModel);
var obj = (T?)Activator.CreateInstance(type!);
var test = type!.GetMethod("FromJson");
object[] parametersArray = { result };
var tim = test!.Invoke(obj, parametersArray);
if (tim is List<T> nowwhat)
{
//can't return List<t> since the return type is T
}
return (T)tim!;
}
//<snip> other non-relevant code ...
}
此解决方案存在一些问题,难以推理。
此方法从动态语言 (JSON) 获取数据并将其转换为静态语言 (C#)。尽管泛型看起来像是动态的,但实际上并非如此。它们需要在编译时知道。
考虑到这一点,
returnModel
论点只会让事情变得混乱。该方法最好不要使用它这里最好的做法是在考虑类型之前弥合动态语言之间的差距。在这种情况下,这很简单,JSON 数组将以
做出决定'['
字符开头,因此系统可以根据正如@DiplomacyNotWar 所建议的,您需要一个 return 类型来封装两种类型的输出。 Sum 类型很棒,但我个人喜欢将它们留在函数世界中。相反,您可以 return 一个
List<T>
,它可以处理这两种情况// 1. Return a List. This type can encapsulate both use cases private static async Task<List<T>> ProcessJsonResponse<T>(HttpResponseMessage response, bool parseFromJson) { var result = await response.Content.ReadAsStringAsync(); // 2: find out what type you will need BEFORE you do anything type based // this code is inefficient and buggy, but you get the gist bool isArray = result.TrimStart()[0] == '['; if (parseFromJson) { // 3. Have two completely separate execution paths for two different types if (isArray) { // 4. Different method to original FromJsonList var test = typeof(T)!.GetMethod("FromJsonList"); object[] parametersArray = { result }; // I am assuming that this will be a static method invoke return (List<T>)test!.Invoke(null, parametersArray)!; } else { var obj = (T?)Activator.CreateInstance(typeof(T)); var test = typeof(T)!.GetMethod("FromJson"); object[] parametersArray = { result }; var tim = (T)test!.Invoke(obj, parametersArray)!; return new List<T> { tim }; } } //<snip> other non-relevant code ... SHOLD }
这就是我的想法 - 我将@Shane 的回答标记为正确,因为它让我走上了正确的轨道,让我看到了我做错了什么。这也不完整,因为需要更多的错误检查,但这比我最初写的要好得多。
private static async Task<List<T>> ProcessJsonResponse<TX>.
(HttpResponseMessage response, string? returnModel = null)
{
var result = await response.Content.ReadAsStringAsync();
if (result == "[]")
{
var obj = (T)Activator.CreateInstance(typeof(T));
return new List<T> { obj };
}
if (returnModel != null)
{
var token = JToken.Parse(result);
switch (token)
{
case JObject:
{
var returnObject = JsonConvert.DeserializeObject<T>(result);
return new List<T> { returnObject };
}
case JArray:
return JsonConvert.DeserializeObject<List<T>>(result);
}
}
var model = JsonConvert.DeserializeObject<T>(result);
Debug.Assert(model != null, nameof(model) + " != null");
return new List<T> { model };
}