Aracılığıyla paylaş


Properties

Özellikler C# dilinde birinci sınıf vatandaşlardır. Dil, geliştiricilerin tasarım amaçlarını doğru şekilde ifade eden kod yazmasına olanak tanıyan söz dizimini tanımlar.

Özelliklere erişildiğinde alanlar gibi davranır. Ancak, alanlardan farklı olarak, özellikler bir özelliğe erişildiğinde veya atandığında yürütülen deyimleri tanımlayan erişimcilerle birlikte uygulanır.

Özellik söz dizimi

Özelliklerin söz dizimi, alanlara yönelik doğal bir uzantıdır. Bir alan bir depolama konumu tanımlar:

public class Person
{
    public string? FirstName;

    // Omitted for brevity.
}

Özellik tanımı, bir get ve set erişimcisi için bu özelliğin değerini alan ve atayan bildirimler içerir:

public class Person
{
    public string? FirstName { get; set; }

    // Omitted for brevity.
}

Yukarıda gösterilen söz dizimi otomatik özellik söz dizimidir. Derleyici, özelliği yedekleyen alan için depolama konumunu oluşturur. Derleyici ayrıca ve set erişimcilerinin gövdesini get de uygular.

Bazen, bir özelliği türü için varsayılan değer dışında bir değere başlatmanız gerekir. C# özelliği için kapanış ayracından sonra bir değer ayarlayarak bunu etkinleştirir. özelliği için ilk değerin FirstName yerine nullboş dize olmasını tercih edebilirsiniz. Aşağıda gösterildiği gibi bunu belirtebilirsiniz:

public class Person
{
    public string FirstName { get; set; } = string.Empty;

    // Omitted for brevity.
}

Bu makalenin devamında göreceğiniz gibi, özel başlatma en çok salt okunur özellikler için kullanışlıdır.

Aşağıda gösterildiği gibi depolama alanını kendiniz de tanımlayabilirsiniz:

public class Person
{
    public string? FirstName
    {
        get { return _firstName; }
        set { _firstName = value; }
    }
    private string? _firstName;

    // Omitted for brevity.
}

Özellik uygulaması tek bir ifade olduğunda, alıcı veya ayarlayıcı için ifade gövdeli üyeleri kullanabilirsiniz:

public class Person
{
    public string? FirstName
    {
        get => _firstName;
        set => _firstName = value;
    }
    private string? _firstName;

    // Omitted for brevity.
}

Bu basitleştirilmiş söz dizimi, bu makale boyunca uygun olduğunda kullanılacaktır.

Yukarıda gösterilen özellik tanımı bir okuma-yazma özelliğidir. Küme erişimcisindeki anahtar sözcüğüne value dikkat edin. Erişimcinin set her zaman adlı valuetek bir parametresi vardır. Erişimci özelliğin get türüne dönüştürülebilir bir değer döndürmelidir (string bu örnekte).

Söz diziminin temelleri bunlardır. Çeşitli farklı tasarım deyimlerini destekleyen birçok farklı varyasyon vardır. Şimdi her biri için söz dizimi seçeneklerini keşfedelim ve öğrenelim.

Doğrulama

Yukarıdaki örneklerde, özellik tanımının en basit örneklerinden biri gösterilmiştir: doğrulama içermeyen bir okuma-yazma özelliği. ve set erişimcilerine get istediğiniz kodu yazarak birçok farklı senaryo oluşturabilirsiniz.

Bir özellik tarafından temsil edilen değerlerin set her zaman geçerli olduğundan emin olmak için erişimciye kod yazabilirsiniz. Örneğin, sınıf için bir kuralın Person adın boş veya boş alan olamaz olduğunu varsayalım. Bunu aşağıdaki gibi yazabilirsiniz:

public class Person
{
    public string? FirstName
    {
        get => _firstName;
        set
        {
            if (string.IsNullOrWhiteSpace(value))
                throw new ArgumentException("First name must not be blank");
            _firstName = value;
        }
    }
    private string? _firstName;

    // Omitted for brevity.
}

