如何在 .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 ...
    }

此解决方案存在一些问题,难以推理。

  1. 此方法从动态语言 (JSON) 获取数据并将其转换为静态语言 (C#)。尽管泛型看起来像是动态的,但实际上并非如此。它们需要在编译时知道。

  2. 考虑到这一点,returnModel 论点只会让事情变得混乱。该方法最好不要使用它

  3. 这里最好的做法是在考虑类型之前弥合动态语言之间的差距。在这种情况下,这很简单,JSON 数组将以 '[' 字符开头,因此系统可以根据

    做出决定
  4. 正如@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 };
    }