2014-12-03 76 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); 
    } 
} 

這工作得很好,我的目的,除了一個事實,我需要爲每個可能的Vector大小創建一個不同的ISize實現。有沒有什麼辦法可以讓我實現Vector類,以便讓我解決這個問題?

+0

沒有C++等價於「非類型模板參數」,我不認爲這是可能的。 – 2014-12-03 21:35:22

回答

1

爲了獲得編譯時錯誤,您需要具有不同的類型。 C#沒有一個概念讓我們定義一個類型參數,它本身帶有一種值參數 - 這是你需要做的。

因此,我不認爲你在問什麼是可能的。

我認爲可能有一種方法可以爲使用匿名類型的矢量實例族創建獨特類型,但這會變得古怪,我認爲它不會提供您想要的類型安全。 C++在模板中有這樣的概念(所以這不是不合理的),在C#中是不可能的。

0

您可以使用編譯時類型檢查創建單個N維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矢量作爲參數,你可以這樣寫:

public static void Foo(Vector<Vector<Vector<IVector>>> vector) 
{ 
    var first = vector.Value; 
    var second = vector.Tail.Value; 
    var third = vector.Tail.Tail.Value; 
}