Yukarıdaki örnek, özellik ayarlayıcısı doğrulamasının bir parçası olarak bir throw ifade kullanılarak basitleştirilebilir:

public class Person
{
    public string? FirstName
    {
        get => _firstName;
        set => _firstName = (!string.IsNullOrWhiteSpace(value)) ? value : throw new ArgumentException("First name must not be blank");
    }
    private string? _firstName;

    // Omitted for brevity.
}

Yukarıdaki örnek, adın boş veya boşluk olmaması gerektiğini belirten kuralı uygular. Geliştirici yazarsa

hero.FirstName = "";

Bu atama bir ArgumentExceptionoluşturur. Özellik kümesi erişimcisinin geçersiz dönüş türü olması gerektiğinden, özel durum oluşturarak küme erişimcisinde hataları bildirirsiniz.

Bu söz dizimini senaryonuzda gereken her şeye genişletebilirsiniz. Farklı özellikler arasındaki ilişkileri denetleyebilir veya herhangi bir dış koşula göre doğrulayabilirsiniz. Geçerli C# deyimleri bir özellik erişimcisinde geçerlidir.

Erişim denetimi

Bu noktaya kadar, gördüğünüz tüm özellik tanımları genel erişimcileri olan okuma/yazma özellikleridir. Özellikler için tek geçerli erişilebilirlik bu değildir. Salt okunur özellikler oluşturabilir veya kümeye farklı erişilebilirlik sağlayabilir ve erişimcileri alabilirsiniz. Sınıfınızın Person yalnızca bu sınıftaki diğer yöntemlerden özelliğinin FirstName değerini değiştirmeyi etkinleştirmesi gerektiğini varsayalım. Set erişimcisine private yerine erişilebilirlik publicverebilirsiniz:

public class Person
{
    public string? FirstName { get; private set; }

    // Omitted for brevity.
}

Artık özelliğine FirstName herhangi bir koddan erişilebilir, ancak yalnızca sınıfındaki Person diğer kodlardan atanabilir.

Kümeye herhangi bir kısıtlayıcı erişim değiştirici ekleyebilir veya erişimcileri alabilirsiniz. Bireysel erişimciye yerleştirdiğiniz tüm erişim değiştiriciler, özellik tanımındaki erişim değiştiriciden daha sınırlı olmalıdır. Özelliği olduğundan yukarıdaki yasaldır FirstNamepublic, ancak küme erişimcisi şeklindedir private. Bir erişimci ile public özellik private bildiremediniz. Özellik bildirimleri , , internalprotected internalveya hatta privatebildirilebilirprotected.

Erişimciye daha kısıtlayıcı değiştirici yerleştirmek de yasaldır get . Örneğin, bir public özelliğiniz olabilir, ancak erişimciyi get ile privatekısıtlayabilirsiniz. Bu senaryo pratikte nadiren gerçekleştirilir.

Salt Okunur

Ayrıca, yalnızca bir oluşturucuda ayarlanabilmesi için bir özellikte yapılan değişiklikleri kısıtlayabilirsiniz. sınıfını Person aşağıdaki gibi değiştirebilirsiniz:

public class Person
{
    public Person(string firstName) => FirstName = firstName;

    public string FirstName { get; }

    // Omitted for brevity.
}

Yalnızca başlatma

Yukarıdaki örnek, çağıranların parametresini içeren oluşturucuyu FirstName kullanmasını gerektirir. Çağıranlar, özelliğine bir değer atamak için nesne başlatıcılarını kullanamaz. Başlatıcıları desteklemek için, aşağıdaki kodda gösterildiği gibi erişimciyi bir init erişimci yapabilirsinizset:

public class Person
{
    public Person() { }
    public Person(string firstName) => FirstName = firstName;

    public string? FirstName { get; init; }

    // Omitted for brevity.
}

Yukarıdaki örnek, bir çağıranın, bu kod özelliğini ayarlamasa bile varsayılan oluşturucuyu kullanarak bir Person oluşturmasına FirstName izin verir. C# 11'den başlayarak, arayanların bu özelliği ayarlamasını gerektirebilirsiniz:

public class Person
{
    public Person() { }

