C # 'daki bir dizi gibi bir Listeyi neden başlatabilirim?


131

Bugün C # 'da yapabileceğimi görünce şaşırdım:

List<int> a = new List<int> { 1, 2, 3 };

Bunu neden yapabilirim? Hangi kurucu denir? Bunu kendi derslerimle nasıl yapabilirim? Dizileri başlatmanın bu yol olduğunu biliyorum ama diziler dil öğeleri ve Listeler basit nesnelerdir ...


1
Bu soru yardımcı olabilir: stackoverflow.com/questions/1744967/…
Bob Kaufman

10
Oldukça harika ha? Sözlükleri başlatmak için de çok benzer kodlar yapabilirsiniz:{ { "key1", "value1"}, { "key2", "value2"} }
danludwig

Başka bir bakış açısına göre, bu dizi gibi başlatma sözdizimi, bize a'nın temelindeki veri türünün List<int>aslında yalnızca bir dizi olduğunu hatırlatır . C # ekibinden, ArrayList<T>kulağa çok açık ve doğal gelen bir isim vermedikleri için nefret ediyorum .
MHK

Yanıtlar:


183

Bu, .NET'teki koleksiyon başlatıcı sözdiziminin bir parçasıdır. Bu sözdizimini, oluşturduğunuz herhangi bir koleksiyonda kullanabilirsiniz:

  • Uygular IEnumerable(tercihen IEnumerable<T>)

  • Adlı bir yöntemi vardır. Add(...)

Olan şey, varsayılan kurucunun çağrılması ve ardından Add(...)başlatıcının her üyesi için çağrılmasıdır.

Bu nedenle, bu iki blok kabaca aynıdır:

List<int> a = new List<int> { 1, 2, 3 };

Ve

List<int> temp = new List<int>();
temp.Add(1);
temp.Add(2);
temp.Add(3);
List<int> a = temp;

İsterseniz , örneğin List<T>büyüme sırasında aşırı boyutlandırmayı önlemek için alternatif bir kurucu çağırabilirsiniz.

// Notice, calls the List constructor that takes an int arg
// for initial capacity, then Add()'s three items.
List<int> a = new List<int>(3) { 1, 2, 3, }

Add()Yöntemin tek bir öğe almasına gerek olmadığını unutmayın, örneğin Add()yöntemi Dictionary<TKey, TValue>iki öğe alır:

var grades = new Dictionary<string, int>
    {
        { "Suzy", 100 },
        { "David", 98 },
        { "Karen", 73 }
    };

Aşağıdakilerle kabaca aynıdır:

var temp = new Dictionary<string, int>();
temp.Add("Suzy", 100);
temp.Add("David", 98);
temp.Add("Karen", 73);
var grades = temp;

Bu nedenle, bunu kendi sınıfınıza eklemek için yapmanız gereken tek şey, belirtildiği gibi, uygulamak IEnumerable(tekrar, tercihen IEnumerable<T>) ve bir veya daha fazla Add()yöntem oluşturmaktır :

public class SomeCollection<T> : IEnumerable<T>
{
    // implement Add() methods appropriate for your collection
    public void Add(T item)
    {
        // your add logic    
    }

