Арифметические действия в обобщенных классах - C#

Узнай цену своей работы

Формулировка задачи:

Здравствуйте! Нужен пример, как ограничить обобщенный тип для написания универсального класса так, чтобы можно было выполнять действия сложения, вычитания, деления и т. п. P.S. Нужен именно пример кода. На фразы, типа:"Ограничь тип структурой или интерфейсом, а действия реализуй при помощи делегатов" натыкаюсь постоянно, но не совсем понимаю, как это все реализовывается на практике. Заранее спасибо.

Решение задачи: «Арифметические действия в обобщенных классах»

textual
Листинг программы
  1. static class MathEx
  2. {
  3. }
  4.  
  5. static class MathEx<T>
  6. {
  7.     public static readonly Func<T, T, T> add = BuildBinaryOperator(ExpressionType.Add);
  8.     public static readonly Func<T, T, T> sub = BuildBinaryOperator(ExpressionType.Subtract);
  9.     public static readonly Func<T, T, T> mul = BuildBinaryOperator(ExpressionType.Multiply);
  10.     public static readonly Func<T, T, T> div = BuildBinaryOperator(ExpressionType.Divide);
  11.  
  12.     static Func<T,T,T> BuildBinaryOperator(ExpressionType Type)
  13.     {
  14.         var t = typeof(T);
  15.         var a = Expression.Parameter(typeof(T), "a");
  16.         var b = Expression.Parameter(typeof(T), "b");
  17.         var o = Expression.MakeBinary(Type, a, b);
  18.         return Expression.Lambda<Func<T, T, T>>(o, a, b).Compile();
  19.     }
  20. }
  21.  
  22. abstract class Vector
  23. {
  24.     public static Vector<T> Create<T>(params T[] Components)
  25.         => new Vector<T>(Components);
  26. }
  27.  
  28. class Vector<T>: Vector
  29. {
  30.     T[] data;
  31.  
  32.     public Vector(int Length)
  33.     {
  34.         data = new T[Length];
  35.     }
  36.  
  37.     public Vector(IEnumerable<T> Components)
  38.     {
  39.         data = Components.ToArray();
  40.     }
  41.  
  42.     public int Length => data.Length;
  43.     public T this[int Index]
  44.     {
  45.         get => data[Index];
  46.         set => data[Index] = value;
  47.     }
  48.  
  49.     public override string ToString()
  50.     {
  51.         return $"<{ string.Join("; ", data) }>";
  52.     }
  53.  
  54.     private static IEnumerable<R> CheckedZip<R>(Vector<T> Left, Vector<T> Right, Func<T, T, R> ResultSelector)
  55.     {
  56.         if (Left.Length != Right.Length)
  57.             throw new ArgumentException("Vectors must be the same lengths");
  58.  
  59.         return Left.data.Zip(Right.data, ResultSelector);
  60.     }
  61.  
  62.     public static Vector<T> operator +(Vector<T> Left, Vector<T> Right)
  63.         => new Vector<T>(CheckedZip(Left, Right, MathEx<T>.add));
  64.  
  65.     public static Vector<T> operator -(Vector<T> Left, Vector<T> Right)
  66.         => new Vector<T>(CheckedZip(Left, Right, MathEx<T>.sub));
  67.  
  68.     public static T operator *(Vector<T> Left, Vector<T> Right)
  69.         => CheckedZip(Left, Right, MathEx<T>.mul).Aggregate(MathEx<T>.add);
  70.  
  71.     public static Vector<T> operator *(Vector<T> Vector, T Scalar)
  72.         => new Vector<T>(Vector.data.Select(Component => MathEx<T>.mul(Component, Scalar)));
  73.  
  74.     public static Vector<T> operator *(T Scalar, Vector<T> Vector)
  75.         => new Vector<T>(Vector.data.Select(Component => MathEx<T>.mul(Scalar, Component)));
  76.  
  77.     public static Vector<T> operator /(Vector<T> Vector, T Scalar)
  78.         => new Vector<T>(Vector.data.Select(Component => MathEx<T>.div(Component, Scalar)));
  79. }
  80.  
  81. struct MyValue
  82. {
  83.     public readonly string Value;
  84.     public MyValue(string Value) => this.Value = Value;
  85.     public override string ToString() => Value;
  86.     public static MyValue operator +(MyValue left, MyValue right) => new MyValue(left.Value + right.Value);
  87.     public static MyValue operator -(MyValue left, MyValue right) => throw new NotImplementedException();
  88.     public static MyValue operator *(MyValue left, MyValue right) => throw new NotImplementedException();
  89.     public static MyValue operator /(MyValue left, MyValue right) => throw new NotImplementedException();
  90.     public static explicit operator MyValue(string Value) => new MyValue(Value);
  91. }
  92.  
  93. class Program
  94. {
  95.     static void TryAdd<T>(Vector<T> left, Vector<T> right)
  96.     {
  97.         Console.WriteLine($"{typeof(T).Name, 10}: {left} + {right} = {left + right}");
  98.     }
  99.  
  100.     static void Main()
  101.     {
  102.         var s1 = Vector.Create((MyValue)"a", (MyValue)"b");
  103.         var s2 = Vector.Create((MyValue)"A", (MyValue)"B");
  104.         TryAdd(s1, s2);
  105.  
  106.         var i1 = Vector.Create(1, 2);
  107.         var i2 = Vector.Create(3, 4);
  108.         TryAdd(i1, i2);
  109.  
  110.         var f1 = Vector.Create(1.2f, 3.4f);
  111.         var f2 = Vector.Create(5.6f, 7.8f);
  112.         TryAdd(f1, f2);
  113.  
  114.         var d1 = Vector.Create(1.2d, 3.4d);
  115.         var d2 = Vector.Create(5.6d, 7.8d);
  116.         TryAdd(d1, d2);
  117.  
  118.         Console.ReadLine();
  119.     }
  120. }

ИИ поможет Вам:


  • решить любую задачу по программированию
  • объяснить код
  • расставить комментарии в коде
  • и т.д
Попробуйте бесплатно

Оцени полезность:

8   голосов , оценка 3.875 из 5

Нужна аналогичная работа?

Оформи быстрый заказ и узнай стоимость

Бесплатно
Оформите заказ и авторы начнут откликаться уже через 10 минут
Похожие ответы