Nesne ve Koleksiyon Başlatıcıları (C# Programlama Kılavuzu)

C# bir nesne veya koleksiyonun örneğini oluşturmanıza ve tek bir deyimde üye atamaları gerçekleştirmenize olanak tanır.

Nesne başlatıcılar

Nesne başlatıcıları, oluşturma zamanında ardından atama deyimleri satırları gelecek şekilde bir oluşturucu çağırmak zorunda kalmadan, bir nesnenin istediğiniz erişilebilir alanlarına veya özelliklerine değerler atamanıza olanak tanır. Nesne başlatıcı sözdizimi, bir oluşturucu için bağımsız değişkenler belirtmenize veya bağımsız değişkenleri (ve parantez sözdizimini) atmanıza olanak tanır. Aşağıdaki örnekte, adlandırılmış bir türe Cat sahip bir nesne başlatıcının nasıl kullanılacağı ve parametresiz oluşturucunun nasıl çağrıldığı gösterilmektedir. sınıfında otomatik olarak uygulanan özelliklerin kullanımına Cat dikkat edin. Daha fazla bilgi için bkz . Otomatik Uygulanan Özellikler.

public class Cat
{
    // Auto-implemented properties.
    public int Age { get; set; }
    public string? Name { get; set; }

    public Cat()
    {
    }

    public Cat(string name)
    {
        this.Name = name;
    }
}
Cat cat = new Cat { Age = 10, Name = "Fluffy" };
Cat sameCat = new Cat("Fluffy"){ Age = 10 };

Nesne başlatıcıları söz dizimi bir örnek oluşturmanıza olanak tanır ve bundan sonra yeni oluşturulan nesneyi atamadaki değişkene atanan özellikleriyle atar.

Nesne başlatıcılar, alanları ve özellikleri atamanın yanı sıra dizin oluşturucuları da ayarlayabilir. Şu temel Matrix sınıfı göz önünde bulundurun:

public class Matrix
{
    private double[,] storage = new double[3, 3];

    public double this[int row, int column]
    {
        // The embedded array will throw out of range exceptions as appropriate.
        get { return storage[row, column]; }
        set { storage[row, column] = value; }
    }
}

Kimlik matrisini aşağıdaki kodla başlatabilirsiniz:

var identity = new Matrix
{
    [0, 0] = 1.0,
    [0, 1] = 0.0,
    [0, 2] = 0.0,

    [1, 0] = 0.0,
    [1, 1] = 1.0,
    [1, 2] = 0.0,

    [2, 0] = 0.0,
    [2, 1] = 0.0,
    [2, 2] = 1.0,
};

Erişilebilir bir ayarlayıcı içeren herhangi bir erişilebilir dizin oluşturucu, bağımsız değişken sayısından veya türlerinden bağımsız olarak nesne başlatıcıdaki ifadelerden biri olarak kullanılabilir. Dizin bağımsız değişkenleri atamanın sol tarafını oluşturur ve değer ifadenin sağ tarafıdır. Örneğin, uygun dizin oluşturucular varsa IndexersExample bunların tümü geçerlidir:

var thing = new IndexersExample
{
    name = "object one",
    [1] = '1',
    [2] = '4',
    [3] = '9',
    Size = Math.PI,
    ['C',4] = "Middle C"
}

Yukarıdaki kodun derlenmesi için türün IndexersExample aşağıdaki üyelere sahip olması gerekir:

public string name;
public double Size { set { ... }; }
public char this[int i] { set { ... }; }
public string this[char c, int i] {  set { ... }; }

Anonim türlerde Nesne Başlatıcıları

Nesne başlatıcıları herhangi bir bağlamda kullanılabilse de, özellikle LINQ sorgu ifadelerinde kullanışlıdır. Sorgu ifadeleri, aşağıdaki bildirimde gösterildiği gibi yalnızca bir nesne başlatıcı kullanılarak başlatılabilir anonim türleri sık sık kullanır.

var pet = new { Age = 10, Name = "Fluffy" };  

Anonim türler, özgün dizinin nesnelerini, değeri ve şekli özgünden farklı olabilecek nesnelere dönüştürmek için LINQ sorgu ifadesindeki yan tümcesini etkinleştirir select . Bir sıradaki her bir nesneden elde edilen bilgilerin yalnızca bir kısmını depolamak isterseniz, bu kullanışlıdır. Aşağıdaki örnekte, bir ürün nesnesinin (p) birçok alan ve yöntem içerdiğini ve yalnızca ürün adını ve birim fiyatını içeren bir nesne dizisi oluşturmakla ilgilendiğinizi varsayalım.

var productInfos =
    from p in products
    select new { p.ProductName, p.UnitPrice };

Bu sorgu yürütülürken değişken, productInfos bu örnekte gösterildiği gibi bir deyimde erişilebilen bir foreach nesne dizisi içerir:

foreach(var p in productInfos){...}  

Yeni anonim türdeki her nesne, özgün nesnedeki özellikler veya alanlarla aynı adları alan iki ortak özelliğe sahiptir. Anonim bir tür oluştururken bir alanı yeniden adlandırabilirsiniz; Aşağıdaki örnek alanı olarak Priceyeniden adlandırırUnitPrice.

select new {p.ProductName, Price = p.UnitPrice};  

Değiştirici ile required Nesne Başlatıcılar

Çağıranları nesne başlatıcı kullanarak bir özelliğin veya alanın değerini ayarlamaya zorlamak için anahtar sözcüğünü kullanırsınız required . Gerekli özelliklerin oluşturucu parametresi olarak ayarlanması gerekmez. Derleyici, tüm çağıranların bu değerleri başlatmasını sağlar.

public class Pet
{
    public required int Age;
    public string Name;
}

// `Age` field is necessary to be initialized.
// You don't need to initialize `Name` property
var pet = new Pet() { Age = 10};

// Compiler error:
// Error CS9035 Required member 'Pet.Age' must be set in the object initializer or attribute constructor.
// var pet = new Pet();

Özellikle yönetecek birden çok alanınız veya özelliğiniz varsa ve bunların tümünü oluşturucuya eklemek istemediğinizde, nesnenizin düzgün bir şekilde başlatıldığını garanti etmek tipik bir uygulamadır.

Erişimci ile init Nesne Başlatıcıları

Tasarlanan nesnede kimsenin değişiklik yapmamasını sağlamak bir init erişimci kullanılarak sınırlandırılabilir. Özellik değerinin ayarını kısıtlamaya yardımcı olur.

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; init; }
}

