Bagikan melalui


Atribut lain-lain yang diinterpretasikan oleh pengompilasi C#

Ada beberapa atribut yang dapat diterapkan ke elemen dalam kode Anda yang menambahkan arti semantik ke elemen-elemen tersebut:

  • Conditional: Buat eksekusi metode bergantung pada pengidentifikasi praproscesor.
  • Obsolete: Tandai jenis atau anggota untuk memungkinkan penghapusan di masa mendatang.
  • Deprecated: (Windows Foundation) Tandai jenis atau anggota untuk (potensi) penghapusan di masa mendatang.
  • Experimental: Tandai jenis atau anggota sebagai eksperimental.
  • SetsRequiredMembers: Menunjukkan bahwa konstruktor menetapkan semua properti yang diperlukan.
  • AttributeUsage: Deklarasikan elemen bahasa tempat atribut dapat diterapkan.
  • AsyncMethodBuilder: Mendeklarasikan jenis penyusun metode asinkron.
  • InterpolatedStringHandler: Tentukan penyusun string terinterpolasi untuk skenario yang diketahui.
  • ModuleInitializer: Mendeklarasikan metode yang menginisialisasi modul.
  • SkipLocalsInit: Elide kode yang menginisialisasi penyimpanan variabel lokal ke 0.
  • UnscopedRef: Nyatakan bahwa variabel yang ref biasanya dipahami sebagai scoped sebaiknya dianggap tidak terlingkup.
  • OverloadResolutionPriority: Tambahkan atribut tiebreaker untuk memengaruhi resolusi kelebihan beban untuk kelebihan beban yang mungkin ambigu.
  • EnumeratorCancellation: Tentukan parameter untuk token pembatalan dalam enumerator asinkron.
  • CollectionBuilder: Tentukan metode penyusun untuk jenis koleksi saat ekspresi koleksi dikonversi ke jenis koleksi tersebut.
  • InlineArray: Tentukan bahwa jenis struct adalah array sebaris.
  • IUnknownConstant: Menentukan bagaimana argumen yang hilang harus disediakan untuk parameter default.
  • IDispatchConstant: Menentukan bagaimana argumen yang hilang harus disediakan untuk parameter default.

Pengompilasi menggunakan makna semantik tersebut untuk mengubah outputnya dan melaporkan kemungkinan kesalahan oleh pengembang menggunakan kode Anda.

atribut Conditional

Atribut Conditional membuat eksekusi metode bergantung pada pengidentifikasi prapemrosesan. Atribut Conditional adalah alias untuk ConditionalAttribute, dan dapat diterapkan ke metode atau kelas atribut.

Dalam contoh berikut, Conditional diterapkan ke metode untuk mengaktifkan atau menonaktifkan tampilan informasi diagnostik khusus program:

#define TRACE_ON
using System.Diagnostics;

namespace AttributeExamples;

public class Trace
{
    [Conditional("TRACE_ON")]
    public static void Msg(string msg)
    {
        Console.WriteLine(msg);
    }
}

public class TraceExample
{
    public static void Main()
    {
        Trace.Msg("Now in Main...");
        Console.WriteLine("Done.");
    }
}

Jika pengidentifikasi TRACE_ON tidak ditentukan, output pelacakan tidak ditampilkan. Jelajahi sendiri di jendela interaktif.

Atribut Conditional sering digunakan dengan pengidentifikasi DEBUG untuk mengaktifkan fitur pelacakan dan pengelogan untuk build debug tetapi tidak dalam build rilis, seperti yang ditunjukkan dalam contoh berikut:

[Conditional("DEBUG")]
static void DebugMethod()
{
}

Ketika metode bertanda kondisional dipanggil, ada atau tidak adanya simbol prapemrosesan yang ditentukan menentukan apakah pengompilasi menyertakan atau menghilangkan panggilan ke metode. Jika simbol ditentukan, panggilan disertakan; jika tidak, panggilan dihilangkan. Metode kondisional harus merupakan metode dalam kelas atau deklarasi struct dan harus memiliki jenis pengembalian void. Penggunaan Conditional lebih bersih, lebih elegan, dan kurang rawan kesalahan dibandingkan metode penutupan di dalam blok #if…#endif.