    [SetsRequiredMembers]
    public Person(string firstName) => FirstName = firstName;

    public required string FirstName { get; init; }

    // Omitted for brevity.
}

Yukarıdaki kod, sınıfına Person iki ekleme yapar. İlk olarak, FirstName özellik bildirimi değiştiriciyi required içerir. Bu, yeni Person bir kod oluşturan tüm kodların bu özelliği ayarlaması gerektiği anlamına gelir. İkincisi, parametre firstName alan oluşturucu özniteliğine System.Diagnostics.CodeAnalysis.SetsRequiredMembersAttribute sahiptir. Bu öznitelik, derleyiciye bu oluşturucunun tümrequired üyeleri ayarlandığını bildirir.

Önemli

Boş değer atanamaz ile karıştırmayınrequired. bir özelliği null veya defaultolarak ayarlamak required için geçerlidir. Bu örneklerde olduğu gibi string tür null atanamazsa, derleyici bir uyarı döndürür.

Çağıranların, aşağıdaki kodda gösterildiği gibi oluşturucuyu ile SetsRequiredMembers kullanması veya nesne başlatıcı kullanarak özelliğini ayarlaması FirstName gerekir:

var person = new VersionNinePoint2.Person("John");
person = new VersionNinePoint2.Person{ FirstName = "John"};
// Error CS9035: Required member `Person.FirstName` must be set:
//person = new VersionNinePoint2.Person();

Hesaplanan özellikler

Bir özelliğin yalnızca üye alanının değerini döndürmesi gerekmez. Hesaplanan değer döndüren özellikler oluşturabilirsiniz. Şimdi, ad ve soyadları birleştirilerek hesaplanan tam adı döndürecek şekilde nesnesini genişletelim Person :

public class Person
{
    public string? FirstName { get; set; }

    public string? LastName { get; set; }

    public string FullName { get { return $"{FirstName} {LastName}"; } }
}

Yukarıdaki örnekte, tam adın biçimlendirilmiş dizesini oluşturmak için dize ilişkilendirme özelliği kullanılmaktadır.

Hesaplanan özelliği oluşturmak FullName için daha kısa bir yol sağlayan ifade gövdeli bir üye de kullanabilirsiniz:

public class Person
{
    public string? FirstName { get; set; }

    public string? LastName { get; set; }

    public string FullName => $"{FirstName} {LastName}";
}

İfade gövdeli üyeler, tek bir ifade içeren yöntemleri tanımlamak için lambda ifadesi söz dizimini kullanır. Burada, bu ifade person nesnesinin tam adını döndürür.

Önbelleğe alınan değerlendirilen özellikler

Hesaplanan özellik kavramını depolama ile karıştırabilir ve önbelleğe alınmış bir değerlendirilmiş özellik oluşturabilirsiniz. Örneğin, dize biçimlendirmesinin FullName yalnızca ilk kez erişildiğinde olması için özelliğini güncelleştirebilirsiniz:

public class Person
{
    public string? FirstName { get; set; }

    public string? LastName { get; set; }

    private string? _fullName;
    public string FullName
    {
        get
        {
            if (_fullName is null)
                _fullName = $"{FirstName} {LastName}";
            return _fullName;
        }
    }
}

Ancak yukarıdaki kod bir hata içeriyor. Kod veya LastName özelliğinin FirstName değerini güncelleştirirse, daha önce değerlendirilen fullName alan geçersiz olur. alanın yeniden hesaplanacak şekilde ve LastName özelliğinin fullName erişimcilerini FirstName değiştirirsinizset:

public class Person
{
    private string? _firstName;
    public string? FirstName
    {
        get => _firstName;
        set
        {
            _firstName = value;
            _fullName = null;
        }
    }

    private string? _lastName;
    public string? LastName
    {
        get => _lastName;
        set
        {
            _lastName = value;
            _fullName = null;
        }
    }

    private string? _fullName;
    public string FullName
    {
        get
        {
            if (_fullName is null)
                _fullName = $"{FirstName} {LastName}";
            return _fullName;
        }
    }
}

