2013-03-15 62 views
1
new List<BaseType> 
{ 
    new DerivedType 
    { 
     x="x1",y="y1",z="z1" 
    }, 
    new DerivedType 
    { 
     x="x2",y="y2",z="z2" 
    }, 
    new DerivedType 
    { 
     x="x3",y="y3",z="z3" 
    }, 
    new DerivedType 
    { 
     x="x4",y="y4",z="z3" 
    }, 
    ... 
} 

在靜態方法中,通過上述方法初始化列表,並且我想知道是否有更好的方法來在語法上做到這一點。尋找更好的方法來初始化C中的大對象列表#

每次都以相同的順序設置相同的字段,以防萬一。

回答

5

如果值實際上「X1」等,怎麼樣:

var list = Enumerable.Range(1, n) 
        .Select(i => new DerivedType { 
           x = "x" + i, 
           y = "y" + i, 
           z = "z" + i 
          }) 
        .ToList<BaseType>(); 

依賴協方差在C#4.在C#3(或針對.NET 3.5),你需要這樣的:

var list = Enumerable.Range(1, n) 
        .Select(i => (BaseType) new DerivedType { 
           x = "x" + i, 
           y = "y" + i, 
           z = "z" + i 
          }) 
        .ToList(); 

或者,如果這些只是樣本值(或者即使他們沒有),簡單地增加一個構造函數來DerivedType,讓你通過一次過三個屬性會減少混亂:

new List<BaseType> 
{ 
    new DerivedType("x1", "y1", "z1"), 
    new DerivedType("x2", "y2", "z2"), 
    new DerivedType("x3", "y3", "z3"), 
    new DerivedType("x4", "y4", "z4"), 
    ... 
} 
+1

我確定我只是老掉牙,但簡單的循環似乎更直截了當。 – 2013-03-15 22:04:03

+0

@EricJ .:這取決於上下文。擁有單一表達式可以讓靜態變量初始化等事情變得更簡單......而LINQ方法更像是描述我們想要列表中的內容,而不是表達我們需要做什麼來創建它。 – 2013-03-15 22:06:00

+0

@lazyberezovsky:它使用C#4,是的。將編輯以清楚說明。 – 2013-03-15 22:13:08

8

爲什麼不在這裏使用for循環?

var list = new List<BaseType>(SomeValue); 
for (int i = 1; i < SomeValue; i++) { 
    list.Add(new DerivedType { 
    x = string.Format("x{0}", i), 
    y = string.Format("y{0}", i), 
    z = string.Format("z{0}", i) 
    }); 
} 

注:我假設在你的示例代碼的最後的init應該有"z4"代替"z3"

+0

+1 C#的新奇功能並不總是給定問題的最佳解決方案:-) – 2013-03-15 22:02:56

1

隨着NBuilder你需要的代碼的一個或兩行(你可以從的NuGet得到它):

List<BaseType> list = Builder<DerivedType>.CreateListOfSize(5).Build() 
              .ToList<BaseType>(); 

它與初始化值的所有屬性"xN""yN""zN"(屬性名+元素索引)。

+1

感謝您注意到我有Jon的確切解決方案,真的很慚愧。和連接NBuilder的+1。 – 2013-03-15 22:15:08

+0

@IlyaIvanov是的,非常強大和方便的工具 – 2013-03-15 22:22:09

0

我會用一個簡單的數組來保存數據。然後使用此數組構建派生類型。請注意,數據值可能有些隨意(這裏顯示的是字符串和int類型)。這可以通過使用一個字符串數組來優化原始問題。

object[] data = 
{ 
    "x1", "y1", 4, 
    "x2", "y2", 3, 
    "x3", "y3", 2, 
    "x4", "y4", 3 
}; 

int countPerType = 3; 
int size = data.Length; 

var initMe = new List<BaseType>(); 

for (int idx = 0; idx < size; idx += countPerType) 
{ 
    initMe.Add(
     new DerivedType() 
     { 
      X = (string)data[idx], 
      Y = (string)data[idx + 1], 
      Z = (int)data[idx + 2] 
     }); 
} 
1

我感到奇怪的是,沒有人解決OP更一般的問題,而是專注於這個例子的特殊情況。

如已通過所有的重量級注意到這裏,爲的例子的具體情況,如Perl的禁慾主義者可能會說,「TMTOWTDI」 —有不止一種辦法做到這一點。一些比其他更好(或至少更簡潔)。

在更一般的情況下,事情並非都是單調的序列,我認爲沒有什麼更好的了。你被困住了很多重複的樣板。

C#沒有像JSON或Javascript的對象初始值設定項或C的compound literals(在2000年與C99一起引入),所有這些都爲這類事情提供了更爲簡潔的語法。可惜,如果你問我。

這裏有一個想法,雖然有點醜陋的黑客:SCG.List<T>和許多其他SCG收藏有一個構造函數重載接受一個IEnumerable<T>IDictionary<TKey,TValue>或類似從在建的對象填充的東西。可以想象的將您的組裝所需的數據作爲一個便於您使用的格式嵌入爲一個embedded resource。它甚至不必是一個嵌入式資源:一個簡單的多行字符串文字(每個項目用逗號分隔的行)都可以實現。提供一個簡單的工廠類或方法,使用該資源生成一個可以交給List<T>構造函數和Bob's-Yer-Uncle的LINQy IEnumerable小部件流。

就像我說的,有點醜陋的黑客,但它會避免重複鍵入。

+0

+1:我也覺得很奇怪,沒有人更普遍地解決這個問題 – phoog 2013-03-16 01:11:14

2

可以使List<T>子類:

public class BaseTypeList : List<BaseType> 
{ 
    public void Add(string x, string y, string z) 
    { 
     Add(new DerivedType { x = x, y = y, z = z }); 
    } 
} 

然後你可以用更簡潔的集合初始化語法:

new BaseTypeList 
{ 
    { "x1", "y1", "z1" }, 
    { "x2", "y2", "z2" }, 
    { "x3", "y3", "z3" }, 
    { "x4", "y4", "z3" /* (sic) */ }, 
    //... 
} 

這工作,因爲編譯器來執行對每個元素單獨重載解析集合初始化程序塊,查找具有匹配給定參數的參數類型的Add方法。

如果需要均勻的派生類型,就有點難看,但它是可能的:

public class BaseTypeList : List<BaseType> 
{ 
    public void Add(Type t, string x, string y, string z) 
    { 
     Add((BaseType)Activator.CreateInstance(t, x, y, z)); 
    } 
} 

那麼你會初始化這樣的集合:

new BaseTypeList 
{ 
    { typeof(DerivedType1), "x1", "y1", "z1" }, 
    { typeof(DerivedType1), "x2", "y2", "z2" }, 
    { typeof(DerivedType2), "x3", "y3", "z3" }, 
    { typeof(DerivedType2), "x4", "y4", "z3" /* (sic) */ }, 
    //... 
} 
+0

+1 ......我沒有想到這一點。 – 2013-03-18 16:42:55