Jika metode memiliki beberapa atribut Conditional, pengompilasi menyertakan panggilan ke metode jika satu atau lebih simbol kondisional ditentukan (simbol secara logis ditautkan bersama menggunakan operator OR). Dalam contoh berikut, keberadaan A maupun B menghasilkan panggilan metode:

[Conditional("A"), Conditional("B")]
static void DoIfAorB()
{
    // ...
}

Menggunakan Conditional dengan kelas atribut

Atribut Conditional juga dapat diterapkan ke definisi kelas atribut. Dalam contoh berikut, atribut Documentation kustom menambahkan informasi ke metadata jika DEBUG ditentukan.

[Conditional("DEBUG")]
public class DocumentationAttribute : System.Attribute
{
    string text;

    public DocumentationAttribute(string text)
    {
        this.text = text;
    }
}

class SampleClass
{
    // This attribute will only be included if DEBUG is defined.
    [Documentation("This method displays an integer.")]
    static void DoWork(int i)
    {
        System.Console.WriteLine(i.ToString());
    }
}

atribut Obsolete dan Deprecated

Atribut Obsolete menandai elemen kode sebagai tidak lagi direkomendasikan untuk digunakan. Penggunaan entitas yang ditandai sebagai usang menghasilkan peringatan atau kesalahan. Atribut Obsolete adalah atribut penggunaan tunggal dan dapat diterapkan ke entitas apa pun yang memungkinkan atribut. Obsolete adalah alias untuk ObsoleteAttribute.

Dalam contoh berikut, atribut Obsolete diterapkan ke kelas A dan ke metode B.OldMethod. Karena argumen kedua dari konstruktor atribut yang diterapkan pada B.OldMethod diatur ke true, metode ini menyebabkan kesalahan kompilasi, sedangkan menggunakan kelas A menghasilkan peringatan. Namun, memanggil B.NewMethod tidak menghasilkan peringatan atau kesalahan. Misalnya, saat Anda menggunakannya dengan definisi sebelumnya, kode berikut menghasilkan dua peringatan dan satu kesalahan:


namespace AttributeExamples
{
    [Obsolete("use class B")]
    public class A
    {
        public void Method() { }
    }

    public class B
    {
        [Obsolete("use NewMethod", true)]
        public void OldMethod() { }

        public void NewMethod() { }
    }

    public static class ObsoleteProgram
    {
        public static void Main()
        {
            // Generates 2 warnings:
            A a = new A();

            // Generate no errors or warnings:
            B b = new B();
            b.NewMethod();

            // Generates an error, compilation fails.
            // b.OldMethod();
        }
    }
}

String yang disediakan sebagai argumen pertama untuk konstruktor atribut ditampilkan sebagai bagian dari peringatan atau kesalahan. Dua peringatan untuk kelas A dihasilkan: satu untuk deklarasi referensi kelas, dan satu untuk konstruktor kelas. Atribut Obsolete dapat digunakan tanpa argumen, tetapi direkomendasikan untuk menyertakan penjelasan apa yang harus digunakan sebagai gantinya. Anda dapat menggunakan interpolasi string konstanta dan operator nameof untuk memastikan nama cocok:

public class B
{
    [Obsolete($"use {nameof(NewMethod)} instead", true)]
    public void OldMethod() { }

    public void NewMethod() { }
}

Pustaka Metadata Windows Foundation menggunakan Windows.Foundation.Metadata.DeprecatedAttribute alih-alih ObsoleteAttribute.

atribut Experimental

Mulai dari C# 12, jenis, metode, dan rakitan dapat ditandai dengan System.Diagnostics.CodeAnalysis.ExperimentalAttribute untuk menunjukkan fitur eksperimental. Pengompilasi mengeluarkan peringatan jika Anda mengakses metode atau mengetik yang dianotasi dengan ExperimentalAttribute. Semua jenis yang dideklarasikan dalam rakitan atau modul yang ditandai dengan Experimental atribut bersifat eksperimental. Pengkompilasi mengeluarkan peringatan jika Anda mengakses salah satunya. Anda dapat menonaktifkan peringatan ini untuk menguji coba fitur eksperimental.

Peringatan