Bu son sürüm yalnızca gerektiğinde özelliğini değerlendirir FullName . Önceden hesaplanan sürüm geçerliyse kullanılır. Başka bir durum değişikliği daha önce hesaplanan sürümü geçersiz kılırsa, yeniden hesaplanır. Bu sınıfı kullanan geliştiricilerin uygulamanın ayrıntılarını bilmesi gerekmez. Bu iç değişikliklerin hiçbiri Person nesnesinin kullanımını etkilemez. Bir nesnenin veri üyelerini kullanıma açmak için Özellikleri kullanmanın temel nedeni budur.

Otomatik uygulanan özelliklere öznitelik ekleme

Alan öznitelikleri, otomatik uygulanan özelliklerde derleyici tarafından oluşturulan yedekleme alanına eklenebilir. Örneğin, sınıfına Person benzersiz bir tamsayı Id özelliği ekleyen bir düzeltme düşünün. Özelliği otomatik uygulanan bir özellik kullanarak yazarsınız Id , ancak tasarımınız özelliği kalıcı hale çağırmaz Id . NonSerializedAttribute yalnızca alanlara eklenebilir, özelliklere eklenemez. Aşağıdaki örnekte gösterildiği gibi özniteliğindeki tanımlayıcıyı field: kullanarak özelliğinin yedekleme alanına Id ekleyebilirsinizNonSerializedAttribute:

public class Person
{
    public string? FirstName { get; set; }

    public string? LastName { get; set; }

    [field:NonSerialized]
    public int Id { get; set; }

    public string FullName => $"{FirstName} {LastName}";
}

Bu teknik, otomatik uygulanan özellikteki yedekleme alanına eklediğiniz tüm öznitelikler için çalışır.

INotifyPropertyChanged Uygulama

Özellik erişimcisinde kod yazmanız gereken son senaryo, veri bağlama istemcilerine bir değerin INotifyPropertyChanged değiştiğini bildirmek için kullanılan arabirimi desteklemektir. Bir özelliğin değeri değiştiğinde, nesne değişikliği göstermek için olayı tetikler INotifyPropertyChanged.PropertyChanged . Veri bağlama kitaplıkları da bu değişikliğe göre görüntü öğelerini güncelleştirir. Aşağıdaki kod, bu kişi sınıfının özelliği için FirstName nasıl uygulayabileceğinizi INotifyPropertyChanged gösterir.

public class Person : INotifyPropertyChanged
{
    public string? FirstName
    {
        get => _firstName;
        set
        {
            if (string.IsNullOrWhiteSpace(value))
                throw new ArgumentException("First name must not be blank");
            if (value != _firstName)
            {
                _firstName = value;
                PropertyChanged?.Invoke(this,
                    new PropertyChangedEventArgs(nameof(FirstName)));
            }
        }
    }
    private string? _firstName;

    public event PropertyChangedEventHandler? PropertyChanged;
}

işleci ?. null koşullu işleç olarak adlandırılır. İşlecin sağ tarafını değerlendirmeden önce null başvuruyu denetler. Sonuç, olayın abonesi PropertyChanged yoksa olayı tetikleyen kodun yürütülmeyecek olmasıdır. Bu durumda bu çek olmadan bir NullReferenceException çek oluşturur. Daha fazla bilgi için bkz. events. Bu örnek ayrıca özellik adı simgesinden metin gösterimine dönüştürmek için yeni nameof işlecini kullanır. özelliğini nameof kullanmak, özelliğin adını yanlış yazdığınız hataları azaltabilir.

Yine uygulamak INotifyPropertyChanged , ihtiyacınız olan senaryoları desteklemek için erişimcilerinize kod yazabileceğiniz bir örnektir.

Toplama

Özellikler, bir sınıf veya nesnedeki akıllı alanların bir biçimidir. Nesnenin dışından, nesnedeki alanlar gibi görünürler. Ancak, özellikler C# işlevselliğinin tam paleti kullanılarak uygulanabilir. Doğrulama, farklı erişilebilirlik, gecikmeli değerlendirme veya senaryolarınızın ihtiyaç duyduğu gereksinimleri sağlayabilirsiniz.