如何重构具有泛型返回类型的泛型方法的返回形状



我有一个名为Transfer的泛型方法,它也返回一个泛型类型。在Transfer的主体中,我进行了一些处理,得到了MessageBundle对象。如何以通用方式重建Transfer的返回类型(使用MessageBundle对象(?

我只能让它以非通用的方式工作。

namespace ConsoleApp
{
internal class Program
{
static void Main(string[] args)
{
//this works
var test = Transfer<(string? Result, string? Error)>();

//???
var test = Transfer<(int? Result, string? Error)>();
var test = Transfer<(bool? Result, string? Error)>();
var test = Transfer<(object? Result, string? Error)>();
}
public static U Transfer<U>()
{
//getting MessageBundle object
var bundle = new MessageBundle
{
Result = "hi",
Error = null
};
//How to reconstruct in generic way?
(string? Result, string? Error) response = (bundle.Result as string, bundle.Error);
return (U)Convert.ChangeType(response, typeof(U));
}
}
public class MessageBundle
{
public string? Error { get; set; }
public object? Result { get; set; }
}
}

编辑1:我无法控制Transfer方法的签名。

编辑2U(Transfer方法(的形状将是两个元素的元组(Error始终是字符串,而Result可以变化(

如果您事先知道U将是一个由2项组成的元组,但无法以任何方式更改public static U Transfer<U>()的签名(即使添加了ITuple约束(,则需要使用反射来构造元组。假设第一个元组参数是某种类型的.NET基元,并且Result的值是其字符串表示,则可以使用Convert.ChangeType()将字符串值转换为最终值。

一种方法是:

if (!typeof(ITuple).IsAssignableFrom(typeof(U))  // Assert it's a tuple
|| !(typeof(U).IsGenericType && typeof(U).GetGenericArguments() is var arguments && arguments.Length == 2) // Assert it has exactly two generic parameters
|| arguments[1] != typeof(string)) // Assert that the second parameter is a string
throw new ArgumentException(string.Format("Unexpected type {0}", typeof(U)));
var tuple = (U)Activator.CreateInstance(typeof(U), 
bundle.Result == null ? null : Convert.ChangeType(bundle.Result, Nullable.GetUnderlyingType(arguments[0]) ?? arguments[0]), 
bundle.Error)!;

注:

  • 您没有指定在Result转换失败的情况下应该发生什么,例如,您为Result指定了一个整数类型,但值是"hi"。如果发生这种情况,上面的实现将从Convert.ChangeType()中抛出一个异常。

  • 您也没有指定当Result对应于某个未实现IConvertible的复杂对象时应该发生什么。在这种情况下,上面的实现也会抛出异常。

  • Convert.ChangeType(object, Type)使用当前区域性进行转换。如果您想使用不变区域性(例如,因为您正在反序列化通过连线接收的值(,请使用ChangeType(Object, Type, CultureInfo.InvariantCulture):

    var tuple = (U)Activator.CreateInstance(typeof(U), 
    bundle.Result == null ? null : Convert.ChangeType(bundle.Result, Nullable.GetUnderlyingType(arguments[0]) ?? arguments[0], CultureInfo.InvariantCulture), 
    bundle.Error)!;
    
  • 你真的应该重新考虑这个设计。以这种方式使用反射几乎消除了所有编译时对代码正确性的检查。

在这里演示小提琴。

相关内容

  • 没有找到相关文章

最新更新