Fitur eksperimental dapat berubah. API dapat berubah, atau dapat dihapus dalam pembaruan mendatang. Termasuk fitur eksperimental adalah cara bagi penulis pustaka untuk mendapatkan umpan balik tentang ide dan konsep untuk pengembangan di masa mendatang. Berhati-hatilah saat menggunakan fitur apa pun yang ditandai sebagai eksperimental. Anda dapat mempelajari selengkapnya tentang bagaimana API ditandai sebagai eksperimental dalam artikel kami tentang pratinjau API .

Anda dapat membaca detail selengkapnya tentang Experimental atribut dalam spesifikasi fitur.

Pustaka Metadata Windows Foundation menggunakan Windows.Foundation.Metadata.ExperimentalAttribute, yang mendahului C# 12.

atribut SetsRequiredMembers

Atribut SetsRequiredMembers menginformasikan pengkompilasi bahwa konstruktor menetapkan semua required anggota di kelas atau struktur tersebut. Pengkompilasi mengasumsikan konstruktor apa pun dengan System.Diagnostics.CodeAnalysis.SetsRequiredMembersAttribute atribut menginisialisasi semua required anggota. Kode apa pun yang memanggil konstruktor seperti itu tidak memerlukan penginisialisasi objek untuk mengatur anggota yang diperlukan. Menambahkan atribut SetsRequiredMembers terutama bermanfaat untuk rekaman posisional dan konstruktor utama.

atribut AttributeUsage

Atribut AttributeUsage menentukan bagaimana kelas atribut kustom dapat digunakan. AttributeUsageAttribute adalah atribut yang Anda terapkan ke definisi atribut kustom. Atribut AttributeUsage memungkinkan Anda mengontrol:

  • Elemen program mana yang dapat diterapkan atribut. Kecuali Anda membatasi penggunaannya, atribut dapat diterapkan ke salah satu elemen program berikut:
    • Rakitan
    • Modul
    • Bidang
    • Kejadian
    • Metode
    • Pengaturan
    • Properti
    • Tampilkan
    • Jenis
  • Apakah atribut dapat diterapkan ke satu elemen program beberapa kali.
  • Apakah kelas turunan mewarisi atribut.

Pengaturan default terlihat seperti contoh berikut ketika diterapkan secara eksplisit:

[AttributeUsage(AttributeTargets.All,
                   AllowMultiple = false,
                   Inherited = true)]
class NewAttribute : Attribute { }

Dalam contoh ini, kelas NewAttribute dapat diterapkan untuk elemen program mana pun yang didukung. Ini hanya dapat diterapkan satu kali untuk setiap entitas. Kelas turunan mewarisi atribut yang diterapkan ke kelas dasar.

Argumen AllowMultiple dan Inherited bersifat opsional, sehingga kode berikut memiliki efek yang sama:

[AttributeUsage(AttributeTargets.All)]
class NewAttribute : Attribute { }

Argumen AttributeUsageAttribute pertama harus merupakan satu elemen enumerasi AttributeTargets atau lebih. Beberapa jenis target dapat ditautkan bersama dengan operator OR, seperti yang ditunjukkan dalam contoh berikut:

