首页 > 解决方案 > 从 C# 中的泛型方法调用非泛型方法

问题描述

这类似于从泛型方法调用重载泛型方法这个问题,但它不一样:在这种情况下,方法返回void,而我需要返回泛型类型T,所以建议的解决方案不起作用。

我正在实现一个类似元组的类,它具有这些参数的通用参数和访问器:

public class MyClass<T1, T2>
{
    private readonly T1 _item1;
    private readonly T2 _item2;

    public MyClass(T1 item1, T2 item2)
    {
        _item1 = item1;
        _item2 = item2;
    }

    public T1 GetItem(T1 _) => _item1;

    public T2 GetItem(T2 _) => _item2;

    private T GetItem<T>(T x)
    {
        throw new ArgumentException();
        // return x;
    }

    public T Get<T>()
    {
        return GetItem(default(T));
    }
}

我想像这样使用这个类:

var obj = new MyClass<int, string>(1, "hello");
var a = obj.Get<int>();
var b = obj.Get<string>();

但是如果我尝试这个,T GetItem<T>(T x)总是调用泛型(抛出异常),而不是非泛型实现。

如果我尝试GetItem直接访问该方法,它会按预期工作:

var obj = new MyClass<int, string>(1, "hello");
var q = obj.GetItem(default(int));
var w = obj.GetItem(default(string));

q并按预期w包含1和。hello

有没有办法让我随心所欲地使用这个类(使用obj.Get<T>)?我想避免Item1 Item2 Item3吸气剂。

标签: c#generics

解决方案


但是如果我尝试这个,T GetItem<T>(T x)总是调用泛型(抛出异常),而不是非泛型实现。

那是因为重载决议发生在编译时,而在编译时,具体类型T是未知的。

有没有办法让我随心所欲地使用这个类(使用obj.Get<T>)?

使用普通的旧动态类型检查,确保:

public class MyClass<T1, T2>
{
    private readonly T1 _item1;
    private readonly T2 _item2;

    public MyClass(T1 item1, T2 item2)
    {
        _item1 = item1;
        _item2 = item2;
    }

    public T Get<T>()
    {
        if (typeof(T) == typeof(T1))
        {
            return (T)(object)_item1;
        } 
        
        if (typeof(T) == typeof(T2))
        {
            return (T)(object)_item2;
        }
        
        throw new InvalidOperationException();
    }
}

此解决方案的优点是边缘情况(T1 == T2,或 T 既不匹配 T1 也不匹配 T2)的行为被正确定义并且易于查看。


或者,您可以使用链接到的问题中使用的dynamic“hack”,您只需将结果转换为T: return (T)GetItem((dynamic)default(T));,这是一个工作小提琴

但这只是丑陋的,请不要这样做。将小提琴与上面的版本进行比较,并诚实地判断哪一个更易于阅读、更易于理解,因此更易于维护。


推荐阅读