// The `LastName` property can be set only during initialization. It CAN'T be modified afterwards.
// The `FirstName` property can be modified after initialization.
var pet = new Person() { FirstName = "Joe", LastName = "Doe"};

// You can assign the FirstName property to a different value.
pet.FirstName = "Jane";

// Compiler error:
// Error CS8852  Init - only property or indexer 'Person.LastName' can only be assigned in an object initializer,
//               or on 'this' or 'base' in an instance constructor or an 'init' accessor.
// pet.LastName = "Kowalski";

Gerekli yalnızca başlatma özellikleri sabit yapıları desteklerken, bu türdeki kullanıcılar için doğal söz dizimine izin verir.

Sınıf türündeki özelliklere sahip Nesne Başlatıcılar

Bir nesneyi başlatırken, özellikle de geçerli örneği yeniden kullanırken, sınıf türündeki özelliklerin etkilerini göz önünde bulundurmak çok önemlidir.

public class HowToClassTypedInitializer
{
    public class EmbeddedClassTypeA
    {
        public int I { get; set; }
        public bool B { get; set; }
        public string S { get; set; }
        public EmbeddedClassTypeB ClassB { get; set; }

        public override string ToString() => $"{I}|{B}|{S}|||{ClassB}";

        public EmbeddedClassTypeA()
        {
            Console.WriteLine($"Entering EmbeddedClassTypeA constructor. Values are: {this}");
            I = 3;
            B = true;
            S = "abc";
            ClassB = new() { BB = true, BI = 43 };
            Console.WriteLine($"Exiting EmbeddedClassTypeA constructor. Values are: {this})");
        }
    }

    public class EmbeddedClassTypeB
    {
        public int BI { get; set; }
        public bool BB { get; set; }
        public string BS { get; set; }

        public override string ToString() => $"{BI}|{BB}|{BS}";

        public EmbeddedClassTypeB()
        {
            Console.WriteLine($"Entering EmbeddedClassTypeB constructor. Values are: {this}");
            BI = 23;
            BB = false;
            BS = "BBBabc";
            Console.WriteLine($"Exiting EmbeddedClassTypeB constructor. Values are: {this})");
        }
    }

    public static void Main()
    {
        var a = new EmbeddedClassTypeA
        {
            I = 103,
            B = false,
            ClassB = { BI = 100003 }
        };
        Console.WriteLine($"After initializing EmbeddedClassTypeA: {a}");

        var a2 = new EmbeddedClassTypeA
        {
            I = 103,
            B = false,
            ClassB = new() { BI = 100003 } //New instance
        };
        Console.WriteLine($"After initializing EmbeddedClassTypeA a2: {a2}");
    }

