2014-12-03 2 views
2

Я создаю библиотеку линейной алгебры в C#, и я хотел бы заставить ошибки несогласованности размерности до времени компиляции. Я реализовал аналогичное решение для this, где признаком, который я использую, является класс, который однозначно отображает целое число. Проблема заключается в том, что для каждого возможного размера, который я бы хотел, чтобы мои векторы имели, мне нужно было бы создать класс с уникальным именем для его представления.Проверка согласованности векторного математического измерения во время компиляции

Вот пример того, что реализации:

public class Vector<T> where T: ISize, new() 
{ 
    static readonly T size = new T(); 
    List<double> values; 

    public Vector(List<double> values) 
    { 
     if (values.Count != size.Size) 
      throw new IndexOutOfRangeException(); 

     this.values = new List<double>(values); 
    } 

    public double Get(int index) 
    { 
     return values[index]; 
    } 

    public Vector<T> Add(Vector<T> other) 
    { 
     var vv = new List<double>(); 

     for (int ii = 0; ii < size.Size; ++ii) 
      vv.Add(other.Get(ii) + this.values[ii]); 

     return new Vector<T>(vv); 
    } 
} 

public interface ISize 
{ 
    int Size { get; } 
} 

public class S1 : ISize 
{ 
    public int Size 
    { 
     get { return 1; } 
    } 
} 

public class S2 : ISize 
{ 
    public int Size 
    { 
     get { return 2; } 
    } 
} 

А вот пример его использования:

class Program 
{ 
    static void Main(string[] args) 
    { 
     var v1 = new Vector<S2>(new List<double>() { 1, 2 }); 
     var v2 = new Vector<S2>(new List<double>() { 10, -4 }); 
     var z1 = new Vector<S1>(new List<double>() { 10 }); 

     // works 
     var v3 = v1.Add(v2); 

     // complie-time error 
     var z2 = z1.Add(v1); 
    } 
} 

Это работает очень хорошо для моих целей, за исключением того, что мне нужно, кроме для создания различной реализации ISize для любого возможного размера Vector. Есть ли способ реализовать класс Vector, который позволил бы мне обойти эту проблему?

+0

Без эквивалента C++ «параметры шаблона непигового типа», я не думаю, что это возможно. –

ответ

1

Для получения ошибки во время компиляции необходимо иметь разные типы. C# не имеет понятия, которое позволяет вам определить параметр типа, который сам берет некие значения параметров - вот что вам нужно сделать.

Поэтому, я не думаю, что вы спрашиваете.

Я думаю, что может быть способ сделать уникальные типы для семейства векторных экземпляров с использованием анонимных типов, но это будет изворотливым, и я не думаю, что это обеспечило бы безопасность типа, которую вы хотите.

C++ имеет такое понятие в шаблонах (так что это не необоснованно), просто невозможно в C#.

0

Вы можете создать один класс N-dimentional Vector с проверкой типа времени компиляции, но это довольно грязно. То, что мы создаем здесь, это связные списки стиля LISP, но через общие аргументы типа, а не исключительно из ссылок на объекты через поля.

public interface IVector 
{ 
    double Value { get; } 
    IVector Tail { get; } 
} 
public class Vector<T> : IVector 
    where T : IVector 
{ 
    internal Vector(double value, T tail) 
    { 
     Value = value; 
     Tail = tail; 
    } 

    public double Value { get; private set; } 
    public T Tail { get; private set; } 

    public Vector<Vector<T>> Add(double value) 
    { 
     return new Vector<Vector<T>>(value, this); 
    } 
} 
internal class EmptyVector : IVector 
{ 
    public double Value 
    { 
     get { throw new NotImplementedException(); } 
    } 

    public IVector Tail 
    { 
     get { return null; } 
    } 
} 

public static class Vector 
{ 
    public static readonly Vector<IVector> Empty = new Vector<IVector>(
     0, new EmptyVector()); 
    public static IEnumerable<double> AllValues(this IVector vector) 
    { 
     IVector current = vector; 
     while (current != Vector.Empty && current != null) 
     { 
      yield return current.Value; 
      current = current.Tail; 
     }; 
    } 
} 

Это позволяет нам написать:

var v1 = Vector.Empty.Add(1).Add(2); 
var v2 = Vector.Empty.Add(10).Add(-4); 
var z1 = Vector.Empty.Add(10); 


v1 = v2;//works, as they are the same type 
z1 = v2;//fails, as they aren't the same type, since they're a different size 

Это позволяет позволяет написать метод, который принимает вектор определенного размера. Это не удобно, и оно не масштабируется, но оно работает. Если вы хотите, скажем, 3D-вектор в качестве параметра, вы можете написать:

Смежные вопросы