在C#中为没有继承的泛型类创建一个具体构造函数

本文关键字:一个 构造函数 创建 泛型类 继承 | 更新日期: 2023-09-27 18:21:30

是否可以为泛型类提供构造函数,使该类在没有继承的情况下成为非泛型?

namespace MathParser.Calculation
{
    using System;
    using System.Globalization;
    class Stackoverflow<T>
    {
        private Func<IConvertible, IFormatProvider, T> convertValue;
        private Func<T, T, T> op;
        public Stackoverflow(Func<IConvertible, IFormatProvider, T> ToGenericValue, Func<T, T, T> opGeneric)
        {
            this.convertValue = ToGenericValue;
            this.op = opGeneric;
        }
        /* This is what i want to write
        public Stackoverflow(Func<Int64, Int64, Int64> opGeneric) where T : Int64
        {
            this.convertValue = (val, f) => { return val.ToInt64(f); };
            this.op = opGeneric;
        }
        */
        public T operation<K>(K a, K b) where K : IConvertible
        {
            T aAsT = this.convertValue(a, CultureInfo.InvariantCulture);
            T bAsT = this.convertValue(b, CultureInfo.InvariantCulture);
            return op(aAsT, bAsT);
        }
    }
    class Caller
    {
        public void call(Int64 a, Int64 b)
        {
            var op1 = new Operation<Int64>(
                (val, f) => { return val.ToInt64(f); }, //repeated
                (x, y) => { return x / y; }
                );
            var op2 = new Operation<Int64>(
                (val, f) => { return val.ToInt64(f); }, //repeated
                (x, y) => { return x + y; }
                );
            var op3 = new Operation<Int64>(
                (val, f) => { return val.ToInt64(f); }, //repeated
                (x, y) => { return (x - y) * x; }
                );
        }
    }
}

显然,我可以从基类中继承如下:

    class STO64 : Stackoverflow<Int64>
    {
        public STO64( Func<Int64, Int64, Int64> opGeneric)
            : base( (val, f) => { return val.ToInt64(f); }, opGeneric )
        {
        }
        public Int64 operation<K>(K a, K b) where K : IConvertible
        {
            return base.operation(a, b);
        }
    }

但我想知道有没有一种方法可以用不同的版本重载基类构造函数。

在C#中为没有继承的泛型类创建一个具体构造函数

否。

构造函数构造在中定义的类。同一个类不能同时是泛型和非泛型。

根据您的需要,如果您必须避免泛型或使用泛型"创建者"方法Base Create<T>()...创建非泛型类,则可以尝试添加非泛型基类(class Base<T> : Base)。

我认为诀窍在于一些选角。我在StackOverflow上写了一个构造函数,看起来像这样:

    public Stackoverflow(Func<T, T, T> opGeneric) 
    {
        this.convertValue = (val, f) => { return (T)(IConvertible)val.ToInt64(f); };
        this.op = opGeneric;
    }

然后对于Caller类,它看起来是这样的(部分):

class Caller
{
    Stackoverflow<Int64> op1 = new Stackoverflow<Int64>(
     (x, y) => { return x / y; }
     );
 ...
}

在我的主程序中,我可以创建一个新的调用者:

        var caller = new Caller();

我还对您的项目进行了一些其他更改,以便执行代码。完整的解决方案位于https://github.com/kc1073/Samples

KC

这个答案更符合你的意图,而不是你提出的问题。

您希望为特定类型设置一次转换器,然后继续使用它们,而不必每次都再次指定它们。

通用静态变量可以为您解决这个问题。对于泛型参数的每个变体,泛型静态变量都是不同的静态变量,因此,如果我们将convertValue设置为泛型类型Stackoverflow<T>内部的静态变量时,则它Stackoverflow<Int64>.convertValueStackoverflow<Int32>.convertValue是不同的值。由于它是一个静态变量,该值将一直保持到AppDomain停止运行。

我将您的类转换为一个带有静态方法和变量的静态类来演示这个概念。

using System;
using System.Globalization;
public class Stackoverflow<T>
{
    private static Func<IConvertible, IFormatProvider, T> convertValue = (a, b) =>
    {
        throw new Exception("Initialize must be called to initialize the operations");
    };
    private static Func<T, T, T> op = (a, b) =>
        {
            throw new Exception("Initialize must be called to initialize the operations");
        };
    public static void Initialize(Func<IConvertible, IFormatProvider, T> ToGenericValue, Func<T, T, T> opGeneric)
    {
        convertValue = ToGenericValue;
        op = opGeneric;
    }
    public static T Operation<K>(K a, K b) where K : IConvertible
    {
        T aAsT = convertValue(a, CultureInfo.InvariantCulture);
        T bAsT = convertValue(b, CultureInfo.InvariantCulture);
        return op(aAsT, bAsT);
    }
}

代码可参考如下:

Stackoverflow<Int64>.Initialize(
        (val, f) => { return val.ToInt64(f); },
        (x, y) => { return x / y; }
    );
var op1 = Stackoverflow<Int64>.Operation(a, b);
var op2 = Stackoverflow<Int64>.Operation("8830000", "922");