    // Output:
    //Entering EmbeddedClassTypeA constructor Values are: 0|False||||
    //Entering EmbeddedClassTypeB constructor Values are: 0|False|
    //Exiting EmbeddedClassTypeB constructor Values are: 23|False|BBBabc)
    //Exiting EmbeddedClassTypeA constructor Values are: 3|True|abc|||43|True|BBBabc)
    //After initializing EmbeddedClassTypeA: 103|False|abc|||100003|True|BBBabc
    //Entering EmbeddedClassTypeA constructor Values are: 0|False||||
    //Entering EmbeddedClassTypeB constructor Values are: 0|False|
    //Exiting EmbeddedClassTypeB constructor Values are: 23|False|BBBabc)
    //Exiting EmbeddedClassTypeA constructor Values are: 3|True|abc|||43|True|BBBabc)
    //Entering EmbeddedClassTypeB constructor Values are: 0|False|
    //Exiting EmbeddedClassTypeB constructor Values are: 23|False|BBBabc)
    //After initializing EmbeddedClassTypeA a2: 103|False|abc|||100003|False|BBBabc
}

Aşağıdaki örnekte, ClassB için başlatma işleminin özgün örnekteki diğer değerleri korurken belirli değerleri güncelleştirmeyi nasıl içerdiği gösterilmektedir. Başlatıcı geçerli örneği yeniden kullanır: ClassB'nin değerleri şunlardır: 100003 (burada atadığımız yeni değer), true (EmbeddedClassTypeA'nın başlatılmasından korunur), BBBabc (EmbeddedClassTypeB'den değişmeyen varsayılan değer)

Koleksiyon başlatıcıları

Koleksiyon başlatıcıları, örnek yöntemi veya uzantı yöntemi olarak uygun imzayı uygulayan IEnumerable ve içeren Add bir koleksiyon türünü başlatırken bir veya daha fazla öğe başlatıcı belirtmenize olanak tanır. Öğe başlatıcıları basit bir değer, ifade veya nesne başlatıcı olabilir. Koleksiyon başlatıcı kullanarak birden çok çağrı belirtmeniz gerekmez; derleyicisi çağrıları otomatik olarak ekler.

Aşağıdaki örnekte iki basit koleksiyon başlatıcı gösterilmektedir:

List<int> digits = new List<int> { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };  
List<int> digits2 = new List<int> { 0 + 1, 12 % 3, MakeInt() };  

Aşağıdaki koleksiyon başlatıcı, önceki örnekte tanımlanan sınıfın Cat nesnelerini başlatmak için nesne başlatıcıları kullanır. Nesne başlatıcıların tek tek küme ayraçları içine alındığına ve virgüllerle ayrıldığına dikkat edin.

List<Cat> cats = new List<Cat>
{
    new Cat{ Name = "Sylvester", Age=8 },
    new Cat{ Name = "Whiskers", Age=2 },
    new Cat{ Name = "Sasha", Age=14 }
};

Koleksiyonun yöntemi izin veriyorsa, bir koleksiyon başlatıcıda Add öğe olarak null belirtebilirsiniz.

List<Cat?> moreCats = new List<Cat?>
{
    new Cat{ Name = "Furrytail", Age=5 },
    new Cat{ Name = "Peaches", Age=4 },
    null
};

Koleksiyon okuma/yazma dizin oluşturmayı destekliyorsa dizine alınan öğeleri belirtebilirsiniz.

var numbers = new Dictionary<int, string>
{
    [7] = "seven",
    [9] = "nine",
    [13] = "thirteen"
};

Yukarıdaki örnek, değerleri ayarlamak için öğesini Item[TKey] çağıran kod oluşturur. Aşağıdaki söz dizimini kullanarak sözlükleri ve diğer ilişkilendirici kapsayıcıları da başlatabilirsiniz. Dizin oluşturucu söz dizimi yerine parantez ve atama yerine birden çok değer içeren bir nesne kullandığına dikkat edin:

var moreNumbers = new Dictionary<int, string>
{
    {19, "nineteen" },
    {23, "twenty-three" },
    {42, "forty-two" }
};

Bu başlatıcı örneği, üç öğeyi sözlüğe eklemek için çağırır Add(TKey, TValue) . İlişkili koleksiyonları başlatmanın bu iki farklı yolu, derleyicinin oluşturduğu yöntem çağrıları nedeniyle biraz farklı davranışlara sahiptir. Her iki değişken de sınıfıyla Dictionary çalışır. Diğer türler, genel API'lerine göre yalnızca birini veya diğerini destekleyemeyebilir.

Koleksiyon salt okunur özellik başlatma ile Nesne Başlatıcıları

Bazı sınıflar, aşağıdaki örnekte özelliği gibi CatsCatOwner özelliğin salt okunur olduğu koleksiyon özelliklerine sahip olabilir:

public class CatOwner
{
    public IList<Cat> Cats { get; } = new List<Cat>();
}

Özelliğe yeni bir liste atanamadığından, şu ana kadar açıklanan koleksiyon başlatıcı söz dizimini kullanamayacaksınız:

CatOwner owner = new CatOwner
{
    Cats = new List<Cat>
    {
        new Cat{ Name = "Sylvester", Age=8 },
        new Cat{ Name = "Whiskers", Age=2 },
        new Cat{ Name = "Sasha", Age=14 }
    }
};

Ancak, aşağıda gösterildiği gibi liste oluşturma ()new List<Cat> atlanarak başlatma söz dizimi kullanılarak yeni girdiler eklenebilirCats:

CatOwner owner = new CatOwner
{
    Cats =
    {
        new Cat{ Name = "Sylvester", Age=8 },
        new Cat{ Name = "Whiskers", Age=2 },
        new Cat{ Name = "Sasha", Age=14 }
    }
};

Eklenecek girdi kümesi, küme ayraçlarıyla çevrelenmiş olarak görünür. Yukarıdakiler yazma işlemiyle aynıdır:

CatOwner owner = new CatOwner();
owner.Cats.Add(new Cat{ Name = "Sylvester", Age=8 });
owner.Cats.Add(new Cat{ Name = "Whiskers", Age=2 });
owner.Cats.Add(new Cat{ Name = "Sasha", Age=14 });

Örnekler

Aşağıdaki örnek, nesne ve koleksiyon başlatıcı kavramlarını birleştirir.

public class InitializationSample
{
    public class Cat
    {
        // Auto-implemented properties.
        public int Age { get; set; }
        public string? Name { get; set; }

        public Cat() { }

        public Cat(string name)
        {
            Name = name;
        }
    }

    public static void Main()
    {
        Cat cat = new Cat { Age = 10, Name = "Fluffy" };
        Cat sameCat = new Cat("Fluffy"){ Age = 10 };

        List<Cat> cats = new List<Cat>
        {
            new Cat { Name = "Sylvester", Age = 8 },
            new Cat { Name = "Whiskers", Age = 2 },
            new Cat { Name = "Sasha", Age = 14 }
        };

        List<Cat?> moreCats = new List<Cat?>
        {
            new Cat { Name = "Furrytail", Age = 5 },
            new Cat { Name = "Peaches", Age = 4 },
            null
        };

        // Display results.
        System.Console.WriteLine(cat.Name);

        foreach (Cat c in cats)
            System.Console.WriteLine(c.Name);

        foreach (Cat? c in moreCats)
            if (c != null)
                System.Console.WriteLine(c.Name);
            else
                System.Console.WriteLine("List element has null value.");
    }
    // Output:
    //Fluffy
    //Sylvester
    //Whiskers
    //Sasha
    //Furrytail
    //Peaches
    //List element has null value.
}

Aşağıdaki örnekte, birden çok parametreye sahip bir yöntem uygulayan IEnumerable ve içeren bir Add nesne gösterilmektedir. Bu nesne, listedeki öğe başına yöntemin imzasına karşılık gelen öğe başına birden çok öğe içeren bir koleksiyon başlatıcısı Add kullanır.

    public class FullExample
    {
        class FormattedAddresses : IEnumerable<string>
        {
            private List<string> internalList = new List<string>();
            public IEnumerator<string> GetEnumerator() => internalList.GetEnumerator();

            System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => internalList.GetEnumerator();

            public void Add(string firstname, string lastname,
                string street, string city,
                string state, string zipcode) => internalList.Add(
                $@"{firstname} {lastname}
{street}
{city}, {state} {zipcode}"
                );
        }

        public static void Main()
        {
            FormattedAddresses addresses = new FormattedAddresses()
            {
                {"John", "Doe", "123 Street", "Topeka", "KS", "00000" },
                {"Jane", "Smith", "456 Street", "Topeka", "KS", "00000" }
            };

            Console.WriteLine("Address Entries:");

            foreach (string addressEntry in addresses)
            {
                Console.WriteLine("\r\n" + addressEntry);
            }
        }

        /*
         * Prints:

            Address Entries:

            John Doe
            123 Street
            Topeka, KS 00000

            Jane Smith
            456 Street
            Topeka, KS 00000
         */
    }

Add yöntemleri, aşağıdaki örnekte gösterildiği gibi değişken sayıda bağımsız değişken almak için anahtar sözcüğünü kullanabilir params . Bu örnek, dizinleri kullanarak bir koleksiyonu başlatmak için dizin oluşturucunun özel uygulamasını da gösterir.

public class DictionaryExample
{
    class RudimentaryMultiValuedDictionary<TKey, TValue> : IEnumerable<KeyValuePair<TKey, List<TValue>>> where TKey : notnull
    {
        private Dictionary<TKey, List<TValue>> internalDictionary = new Dictionary<TKey, List<TValue>>();

        public IEnumerator<KeyValuePair<TKey, List<TValue>>> GetEnumerator() => internalDictionary.GetEnumerator();

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => internalDictionary.GetEnumerator();

        public List<TValue> this[TKey key]
        {
            get => internalDictionary[key];
            set => Add(key, value);
        }

        public void Add(TKey key, params TValue[] values) => Add(key, (IEnumerable<TValue>)values);

        public void Add(TKey key, IEnumerable<TValue> values)
        {
            if (!internalDictionary.TryGetValue(key, out List<TValue>? storedValues))
                internalDictionary.Add(key, storedValues = new List<TValue>());

            storedValues.AddRange(values);
        }
    }

    public static void Main()
    {
        RudimentaryMultiValuedDictionary<string, string> rudimentaryMultiValuedDictionary1
            = new RudimentaryMultiValuedDictionary<string, string>()
            {
                {"Group1", "Bob", "John", "Mary" },
                {"Group2", "Eric", "Emily", "Debbie", "Jesse" }
            };
        RudimentaryMultiValuedDictionary<string, string> rudimentaryMultiValuedDictionary2
            = new RudimentaryMultiValuedDictionary<string, string>()
            {
                ["Group1"] = new List<string>() { "Bob", "John", "Mary" },
                ["Group2"] = new List<string>() { "Eric", "Emily", "Debbie", "Jesse" }
            };
        RudimentaryMultiValuedDictionary<string, string> rudimentaryMultiValuedDictionary3
            = new RudimentaryMultiValuedDictionary<string, string>()
            {
                {"Group1", new string []{ "Bob", "John", "Mary" } },
                { "Group2", new string[]{ "Eric", "Emily", "Debbie", "Jesse" } }
            };

        Console.WriteLine("Using first multi-valued dictionary created with a collection initializer:");

        foreach (KeyValuePair<string, List<string>> group in rudimentaryMultiValuedDictionary1)
        {
            Console.WriteLine($"\r\nMembers of group {group.Key}: ");

            foreach (string member in group.Value)
            {
                Console.WriteLine(member);
            }
        }

        Console.WriteLine("\r\nUsing second multi-valued dictionary created with a collection initializer using indexing:");

        foreach (KeyValuePair<string, List<string>> group in rudimentaryMultiValuedDictionary2)
        {
            Console.WriteLine($"\r\nMembers of group {group.Key}: ");

            foreach (string member in group.Value)
            {
                Console.WriteLine(member);
            }
        }
        Console.WriteLine("\r\nUsing third multi-valued dictionary created with a collection initializer using indexing:");

        foreach (KeyValuePair<string, List<string>> group in rudimentaryMultiValuedDictionary3)
        {
            Console.WriteLine($"\r\nMembers of group {group.Key}: ");

            foreach (string member in group.Value)
            {
                Console.WriteLine(member);
            }
        }
    }

    /*
     * Prints:

        Using first multi-valued dictionary created with a collection initializer:

        Members of group Group1:
        Bob
        John
        Mary

        Members of group Group2:
        Eric
        Emily
        Debbie
        Jesse

        Using second multi-valued dictionary created with a collection initializer using indexing:

        Members of group Group1:
        Bob
        John
        Mary

        Members of group Group2:
        Eric
        Emily
        Debbie
        Jesse

        Using third multi-valued dictionary created with a collection initializer using indexing:

        Members of group Group1:
        Bob
        John
        Mary

        Members of group Group2:
        Eric
        Emily
        Debbie
        Jesse
     */
}

Ayrıca bkz.