方法重载和类型转换

Method overload and type conversion

我有两种C#转换方法:

public int MyConvertToInteger(double x) {
  if (x > int.MaxValue) {
    return int.MaxValue;
  } else if (x < int.MinValue || double.IsNaN(x)) {
    return int.MinValue;
  } else {
    return (int)x;
  }
}

public int MyConvertToInteger(string str) {
  if (str == null) {
    return 0;
  }
  return str.Length;
}

和一个业务方法,每个参数有两种可能的类型,导致四个重载:

public int IntSum(int x, int y) { 
  unchecked {
    return x+y; 
  }
}

public int IntSum(int x, string y) { 
  int iy = MyConvertToInteger(y);
  return IntSum(x, iy);
}

public int IntSum(double x, int y) {
  int ix = MyConvertToInteger(x);
  return IntSum(ix, y);
}

public int IntSum(double x, string y) {
  int ix = MyConvertToInteger(x);
  return IntSum(ix, y);
}

这很烦人但很实用。但是,如果我要添加具有两种可能类型的第三个参数,我们将有多达八个重载,这在 IMO 看来是不可能的。

我想知道是否有办法以某种方式在方法参数中指定可能的转换,这样我们就不会得到大量的重载? (我对 "solutions" 不感兴趣,它涉及采用更通用类型的参数,例如 "object",然后检查传入的任何类型。)

这不是一个好的做法,但请看一下

void Main()
{
    var result = new Summer().Sum("1", 2, 3.0);
}

public class Summer
{
    private int Convert<T>(T source)
    {
        throw new NotSupportedException();
    }

    private int Convert(int source)
    {
        return source;
    }

    private int Convert(string source)
    {
        return source.Length;
    }

    private int Convert(double source)
    {
        return (int)source;
    }


    public int Sum<T, K>(T i1, K i2)
    {
        return Convert((dynamic)i1) + Convert((dynamic)i2);
    }

    public int Sum<T, K, S>(T i1, K i2, S i3)
    {
        return Convert((dynamic)i1) + Convert((dynamic)i2)+ Convert((dynamic)i3);
    }
}

您可以自定义复合类型,例如int或double可以表示为

    public class IntOrDouble
    {
        int i;
        double d;
        public enum MyType
        {
            None,
            Int,
            Double
        }
        MyType myType;
        public IntOrDouble(int i)
        {
            this.i = i;
            myType = MyType.Int;
        }
        public IntOrDouble(double d)
        {
            this.d = d;
            myType = MyType.Double;
        }
        public MyType GetReturnType()
        {
            return myType;
        }
        public int GetInt()
        {
            if (!myType.Equals(MyType.Int))
            {
                throw new Exception("wrong type");
            }
            return i;
        }
        public double GetDouble()
        {
            if (!myType.Equals(MyType.Double))
            {
                throw new Exception("wrong type");
            }
            return d;
        }
}

但这意味着您必须将方法重写为

    public int IntSum(IntOrDouble x, IntOrString y)

编辑通用版(以防重复使用)

    public enum MyType
    {
        None,
        T1,
        T2
    }
    public class CompositeType<T1,T2>
    {
        T1 i;
        T2 d;
        MyType myType;
        public CompositeType(T1 i)
        {
            this.i = i;
            myType = MyType.T1;
        }
        public CompositeType(T2 d)
        {
            this.d = d;
            myType = MyType.T2;
        }
        public MyType GetReturnType()
        {
            return myType;
        }
        public T1 GetT1()
        {
            if (!myType.Equals(MyType.T1))
            {
                throw new Exception("wrong type");
            }
            return i;
        }
        public T2 GetT2()
        {
            if (!myType.Equals(MyType.T2))
            {
                throw new Exception("wrong type");
            }
            return d;
        }
        public object GetValue()
        {
            switch (myType)
            {
                case MyType.None:
                    throw new Exception("wrong type");
                case MyType.T1:
                    return GetT1();
                case MyType.T2:
                    return GetT2();
                default:
                    throw new Exception("wrong type");
            }

        }
    }

用法

    public int CompositeConversion<T>(CompositeType<int, T> x)
    {
        switch (x.GetReturnType())
        {
            case MyType.None:
                throw new Exception("wrong type");
            case MyType.T1:
                return x.GetT1();
            case MyType.T2:
                if (typeof(T) == typeof(double))
                {
                    return MyConvertToInteger((double)x.GetValue());
                }
                if (typeof(T) == typeof(string))
                {
                    return MyConvertToInteger((string)x.GetValue());
                }
                throw new Exception("wrong type");
            default:
                throw new Exception("wrong type");
        }
    }
    public int IntSum(CompositeType<int,double> x, CompositeType<int, string> y)
    {
        return CompositeConversion(x) + CompositeConversion(y);
    }

单元测试

        int test1 = t.IntSum(3.7, "55.9");
        int test2 = t.IntSum(
            new CompositeType<int,double>(3.7), 
            new CompositeType<int,string>("55.9")
            ); // test1 and test2 are both 7

嗯,

I am wondering if there is a way to somehow specify the possible conversions in the method argument, so that we don't get this profusion of overloads?

没有。这在 C# 中是不可能的。

有时必须创建许多重载,尤其是当性能受到威胁时。我见过为一个方法创建 50 个重载的项目。然而,可能的是 运行 来自更通用的更严格的重载,换句话说 Sum(x ,y, z) 重载可以 运行 两个 (x, y) + (y, z) 所以没有真正的需要在更通用的重载中编写任何其他逻辑,只是为了重用已经存在的逻辑。

唯一的其他选择是接受 params object[] 并确定我们使用的类型、创建复合类型或使用 dynamic 的 .