Yapı türleri (C# başvurusu)

Yapı türü (veya yapı türü), verileri ve ilgili işlevleri kapsülleyebilecek bir değer türüdür. Bir yapı türü tanımlamak için anahtar sözcüğünü struct kullanırsınız:

public struct Coords
{
    public Coords(double x, double y)
    {
        X = x;
        Y = y;
    }

    public double X { get; }
    public double Y { get; }

    public override string ToString() => $"({X}, {Y})";
}

ref struct türleri ve readonly ref struct türleri başvuru yapısı türleri makalesinde ele alınmıştır.

Yapı türlerinin değer semantiği vardır. Yani, bir yapı türünün değişkeni türün bir örneğini içerir. Varsayılan olarak, değişken değerleri atamada kopyalanır, bir bağımsız değişken yönteme geçirilir ve yöntem sonucu döndürüler. Yapı türü değişkenleri için, türün bir örneği kopyalanır. Daha fazla bilgi için bkz . Değer türleri.

Genellikle, çok az davranış sağlayan veya hiç davranış sağlamayan küçük veri odaklı türler tasarlamak için yapı türlerini kullanırsınız. Örneğin, .NET bir sayıyı ( hem tamsayı hem de gerçek), Boole değerini, Unicode karakterini ve zaman örneğini temsil etmek için yapı türlerini kullanır. Bir türün davranışına odaklandıysanız bir sınıf tanımlamayı göz önünde bulundurun. Sınıf türleri başvuru semantiğine sahiptir. Diğer bir ifadeyle, sınıf türündeki bir değişken, örneğin kendisine değil, türün bir örneğine başvuru içerir.

Yapı türleri değer semantiğine sahip olduğundan sabit yapı türlerini tanımlamanızı öneririz.

readonly Yapı

Bir yapı türünün sabit olduğunu bildirmek için değiştiriciyi kullanırsınız readonly . Bir readonly yapının tüm veri üyeleri aşağıdaki gibi salt okunur olmalıdır:

  • Herhangi bir alan bildiriminde readonly değiştirici olmalıdır
  • Otomatik uygulananlar da dahil olmak üzere tüm özellikler salt okunur olmalıdır. C# 9.0 ve sonraki sürümlerde bir özelliğin erişimcisiinit olabilir.

Bu, hiçbir readonly yapı üyesinin yapı durumunu değiştirmesini garanti eder. Bu, oluşturucular dışındaki diğer örnek üyelerinin örtük olduğu readonlyanlamına gelir.

Not

Yapıda readonly , değiştirilebilir başvuru türünün veri üyesi yine de kendi durumunu sessize alabilir. Örneğin, bir List<T> örneği değiştiremezsiniz, ancak örneğine yeni öğeler ekleyebilirsiniz.

Aşağıdaki kod, C# 9.0 ve sonraki sürümlerde kullanılabilen init-only özellik ayarlayıcılarıyla bir readonly yapı tanımlar:

public readonly struct Coords
{
    public Coords(double x, double y)
    {
        X = x;
        Y = y;
    }

    public double X { get; init; }
    public double Y { get; init; }

    public override string ToString() => $"({X}, {Y})";
}

readonly örnek üyeleri

Bir örnek üyesinin readonly bir yapı durumunu değiştirmediğini bildirmek için değiştiriciyi de kullanabilirsiniz. Yapı türünün tamamını olarak readonlybildiremiyorsanız, yapısının readonly durumunu değiştirmeyen örnek üyelerini işaretlemek için değiştiriciyi kullanın.

Bir readonly örnek üyesi içinde, yapının örnek alanlarına atayamazsınız. Ancak, üye readonly olmayanreadonly bir üyeyi çağırabilir. Bu durumda derleyici, yapı örneğinin bir kopyasını oluşturur ve bu kopyada üye olmayanıreadonly çağırır. Sonuç olarak, özgün yapı örneği değiştirilmez.

Genellikle değiştiriciyi readonly aşağıdaki örnek üyelerine uygularsınız:

  • Yöntemler:

    public readonly double Sum()
    {
        return X + Y;
    }
    

    Değiştiriciyi readonly içinde bildirilen System.Objectyöntemleri geçersiz kılan yöntemlere de uygulayabilirsiniz:

    public readonly override string ToString() => $"({X}, {Y})";
    
  • özellikler ve dizin oluşturucular:

    private int counter;
    public int Counter
    {
        readonly get => counter;
        set => counter = value;
    }
    

    Değiştiriciyi bir özelliğin readonly veya dizin oluşturucunun her iki erişimcisine de uygulamanız gerekiyorsa, özelliğin veya dizin oluşturucunun bildiriminde uygulayın.

    Not

    Derleyici, otomatik uygulanan bir getözelliğin erişimcisini, bir özellik bildiriminde değiştiricinin readonly varlığına bakılmaksızın olarak readonlybildirir.

    C# 9.0 ve sonraki sürümlerde değiştiriciyi erişimciye readonly sahip init bir özelliğe veya dizin oluşturucuya uygulayabilirsiniz:

    public readonly double X { get; init; }
    

Değiştiriciyi readonly bir yapı türünün statik alanlarına uygulayabilirsiniz, ancak özellikler veya yöntemler gibi diğer statik üyelere uygulayamayın.

Derleyici, performans iyileştirmeleri için değiştiriciyi readonly kullanabilir. Daha fazla bilgi için bkz . Güvenli ve verimli C# kodu yazma.

Yıkıcı olmayan mutasyon

C# 10'undan başlayarak, belirtilen özelliklerin ve alanların değiştirildiği bir yapı türü örneğinin kopyasını oluşturmak için ifadeyi kullanabilirsinizwith. Aşağıdaki örnekte gösterildiği gibi, hangi üyelerin değiştirileceğini ve yeni değerlerini belirtmek için nesne başlatıcı söz dizimini kullanırsınız:

public readonly struct Coords
{
    public Coords(double x, double y)
    {
        X = x;
        Y = y;
    }

    public double X { get; init; }
    public double Y { get; init; }

    public override string ToString() => $"({X}, {Y})";
}

public static void Main()
{
    var p1 = new Coords(0, 0);
    Console.WriteLine(p1);  // output: (0, 0)

    var p2 = p1 with { X = 3 };
    Console.WriteLine(p2);  // output: (3, 0)

    var p3 = p1 with { X = 1, Y = 4 };
    Console.WriteLine(p3);  // output: (1, 4)
}

record Yapı

C# 10'da kayıt yapısı türlerini tanımlayabilirsiniz. Kayıt türleri, verileri kapsüllemek için yerleşik işlevler sağlar. Hem readonly record struct hem de record struct türlerini tanımlayabilirsiniz. Kayıt yapısı bir ref structolamaz. Daha fazla bilgi ve örnek için bkz. Kayıtlar.

Yapı başlatma ve varsayılan değerler

Bir struct türün değişkeni doğrudan ilgili structiçin verileri içerir. Bu, varsayılan değerine sahip başlatılmamış structbir ile onu oluşturarak ayarlanan değerleri depolayan başlatılan structbir arasında ayrım oluşturur. Örneğin aşağıdaki kodu göz önünde bulundurun:

public readonly struct Measurement
{
    public Measurement()
    {
        Value = double.NaN;
        Description = "Undefined";
    }

    public Measurement(double value, string description)
    {
        Value = value;
        Description = description;
    }

    public double Value { get; init; }
    public string Description { get; init; }

    public override string ToString() => $"{Value} ({Description})";
}

public static void Main()
{
    var m1 = new Measurement();
    Console.WriteLine(m1);  // output: NaN (Undefined)

    var m2 = default(Measurement);
    Console.WriteLine(m2);  // output: 0 ()

    var ms = new Measurement[2];
    Console.WriteLine(string.Join(", ", ms));  // output: 0 (), 0 ()
}

Yukarıdaki örnekte gösterildiği gibi, varsayılan değer ifadesi parametresiz bir oluşturucuyu yoksayar ve yapı türünün varsayılan değerini üretir. Yapı türü dizi örneği de parametresiz oluşturucuyu yoksayar ve bir yapı türünün varsayılan değerleriyle doldurulmuş bir dizi oluşturur.

Varsayılan değerleri göreceğiniz en yaygın durum dizilerde veya iç depolamanın değişken blokları içerdiği diğer koleksiyonlardadır. Aşağıdaki örnek, her biri varsayılan değere sahip olan 30 TemperatureRange yapıdan oluşan bir dizi oluşturur:

// All elements have default values of 0:
TemperatureRange[] lastMonth = new TemperatureRange[30];

Türler verilerini doğrudan depoladığından, bir yapının üye alanlarının tümü oluşturulduğunda structkesinlikle atanmalıdır. Bir default yapı değeri kesinlikle tüm alanları 0'a atamıştır . Bir oluşturucu çağrıldığında tüm alanlar kesinlikle atanmalıdır. Aşağıdaki mekanizmaları kullanarak alanları başlatırsınız:

  • Herhangi bir alana veya otomatik uygulanan özelliğe alan başlatıcıları ekleyebilirsiniz.
  • Oluşturucunun gövdesinde herhangi bir alanı veya otomatik özellikleri başlatabilirsiniz.

C# 11 ile başlayarak, bir yapıdaki tüm alanları başlatmazsanız, derleyici bu alanları varsayılan değere başlatan oluşturucuya kod ekler. Derleyici, her zamanki kesin atama analizini gerçekleştirir. Atanmadan önce erişilen veya oluşturucu yürütmeyi tamamladığında kesinlikle atanmayan tüm alanlar, oluşturucu gövdesi yürütülmeden önce varsayılan değerlerine atanır. Tüm alanlar atanmadan önce erişilirse this , yapı oluşturucu gövdesi yürütülmeden önce varsayılan değere başlatılır.

public readonly struct Measurement
{
    public Measurement(double value)
    {
        Value = value;
    }

    public Measurement(double value, string description)
    {
        Value = value;
        Description = description;
    }

    public Measurement(string description)
    {
        Description = description;
    }

    public double Value { get; init; }
    public string Description { get; init; } = "Ordinary measurement";

    public override string ToString() => $"{Value} ({Description})";
}

public static void Main()
{
    var m1 = new Measurement(5);
    Console.WriteLine(m1);  // output: 5 (Ordinary measurement)

    var m2 = new Measurement();
    Console.WriteLine(m2);  // output: 0 ()

    var m3 = default(Measurement);
    Console.WriteLine(m3);  // output: 0 ()
}

Her struct parametresiz oluşturucuya sahiptir public . Parametresiz bir oluşturucu yazarsanız, ortak olmalıdır. Bir yapı herhangi bir alan başlatıcı bildirirse, açıkça bir oluşturucu bildirmesi gerekir. Bu oluşturucu parametresiz olmamalıdır. Yapı bir alan başlatıcı bildirir ancak oluşturucu bildirmezse, derleyici bir hata bildirir. Açıkça bildirilen herhangi bir oluşturucu (parametrelerle veya parametresiz) bu yapı için tüm alan başlatıcıları yürütür. Alan başlatıcısı veya oluşturucuda ataması olmayan tüm alanlar varsayılan değere ayarlanır. Daha fazla bilgi için parametresiz yapı oluşturucuları özellik teklifi notunu inceleyin.

Bir yapı türünün tüm örnek alanları erişilebilir durumdaysa, işleci olmadan new da örneği oluşturabilirsiniz. Bu durumda, örneğin ilk kullanımından önce tüm örnek alanlarını başlatmanız gerekir. Aşağıdaki örnekte bunun nasıl yapıldığını gösterilmektedir:

public static class StructWithoutNew
{
    public struct Coords
    {
        public double x;
        public double y;
    }

    public static void Main()
    {
        Coords p;
        p.x = 3;
        p.y = 4;
        Console.WriteLine($"({p.x}, {p.y})");  // output: (3, 4)
    }
}

Yerleşik değer türleri söz konusu olduğunda, türün değerini belirtmek için karşılık gelen değişmez değerleri kullanın.

Yapı türünün tasarımıyla ilgili sınırlamalar

Yapılar, bir sınıf türünün özelliklerinin çoğuna sahiptir. Bazı özel durumlar ve daha yeni sürümlerde kaldırılan bazı özel durumlar vardır:

  • Yapı türü diğer sınıf veya yapı türünden devralamaz ve bir sınıfın temeli olamaz. Ancak, bir yapı türü arabirimleri uygulayabilir.
  • Yapı türü içinde sonlandırıcı bildiremezsiniz.
  • C# 11'in öncesinde, bir yapı türünün oluşturucusunun türün tüm örnek alanlarını başlatması gerekir.
  • C# 10'un öncesinde parametresiz oluşturucu bildiremezsiniz.
  • C# 10'un öncesinde, bir örnek alanını veya özelliğini bildiriminde başlatamazsınız.

Yapı türündeki değişkenleri başvuruya göre geçirme

Bir yapı türü değişkenini bir yönteme bağımsız değişken olarak geçirdiğinizde veya bir yöntemden yapı türü değeri döndürdüyseniz, yapı türünün tüm örneği kopyalanır. Değere göre geçiş, büyük yapı türleri içeren yüksek performanslı senaryolarda kodunuzun performansını etkileyebilir. Başvuruya göre bir yapı türü değişkeni geçirerek değer kopyalamayı önleyebilirsiniz. Bir bağımsız değişkenin refbaşvuruyla geçirilmesi gerektiğini belirtmek için , outveya in yöntem parametresi değiştiricilerini kullanın. Başvuruya göre bir yöntem sonucu döndürmek için başv dönüşlerini kullanın. Daha fazla bilgi için bkz . Güvenli ve verimli C# kodu yazma.

yapı kısıtlaması

Tür parametresinin struct null değer atanamayan bir değer türü olduğunu belirtmek için kısıtlamadastruct anahtar sözcüğünü de kullanırsınız. Hem yapı hem de numaralandırma türleri kısıtlamayı karşılar struct .

Dönüşümler

Herhangi bir yapı türü (türler dışındaref struct) için ve türlerine ve türlerine yönelik ve türlerinden System.ValueTypeSystem.Objectgelen kutulama ve kutu açma dönüştürmeleri vardır. Ayrıca bir yapı türü ile uyguladığı arabirimler arasında kutulama ve kutu açma dönüştürmeleri de vardır.

C# dili belirtimi

Daha fazla bilgi için C# dil belirtimininYapılar bölümüne bakın.

Özellikler hakkında struct daha fazla bilgi için aşağıdaki özellik teklifi notlarını inceleyin:

Ayrıca bkz.