วิธีการใช้. NET reflection เพื่อตรวจสอบชนิดอ้างอิง nullable


15

C # 8.0 แนะนำประเภทอ้างอิงที่ไม่มีค่า นี่คือคลาสธรรมดาที่มีคุณสมบัติเป็นโมฆะ:

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

มีวิธีการตรวจสอบทรัพย์สินชั้นใช้ประเภทอ้างอิง nullable ผ่านการสะท้อน?


การรวบรวมและการมองหาที่ IL ก็มีลักษณะเช่นนี้จะเพิ่ม[NullableContext(2), Nullable((byte) 0)]ไปที่ประเภท ( Foo) - เพื่อให้เป็นสิ่งเพื่อตรวจสอบ แต่ฉันต้องขุดเพิ่มเติมเพื่อทำความเข้าใจกฎของวิธีการตีความว่า!
Marc Gravell

4
ใช่ แต่มันไม่สำคัญ โชคดีที่มันถูก บันทึกไว้
Jeroen Mostert

อ่าฉันเข้าใจแล้ว เพื่อให้string? Xได้รับแอตทริบิวต์ไม่มีและstring Yได้รับ[Nullable((byte)2)]กับ[NullableContext(2)]ใน accessors
Marc Gravell

1
ถ้าชนิดของเพียงมี nullables (หรือไม่ nullables) NullableContextแล้วนั่นคือทั้งหมดที่แสดงโดย หากมีการผสมผสานให้Nullableใช้เช่นกัน NullableContextเป็นการเพิ่มประสิทธิภาพเพื่อพยายามหลีกเลี่ยงการปล่อยNullableทั่วสถานที่
canton7

คำตอบ:


11

สิ่งนี้ดูเหมือนจะใช้งานได้อย่างน้อยในประเภทที่ฉันทดสอบด้วย

คุณต้องผ่านPropertyInfoคุณสมบัติที่คุณสนใจและTypeคุณสมบัติที่กำหนดไว้บน ( ไม่ใช่ประเภทที่ได้รับหรือผู้ปกครอง - ต้องเป็นประเภทที่แน่นอน):

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;
}

ดูเอกสารนี้สำหรับรายละเอียด

เค้าร่างทั่วไปคือคุณสมบัติอย่างใดอย่างหนึ่งสามารถมี[Nullable]แอตทริบิวต์ในนั้นหรือถ้ามันไม่ประเภทล้อมรอบอาจมี[NullableContext]แอตทริบิวต์ ก่อนอื่นเรามองหา[Nullable]แล้วถ้าเราไม่พบมันเรามองหา[NullableContext]ประเภทที่แนบมา

คอมไพเลอร์อาจฝังคุณลักษณะลงในแอสเซมบลีและเนื่องจากเราอาจดูชนิดจากแอสเซมบลีที่แตกต่างกันเราจำเป็นต้องทำการโหลดการสะท้อนเท่านั้น

[Nullable]อาจสร้างอินสแตนซ์ของอาเรย์ถ้าคุณสมบัติเป็นแบบทั่วไป ในกรณีนี้องค์ประกอบแรกแทนคุณสมบัติจริง (และองค์ประกอบเพิ่มเติมเป็นตัวแทนของข้อโต้แย้งทั่วไป) [NullableContext]จะถูกอินสแตนซ์ด้วยไบต์เดียวเสมอ

ค่า2หมายถึง "nullable" 1หมายถึง "ไม่เป็นโมฆะ" และ0หมายถึง "ลบเลือน"


มันยากจริงๆ ฉันเพิ่งพบกรณีการใช้งานที่ไม่ครอบคลุมโดยรหัสนี้ ส่วนต่อประสานสาธารณะIBusinessRelation : ICommon {}/ public interface ICommon { string? Name {get;set;} }. ถ้าฉันเรียกวิธีการIBusinessRelationด้วยคุณสมบัติNameฉันได้รับเท็จ
gsharp

@gsharp อ่าฉันไม่ได้ลองกับอินเตอร์เฟสหรือการสืบทอดใด ๆ ฉันคาดเดาว่าเป็นการแก้ไขที่ค่อนข้างง่าย (ดูที่แอตทริบิวต์บริบทจากอินเตอร์เฟสพื้นฐาน): ฉันจะลองและแก้ไขในภายหลัง
canton7

1
ไม่มีปัญหา ฉันแค่อยากจะพูดถึงมัน สิ่งที่ไร้ค่านี้กำลังทำให้ฉันบ้า ;-)
gsharp

1
@gsharp มองไปที่มันคุณต้องผ่านการประเภทของอินเตอร์เฟซที่กำหนดสถานที่ให้บริการ - นั่นคือไม่ICommon อินเตอร์เฟซที่กำหนดแต่ละตัวของมันเองIBusinessRelation NullableContextฉันได้ชี้แจงคำตอบของฉันและเพิ่มการตรวจสอบรันไทม์สำหรับสิ่งนี้
canton7
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.