Null olabilecek başvuru türünü denetlemek için .NET yansıması nasıl kullanılır


15

C # 8.0 nullable referans türleri sunar. İşte nullable özelliğine sahip basit bir sınıf:

public class Foo
{
    public String? Bar { get; set; }
}

Yansıma yoluyla null olabilecek bir başvuru türü kullanarak bir sınıf özelliğini kontrol etmenin bir yolu var mı?


Bu ekler gibi derleme ve IL bakarak, görünüşe [NullableContext(2), Nullable((byte) 0)]göre tip ( Foo) - böylece kontrol etmek ama bunu nasıl yorumlanacağı kurallarını anlamak için daha derinlere inmek gerekiyordu neyi en!
Marc Gravell

4
Evet, ama önemsiz değil. Neyse ki, bir belgelenmiş .
Jeroen Mostert

Ah, anlıyorum; bu yüzden string? Xhiçbir özellik string Yalır ve erişimciler [Nullable((byte)2)]ile alır[NullableContext(2)]
Marc Gravell

1
Bir tür yalnızca nullables (veya nullables) içeriyorsa, hepsi tarafından temsil edilir NullableContext. Bir karışım varsa, o zaman da Nullablekullanılır. NullableContextdenemek ve Nullableher yere yaymak zorunda kalmamak için bir optimizasyon .
canton7

Yanıtlar:


11

Bu, en azından test ettiğim türlerde işe yarıyor gibi görünüyor.

Sen geçmesi gerekiyor PropertyInfoayrıca ilgilendiğiniz özelliği için ve Typebu özellik üzerinde tanımlanan ( değil türetilmiş bir ya da ebeveyn tipi - bu kesin türü olmak zorunda):

public static bool IsNullable(Type enclosingType, PropertyInfo property)
{
    if (!enclosingType.GetProperties(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly).Contains(property))
        throw new ArgumentException("enclosingType must be the type which defines property");

    var nullable = property.CustomAttributes
        .FirstOrDefault(x => x.AttributeType.FullName == "System.Runtime.CompilerServices.NullableAttribute");
    if (nullable != null && nullable.ConstructorArguments.Count == 1)
    {
        var attributeArgument = nullable.ConstructorArguments[0];
        if (attributeArgument.ArgumentType == typeof(byte[]))
        {
            var args = (ReadOnlyCollection<CustomAttributeTypedArgument>)attributeArgument.Value;
            if (args.Count > 0 && args[0].ArgumentType == typeof(byte))
            {
                return (byte)args[0].Value == 2;
            }
        }
        else if (attributeArgument.ArgumentType == typeof(byte))
        {
            return (byte)attributeArgument.Value == 2;
        }
    }

    var context = enclosingType.CustomAttributes
        .FirstOrDefault(x => x.AttributeType.FullName == "System.Runtime.CompilerServices.NullableContextAttribute");
    if (context != null &&
        context.ConstructorArguments.Count == 1 &&
        context.ConstructorArguments[0].ArgumentType == typeof(byte))
    {
        return (byte)context.ConstructorArguments[0].Value == 2;
    }

    // Couldn't find a suitable attribute
    return false;
}

Ayrıntılar için bu belgeye bakın.

Genel [Nullable]öznitelik, ya özelliğin kendisinde bir özniteliğe sahip olabileceği ya da içermeyen türde bir [NullableContext]özniteliğe sahip olabileceğidir . Önce ararız [Nullable], o zaman bulamazsak [NullableContext], kapalı tipte ararız.

Derleyici öznitelikleri derlemeye gömebilir ve farklı bir derlemeden bir türe baktığımız için, yalnızca yansıma yükü yapmamız gerekir.

[Nullable]özellik genelse bir dizi ile başlatılabilir. Bu durumda, ilk öğe gerçek özelliği temsil eder (ve diğer öğeler genel bağımsız değişkenleri temsil eder). [NullableContext]her zaman tek bir bayt ile başlatılır.

Değeri 2vasıtası "olabilecek". 1"boş bırakılamaz" ve 0"kayıtsız" anlamına gelir.


Gerçekten zor. Sadece bu kod kapsamında olmayan bir kullanım durumu buldum. Kamu arayüz IBusinessRelation : ICommon {}/ public interface ICommon { string? Name {get;set;} }. IBusinessRelationÖzellik ile yöntemi çağırırsanız Nameyanlış alıyorum.
gsharp

@gsharp Ah, bunu arayüzlerle ya da herhangi bir mirasla denememiştim. Ben nispeten kolay bir düzeltme (temel arayüzlerden bağlam özniteliklerine bakın): Daha sonra deneyeceğim
canton7

1
biggie yok. Sadece bahsetmek istedim. Bu boş şeyler beni deli ediyor ;-)
gsharp

1
@gsharp Baktığınızda, özelliği tanımlayan arabirimin türünü geçmeniz gerekir - yani ICommon, değil IBusinessRelation. Her arayüz kendi tanımını yapar NullableContext. Cevabımı açıkladım ve bunun için bir çalışma zamanı kontrolü ekledim.
canton7
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.