[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
class NewPropertyOrFieldAttribute : Attribute { }

Atribut dapat diterapkan ke properti atau field pendukung untuk properti yang diimplementasikan secara otomatis. Atribut tersebut berlaku untuk properti, kecuali Anda menentukan penentu field pada atribut tersebut. Keduanya ditunjukkan dalam contoh berikut:

class MyClass
{
    // Attribute attached to property:
    [NewPropertyOrField]
    public string Name { get; set; } = string.Empty;

    // Attribute attached to backing field:
    [field: NewPropertyOrField]
    public string Description { get; set; } = string.Empty;
}

Jika argumen AllowMultiple adalah true, maka atribut yang dihasilkan dapat diterapkan lebih dari satu kali untuk satu entitas, seperti yang ditunjukkan dalam contoh berikut:

[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
class MultiUse : Attribute { }

[MultiUse]
[MultiUse]
class Class1 { }

[MultiUse, MultiUse]
class Class2 { }

Dalam hal ini, MultiUseAttribute dapat diterapkan berulang kali karena AllowMultiple diatur ke true. Kedua format yang ditunjukkan untuk menerapkan beberapa atribut itu valid.

Jika Inherited adalah false, maka kelas turunan tidak mewarisi atribut dari kelas dasar yang diatribusikan. Contohnya:

[AttributeUsage(AttributeTargets.Class, Inherited = false)]
class NonInheritedAttribute : Attribute { }

[NonInherited]
class BClass { }

class DClass : BClass { }

Dalam hal ini, NonInheritedAttribute tidak diterapkan ke DClass melalui pewarisan.

Anda juga dapat menggunakan kata kunci ini untuk menentukan di mana atribut harus diterapkan. Misalnya, Anda dapat menggunakan penentu field: untuk menambahkan atribut ke bidang backing properti yang diimplementasikan secara otomatis. Atau Anda dapat menggunakan penentu field:, property:, atau param:untuk menerapkan atribut ke salah satu elemen yang dihasilkan dari rekaman posisi. Untuk contohnya, lihat Sintaksis posisi untuk definisi properti.

atribut AsyncMethodBuilder

Anda menambahkan atribut System.Runtime.CompilerServices.AsyncMethodBuilderAttribute ke tipe yang dapat menjadi tipe pengembalian asinkron. Atribut tersebut menentukan jenis yang membangun implementasi metode asinkron saat jenis yang ditentukan dikembalikan dari metode asinkron. Atribut AsyncMethodBuilder dapat diterapkan pada jenis yang:

Konstruktor ke atribut AsyncMethodBuilder menentukan jenis pembangun terkait. Pembangun harus mengimplementasikan anggota yang dapat diakses berikut:

  • Metode Create() statik yang mengembalikan jenis pembangun.

  • Properti Task yang dapat dibaca yang mengembalikan jenis pengembalian asinkron.

  • Metode void SetException(Exception) yang menetapkan pengecualian saat tugas gagal.

  • Metode void SetResult() atau void SetResult(T result) yang menandai tugas sebagai selesai dan secara opsional menetapkan hasil tugas

  • Metode Start dengan tanda tangan API berikut:

    public void Start<TStateMachine>(ref TStateMachine stateMachine)
              where TStateMachine : System.Runtime.CompilerServices.IAsyncStateMachine
    
  • Metode SetStateMachine dengan tanda tangan API berikut:

    public void SetStateMachine(System.Runtime.CompilerServices.IAsyncStateMachine stateMachine)
    
  • Metode AwaitOnCompleted dengan tanda tangan berikut:

    public void AwaitOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine)
        where TAwaiter : System.Runtime.CompilerServices.INotifyCompletion
        where TStateMachine : System.Runtime.CompilerServices.IAsyncStateMachine
    
  • Metode AwaitUnsafeOnCompleted dengan tanda tangan berikut:

          public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine)
              where TAwaiter : System.Runtime.CompilerServices.ICriticalNotifyCompletion
              where TStateMachine : System.Runtime.CompilerServices.IAsyncStateMachine
    

Anda dapat mempelajari pembangun metode asinkron dengan membaca tentang pembangun berikut yang disediakan oleh .NET:

Atribut AsyncMethodBuilder dapat diterapkan ke metode asinkron untuk mengganti penyusun untuk jenis tersebut.

InterpolatedStringHandler dan atribut InterpolatedStringHandlerArguments

Anda menggunakan atribut ini untuk menentukan bahwa jenis adalah handler string terinterpolasi . Pustaka .NET 6 sudah menyertakan System.Runtime.CompilerServices.DefaultInterpolatedStringHandler untuk skenario di mana Anda menggunakan string terinterpolasi sebagai argumen untuk parameter string. Anda mungkin memiliki instans lain di mana Anda ingin mengontrol bagaimana string terinterpolasi diproses. Anda menerapkan System.Runtime.CompilerServices.InterpolatedStringHandlerAttribute untuk jenis yang mengimplementasikan penangan Anda. Anda menerapkan System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute untuk parameter konstruktor jenis tersebut.

Anda dapat mempelajari selengkapnya tentang membangun handler string terinterpolasi dalam spesifikasi fitur untuk peningkatan string terinterpolasi .

atribut ModuleInitializer

Atribut ModuleInitializer menandai metode yang dipanggil oleh runtime saat komponen rakitan dimuat. ModuleInitializer adalah alias untuk ModuleInitializerAttribute.

