这是使用算术实现多态性的好方法吗?
Is this a good way to implement polymorphism for using arithmetic?
所以我想使用多态性来使用算术。
因此,我的第一个想法是制作一个使用算术、IAddable 等的接口;但是我在互联网上发现这是不可能的。但是我想到了一个技巧,现在我想知道:这是多态性的一个很好且快速的实现吗?
public abstract class RingElement
{
public static RingElement operator +(RingElement e1, RingElement e2)
{
if (e1 == null)
return e2;
if (e2 == null)
return e1;
Type type = e1.GetType();
return (RingElement) type.GetMethod("op_Addition").Invoke(null, new object[] {e1, e2 });
}
public static RingElement operator *(RingElement e1, RingElement e2)
{
if (e1 == null)
return e2;
if (e2 == null)
return e1;
Type type = e1.GetType();
return (RingElement) type.GetMethod("op_Multiply").Invoke(null, new object[] { e1, e2 });
}
}
我制作了两个 RingElements:一个 doubleElement(只包含一个 double)和一个通用的
Matrix<T> : RingElement where T : RingElement
空值处理是为了实现空金额或空产品的可能性。
RingElement 的每个继承 class 都应该有两个静态方法
public static T operator +(T x, T y)
public static T operator *(T x, T y)
有自己的实现体,其中 T 是 class 类型
你来的有点早))。 c# 9
(link) 中有 Type Classes
个候选者,这可能是 c#
中最优雅的解决方案。
(如果使用f#
是一个选项,它已经有Statically Resolved Type Parameters,而这个link下的页面正好显示了算术多态的例子)
这行得通,使用反射的位就可以了。它不是 type-safe 并且可能不是最高效的方法,但不幸的是,对于您在 C# 中的问题还没有真正完全令人满意的答案。
以下是一些您可能会觉得有用的建议:
为了解决 Scott Hannen 的合理担忧,关于能够将 DogRingElement : RingElement
添加到 CatRingElement : RingElement
,您可以使用奇怪的重复模式,
public abstract class RingElement<T> where T : RingElement<T> { .. }
public class DogRingElement : RingElement<DogRingElement> { .. }
public class CatRingElement : RingElement<CatRingElement> { .. }
为了提高性能,您可以尝试,
public static RingElement operator +(RingElement e1, RingElement e2)
{
return (RingElement) ((dynamic) e1 + (dynamic) e2);
}
这在开始时对性能有一定的影响,但在第一次使用后会变得更快。
您可以在 Matrix 实现中使用 dynamic
变量,
class Matrix<T>
{
public static Matrix<T> operator + (Matrix<T> a, Matrix<T> b)
{
// check a.M = b.M, a.N = b.N
var c = new Matrix<T>(a.M, a.N);
for (var i = 0; i < a.N ; i ++)
{
for (var i = 0; i < a.N ; i ++)
{
dynamic x = a[i, j], y = b[i, j];
c[i,j] = (T) (x + y);
}
}
return c;
}
}
第一次使用性能不是很好,后来就下降了。
您还可以考虑一个实现算术运算符的包装器 class,持有对实现具有 Add、Mult 等方法的接口的对象的引用,
public interface IRingElem<T> // strangely recurring pattern
where T : IRingElem<T>
{
T Add(T);
}
public class Num<T>
where T : IRingElem<T>
{
private readonly T elem;
public static Num<T> operator + (Num<T> a, Num<T> b)
{
return new Num<T>(a.elem.Add(b.elem));
}
}
通过实现从 T
到 Num<T>
的显式转换和从 Num<T>
到 T
的隐式转换,这相当方便。
如果您追求真正好的性能,您可以考虑将包装器 class 设为 struct
(删除 readonly
有时也有帮助)并在任何地方使用 [MethodImpl(MethodImplOptions.AggressiveInlining)]
包装器 class.
所以我想使用多态性来使用算术。
因此,我的第一个想法是制作一个使用算术、IAddable 等的接口;但是我在互联网上发现这是不可能的。但是我想到了一个技巧,现在我想知道:这是多态性的一个很好且快速的实现吗?
public abstract class RingElement
{
public static RingElement operator +(RingElement e1, RingElement e2)
{
if (e1 == null)
return e2;
if (e2 == null)
return e1;
Type type = e1.GetType();
return (RingElement) type.GetMethod("op_Addition").Invoke(null, new object[] {e1, e2 });
}
public static RingElement operator *(RingElement e1, RingElement e2)
{
if (e1 == null)
return e2;
if (e2 == null)
return e1;
Type type = e1.GetType();
return (RingElement) type.GetMethod("op_Multiply").Invoke(null, new object[] { e1, e2 });
}
}
我制作了两个 RingElements:一个 doubleElement(只包含一个 double)和一个通用的
Matrix<T> : RingElement where T : RingElement
空值处理是为了实现空金额或空产品的可能性。
RingElement 的每个继承 class 都应该有两个静态方法
public static T operator +(T x, T y)
public static T operator *(T x, T y)
有自己的实现体,其中 T 是 class 类型
你来的有点早))。 c# 9
(link) 中有 Type Classes
个候选者,这可能是 c#
中最优雅的解决方案。
(如果使用f#
是一个选项,它已经有Statically Resolved Type Parameters,而这个link下的页面正好显示了算术多态的例子)
这行得通,使用反射的位就可以了。它不是 type-safe 并且可能不是最高效的方法,但不幸的是,对于您在 C# 中的问题还没有真正完全令人满意的答案。
以下是一些您可能会觉得有用的建议:
为了解决 Scott Hannen 的合理担忧,关于能够将 DogRingElement : RingElement
添加到 CatRingElement : RingElement
,您可以使用奇怪的重复模式,
public abstract class RingElement<T> where T : RingElement<T> { .. }
public class DogRingElement : RingElement<DogRingElement> { .. }
public class CatRingElement : RingElement<CatRingElement> { .. }
为了提高性能,您可以尝试,
public static RingElement operator +(RingElement e1, RingElement e2)
{
return (RingElement) ((dynamic) e1 + (dynamic) e2);
}
这在开始时对性能有一定的影响,但在第一次使用后会变得更快。
您可以在 Matrix 实现中使用 dynamic
变量,
class Matrix<T>
{
public static Matrix<T> operator + (Matrix<T> a, Matrix<T> b)
{
// check a.M = b.M, a.N = b.N
var c = new Matrix<T>(a.M, a.N);
for (var i = 0; i < a.N ; i ++)
{
for (var i = 0; i < a.N ; i ++)
{
dynamic x = a[i, j], y = b[i, j];
c[i,j] = (T) (x + y);
}
}
return c;
}
}
第一次使用性能不是很好,后来就下降了。
您还可以考虑一个实现算术运算符的包装器 class,持有对实现具有 Add、Mult 等方法的接口的对象的引用,
public interface IRingElem<T> // strangely recurring pattern
where T : IRingElem<T>
{
T Add(T);
}
public class Num<T>
where T : IRingElem<T>
{
private readonly T elem;
public static Num<T> operator + (Num<T> a, Num<T> b)
{
return new Num<T>(a.elem.Add(b.elem));
}
}
通过实现从 T
到 Num<T>
的显式转换和从 Num<T>
到 T
的隐式转换,这相当方便。
如果您追求真正好的性能,您可以考虑将包装器 class 设为 struct
(删除 readonly
有时也有帮助)并在任何地方使用 [MethodImpl(MethodImplOptions.AggressiveInlining)]
包装器 class.