    // implement your enumerators for IEnumerable<T> (and IEnumerable)
    public IEnumerator<T> GetEnumerator()
    {
        // your implementation
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

O zaman onu BCL koleksiyonlarının yaptığı gibi kullanabilirsiniz:

public class MyProgram
{
    private SomeCollection<int> _myCollection = new SomeCollection<int> { 13, 5, 7 };    

    // ...
}

(Daha fazla bilgi için MSDN'ye bakın )


29
Güzel cevap, yine de ilk örneğinizde "tam olarak aynı" demenin tam olarak doğru olmadığını not ettim. Bu tam olarak aynıdır List<int> temp = new List<int>(); temp.Add(1); ... List<int> a = temp; , yani adeğişken kadar başlatılmadı sonra tüm denir ekler. Aksi takdirde List<int> a = new List<int>() { a.Count, a.Count, a.Count };çılgınca bir şey gibi bir şey yapmak yasal olurdu .
Eric Lippert

1
@ user606723: List<int> a; a = new List<int>() { a.Count };ve arasında gerçek bir fark yokList<int> a = new List<int>() { a.Count };
Joren

4
@Joren: Haklısın; aslında C # spesifikasyonu T x = y;ile aynıdır T x; x = y;, Bu gerçek bazı tuhaf durumlara yol açabilir. Örneğin int x = M(out x) + x;, tamamen yasaldır çünkü int x; x = M(out x) + x;yasaldır.
Eric Lippert

1
@JamesMichaelHare uygulamak gerekli değildir IEnumerable<T>; genel olmayan IEnumerable, koleksiyon başlatıcı sözdiziminin kullanımına izin vermek için yeterlidir.
phoog

2
IDisposable uygulayan bir tür koleksiyon kullanıyorsanız Eric'in noktası önemlidir. çağrılardan using (var x = new Something{ 1, 2 })biri Addbaşarısız olursa nesneyi elden çıkarmaz.
porges


8

Göre C # Sürüm 3.0 Şartnamenin "koleksiyonu nesnesine hangi uygulanan başlatıcısı bir koleksiyon tam olarak bir T için bir tür olduğunu uygular System.Collections.Generic.ICollection olmalıdır"

Bununla birlikte, bu bilgi bu yazı itibariyle yanlış görünmektedir; Eric Lippert'in açıklamasına aşağıdaki yorumlarda bakın.


10
Bu sayfa doğru değil. Bunu dikkatime sunduğunuz için teşekkürler. Bu, bir şekilde silinmemiş olan bazı ön yayın öncesi belgeler olmalı. Orijinal tasarım ICollection gerektirecekti, ancak bu, kararlaştırdığımız son tasarım değildi.
Eric Lippert

1
Açıklama için teşekkürler.
Olivier Jacot-Descombes


6

Koleksiyon başlatıcılarla ilgili bir başka harika şey de, birden fazla Addyöntem aşırı yüklemesine sahip olabilmeniz ve hepsini aynı başlatıcıda çağırabilmenizdir! Örneğin bu işe yarar:

public class MyCollection<T> : IEnumerable<T>
{
    public void Add(T item, int number)
    {

    }
    public void Add(T item, string text) 
    {

    }
    public bool Add(T item) //return type could be anything
    {

    }
}

var myCollection = new MyCollection<bool> 
{
    true,
    { false, 0 },
    { true, "" },
    false
};

Doğru aşırı yükleri çağırır. Ayrıca, sadece adı olan yöntemi arar Add, dönüş türü herhangi bir şey olabilir.


0

Dizi benzeri sözdizimi bir dizi Add()çağrıda döndürülüyor .

Bunu çok daha ilginç bir örnekte görmek için, C # 'da ilk önce yasadışı görünen iki ilginç şeyi yaptığım aşağıdaki kodu düşünün, 1) salt okunur bir özellik ayarlama, 2) başlatıcı gibi bir diziye sahip bir liste ayarlama.

public class MyClass
{   
    public MyClass()
    {   
        _list = new List<string>();
    }
    private IList<string> _list;
    public IList<string> MyList 
    { 
        get
        { 
            return _list;
        }
    }
}
//In some other method
var sample = new MyClass
{
    MyList = {"a", "b"}
};

1) MyList salt okunur olmasına ve 2) dizi başlatıcılı bir liste ayarlamama rağmen bu kod mükemmel çalışacaktır.

Bunun işe yaramasının nedeni, bir nesne başlatıcının parçası olan kodda, derleyicinin her zaman {}benzer bir sözdizimini Add()salt okunur bir alanda bile tamamen yasal olan bir dizi çağrıya dönüştürmesidir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.