Atribut ModuleInitializer hanya dapat diterapkan untuk metode yang:

  • Bersifat statik.
  • Tidak memiliki parameter.
  • Menampilkan void.
  • Dapat diakses dari modul penampung, yaitu, internal atau public.
  • Bukan metode generik.
  • Tidak ditampung dalam kelas generik.
  • Bukan fungsi lokal.

Atribut ModuleInitializer dapat diterapkan ke beberapa metode. Dalam hal ini, urutan di mana runtime memanggil mereka bersifat deterministik tetapi tidak ditentukan.

Contoh berikut menggambarkan penggunaan beberapa metode penginisialisasi modul. Metode Init1 dan Init2 berjalan sebelum Main, dan masing-masing menambahkan string ke properti Text. Sehingga ketika Main berjalan, properti Text sudah memiliki string dari kedua metode penginisialisasi.

using System;

internal class ModuleInitializerExampleMain
{
    public static void Main()
    {
        Console.WriteLine(ModuleInitializerExampleModule.Text);
        //output: Hello from Init1! Hello from Init2!
    }
}
using System.Runtime.CompilerServices;

internal class ModuleInitializerExampleModule
{
    public static string? Text { get; set; }

    [ModuleInitializer]
    public static void Init1()
    {
        Text += "Hello from Init1! ";
    }

    [ModuleInitializer]
    public static void Init2()
    {
        Text += "Hello from Init2! ";
    }
}

Generator kode sumber terkadang perlu menghasilkan kode inisialisasi. Penginisialisasi modul menyediakan tempat standar untuk kode tersebut. Dalam kebanyakan kasus lainnya, Anda harus menulis konstruktor statik alih-alih penginisialisasi modul.

atribut SkipLocalsInit

Atribut SkipLocalsInit mencegah kompiler mengatur .locals init flag saat menulis ke metadata. Atribut SkipLocalsInit adalah atribut penggunaan tunggal dan dapat diterapkan pada metode, properti, kelas, struct, antarmuka, atau modul, tetapi tidak pada assembly. SkipLocalsInit adalah alias untuk SkipLocalsInitAttribute.

Bendera .locals init menyebabkan CLR menginisialisasi semua variabel lokal yang dideklarasikan dalam metode ke nilai defaultnya. Karena pengompilasi juga memastikan bahwa Anda tidak pernah menggunakan variabel sebelum menetapkan beberapa nilai ke dalamnya, .locals init biasanya tidak diperlukan. Namun, inisialisasi nol tambahan mungkin memiliki dampak performa yang terukur dalam beberapa skenario, seperti ketika Anda menggunakan stackalloc untuk mengalokasikan array pada tumpukan. Dalam kasus tersebut, Anda dapat menambahkan atribut SkipLocalsInit. Jika diterapkan ke metode secara langsung, atribut tersebut memengaruhi metode tersebut dan semua fungsi bersarangnya, termasuk lambda dan fungsi lokal. Jika diterapkan pada tipe atau modul, hal tersebut memengaruhi semua metode yang bersarang di dalamnya. Atribut ini tidak memengaruhi metode abstrak, tetapi mempengaruhi kode yang dihasilkan untuk implementasi.

Atribut ini memerlukan opsi pengompilasi AllowUnsafeBlocks. Persyaratan ini menandakan bahwa dalam beberapa kasus kode dapat mengakses memori yang tidak ditetapkan (misalnya, membaca dari memori tumpukan yang tidak terinisialisasi).

Contoh berikut mengilustrasikan efek atribut SkipLocalsInit terhadap metode yang menggunakan stackalloc. Metode ini menampilkan apa pun yang ada dalam memori ketika array bilangan bulat dialokasikan.

[SkipLocalsInit]
static void ReadUninitializedMemory()
{
    Span<int> numbers = stackalloc int[120];
    for (int i = 0; i < 120; i++)
    {
        Console.WriteLine(numbers[i]);
    }
}
// output depends on initial contents of memory, for example:
//0
//0
//0
//168
//0
//-1271631451
//32767
//38
//0
//0
//0
//38
// Remaining rows omitted for brevity.

Untuk mencoba kode ini sendiri, atur opsi pengompilasi AllowUnsafeBlocks di file .csproj Anda:

