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

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

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

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

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

textual
Листинг программы
static class MathEx
{
}
 
static class MathEx<T>
{
    public static readonly Func<T, T, T> add = BuildBinaryOperator(ExpressionType.Add);
    public static readonly Func<T, T, T> sub = BuildBinaryOperator(ExpressionType.Subtract);
    public static readonly Func<T, T, T> mul = BuildBinaryOperator(ExpressionType.Multiply);
    public static readonly Func<T, T, T> div = BuildBinaryOperator(ExpressionType.Divide);
 
    static Func<T,T,T> BuildBinaryOperator(ExpressionType Type)
    {
        var t = typeof(T);
        var a = Expression.Parameter(typeof(T), "a");
        var b = Expression.Parameter(typeof(T), "b");
        var o = Expression.MakeBinary(Type, a, b);
        return Expression.Lambda<Func<T, T, T>>(o, a, b).Compile();
    }
}
 
abstract class Vector
{
    public static Vector<T> Create<T>(params T[] Components)
        => new Vector<T>(Components);
}
 
class Vector<T>: Vector
{
    T[] data;
 
    public Vector(int Length)
    {
        data = new T[Length];
    }
 
    public Vector(IEnumerable<T> Components)
    {
        data = Components.ToArray();
    }
 
    public int Length => data.Length;
    public T this[int Index]
    {
        get => data[Index];
        set => data[Index] = value;
    }
 
    public override string ToString()
    {
        return $"<{ string.Join("; ", data) }>";
    }
 
    private static IEnumerable<R> CheckedZip<R>(Vector<T> Left, Vector<T> Right, Func<T, T, R> ResultSelector)
    {
        if (Left.Length != Right.Length)
            throw new ArgumentException("Vectors must be the same lengths");
 
        return Left.data.Zip(Right.data, ResultSelector);
    }
 
    public static Vector<T> operator +(Vector<T> Left, Vector<T> Right)
        => new Vector<T>(CheckedZip(Left, Right, MathEx<T>.add));
 
    public static Vector<T> operator -(Vector<T> Left, Vector<T> Right)
        => new Vector<T>(CheckedZip(Left, Right, MathEx<T>.sub));
 
    public static T operator *(Vector<T> Left, Vector<T> Right)
        => CheckedZip(Left, Right, MathEx<T>.mul).Aggregate(MathEx<T>.add);
 
    public static Vector<T> operator *(Vector<T> Vector, T Scalar)
        => new Vector<T>(Vector.data.Select(Component => MathEx<T>.mul(Component, Scalar)));
 
    public static Vector<T> operator *(T Scalar, Vector<T> Vector)
        => new Vector<T>(Vector.data.Select(Component => MathEx<T>.mul(Scalar, Component)));
 
    public static Vector<T> operator /(Vector<T> Vector, T Scalar)
        => new Vector<T>(Vector.data.Select(Component => MathEx<T>.div(Component, Scalar)));
}
 
struct MyValue
{
    public readonly string Value;
    public MyValue(string Value) => this.Value = Value;
    public override string ToString() => Value;
    public static MyValue operator +(MyValue left, MyValue right) => new MyValue(left.Value + right.Value);
    public static MyValue operator -(MyValue left, MyValue right) => throw new NotImplementedException();
    public static MyValue operator *(MyValue left, MyValue right) => throw new NotImplementedException();
    public static MyValue operator /(MyValue left, MyValue right) => throw new NotImplementedException();
    public static explicit operator MyValue(string Value) => new MyValue(Value);
}
 
class Program
{
    static void TryAdd<T>(Vector<T> left, Vector<T> right)
    {
        Console.WriteLine($"{typeof(T).Name, 10}: {left} + {right} = {left + right}");
    }
 
    static void Main()
    {
        var s1 = Vector.Create((MyValue)"a", (MyValue)"b");
        var s2 = Vector.Create((MyValue)"A", (MyValue)"B");
        TryAdd(s1, s2);
 
        var i1 = Vector.Create(1, 2);
        var i2 = Vector.Create(3, 4);
        TryAdd(i1, i2);
 
        var f1 = Vector.Create(1.2f, 3.4f);
        var f2 = Vector.Create(5.6f, 7.8f);
        TryAdd(f1, f2);
 
        var d1 = Vector.Create(1.2d, 3.4d);
        var d2 = Vector.Create(5.6d, 7.8d);
        TryAdd(d1, d2);
 
        Console.ReadLine();
    }
}

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


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

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

8   голосов , оценка 3.875 из 5
Похожие ответы