<PropertyGroup>
  ...
  <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>

atribut UnscopedRef

Atribut UnscopedRef menandai deklarasi variabel sebagai tidak terlingkup, yang berarti referensi diizinkan untuk melarikan diri.

Anda menambahkan atribut ini di tempat pengkompilasi memperlakukan ref sebagai scoped secara implisit.

  • Parameter this untuk struct metode instans.
  • ref parameter-parameter yang merujuk ke ref struct jenis-jenis.
  • out Parameter.

Menerapkan System.Diagnostics.CodeAnalysis.UnscopedRefAttribute menandai elemen sebagai tidak memiliki lingkup.

atribut OverloadResolutionPriority

memungkinkan OverloadResolutionPriorityAttribute penulis pustaka untuk lebih memilih satu kelebihan beban daripada yang lain ketika dua kelebihan beban dapat ambigu. Kasus penggunaan utamanya adalah agar penulis pustaka menulis dengan performa kelebihan beban yang lebih baik sambil tetap mendukung kode yang ada tanpa jeda.

Misalnya, Anda dapat menambahkan kelebihan beban baru yang digunakan ReadOnlySpan<T> untuk mengurangi alokasi memori:

[OverloadResolutionPriority(1)]
public void M(params ReadOnlySpan<int> s) => Console.WriteLine("Span");
// Default overload resolution priority of 0
public void M(params int[] a) => Console.WriteLine("Array");

Resolusi kelebihan beban menganggap dua metode sama baiknya untuk beberapa jenis argumen. Untuk argumen , int[]lebih suka kelebihan beban pertama. Untuk membuat pengkompilasi lebih memilih versi ReadOnlySpan, Anda dapat meningkatkan prioritas overload tersebut. Contoh berikut menunjukkan efek penambahan atribut:

var d = new OverloadExample();
int[] arr = [1, 2, 3];
d.M(1, 2, 3, 4); // Prints "Span"
d.M(arr); // Prints "Span" when PriorityAttribute is applied
d.M([1, 2, 3, 4]); // Prints "Span"
d.M(1, 2, 3, 4); // Prints "Span"

Semua kelebihan beban dengan prioritas yang lebih rendah daripada prioritas kelebihan beban tertinggi dihapus dari serangkaian metode yang berlaku. Metode tanpa atribut ini memiliki prioritas kelebihan beban yang diatur ke default nol. Pengembang pustaka harus menggunakan atribut ini sebagai upaya terakhir saat menambahkan overload metode baru yang lebih baik. Penulis pustaka harus memiliki pemahaman mendalam tentang bagaimana Resolusi kelebihan beban berdampak pada pemilihan metode yang lebih baik. Jika tidak, kesalahan tak terduga dapat diakibatkan.

Atribut EnumeratorCancellation

Atribut System.Runtime.CompilerServices.EnumeratorCancellationAttribute menentukan parameter mana yang harus menerima token pembatalan dari API System.Collections.Generic.IAsyncEnumerable<T>.GetAsyncEnumerator(CancellationToken). Ini adalah bagian dari infrastruktur untuk fitur aliran asinkron .

Atribut CollectionBuilder

Atribut System.Runtime.CompilerServices.CollectionBuilderAttribute menentukan metode yang membangun instans jenis koleksi dari ekspresi koleksi . Anda menggunakan atribut ini untuk menentukan metode yang membangun koleksi. Pengkompilasi menghasilkan kode untuk memanggil metode tersebut saat ekspresi koleksi dikonversi ke jenis tersebut.

Atribut InlineArray

Atribut System.Runtime.CompilerServices.InlineArrayAttribute menandai jenis sebagai array sebaris . Anda dapat mempelajari selengkapnya tentang fitur ini dalam artikel di structs, di bagian tentang array sebaris .

Atribut IUnknownConstant dan IDispatchConstant

Atribut System.Runtime.CompilerServices.IUnknownConstantAttribute dan System.Runtime.CompilerServices.IDispatchConstantAttribute dapat ditambahkan ke parameter default untuk menunjukkan bahwa argumen yang hilang harus disediakan sebagai new UnknownWrapper(null) atau new DispatchWrapper(null).

Lihat juga