Saya memiliki kelas Foo
dan kelas statis FooFactory
, yang digunakan untuk membuat instance kelas turunan Foo
dan Foo
melalui API berikut:
public static class FooFactory {
public static T Create<T>() where T : Foo, new() {
...
return new T();
}
}
Spesialisasi new()
dari parameter tipe T
mengharuskan Foo
memiliki konstruktor default public
. Dengan kata lain, tidak ada yang menghalangi pengguna Foo
untuk menginisialisasi kelas secara langsung melalui konstruktor.
Namun,
FooFactory
dimaksudkan untuk melacak semua instanceFoo
, jadi saya ingin memaksa pengguna untuk membuat semua instance turunanFoo
danFoo
melaluiFooFactory
.
Cara terdekat yang dapat saya cegah untuk inisialisasi konstruktor langsung adalah dengan mendekorasi konstruktor default Foo
dengan atribut [Obsolete("message", error: true)]
:
public class Foo {
[Obsolete("Fail", true)]
public Foo() { ... }
}
Dengan dekorasi ini, kode tidak dapat dikompilasi ketika saya memanggil konstruktor default Foo
secara langsung, sedangkan inisialisasi melalui FooFactory.Create<Foo>()
berfungsi.
Namun dengan dekorasi [Obsolete]
ini, saya masih mengalami masalah dengan kelas turunan. Yang berikut ini bahkan tidak dapat dikompilasi karena pengaturan error: true
untuk konstruktor default Foo
:
public class Bar : Foo { ... }
public class Baz : Foo { public Baz() : base() { ... } }
Saya dapat mendeklarasikan kelebihan konstruktor protected
Foo
yang dipanggil oleh kelas turunan alih-alih konstruktor default, tetapi kemudian saya tidak akan memiliki kemampuan untuk secara terprogram mencegah inisialisasi langsung dari kelas turunan.
Jika saya menyetel error
di ObsoleteAttribute
ke false
, saya malah mendapatkan peringatan kompilasi, tetapi saya ingin mendapat keputusasaan yang lebih kuat daripada peringatan...
Apakah ada cara agar saya dapat secara terprogram mencegah pemanggilan langsung konstruktor default untuk Foo
dan kelas turunan ketika konstruktor default harus dideklarasikan public
?
internal
ke perpustakaan dan hapus batasannew()
. Ini berarti Anda bertanggung jawab atas pembuatan semua tipe Foo - person Nkosi   schedule 04.09.2017new()
hanya berfungsi jika konstruktornya dideklarasikanpublic
. - person Anders Gustafsson   schedule 04.09.2017Foo
melakukan pelacakan instance, dengan memanggil bidang statis danthis.GetType()
. - person Jeroen Mostert   schedule 04.09.2017Baz
yang dapat dibuat secara langsung -- pembuatnya selalu menyediakan konstruktor publik untuk pengguna yang mengabaikan permintaan Anda, terlepas dari bagaimanaFoo
disiapkan. Jika Anda menganggap penulis selalu bersekongkol dan berasumsi mereka akan berperilaku baik, saran kedua saya adalah menghilangkan batasannew()
dan meneruskan panggilan konstruktor sebagaiFunc<T>
ke metode internal. Hal ini menjaga keamanan tipe tetapi rumit bagi penulis. - person Jeroen Mostert   schedule 04.09.2017new()
adalah karena spesialisasi ini portabel di seluruh platform. Refleksi, khususnya terhadap metode non-public
, tidak selalu berjalan baik di semua platform. - person Anders Gustafsson   schedule 04.09.2017Foo
? Jika itu bukan suatu keharusan maka akan lebih mudah untuk menyelesaikan masalah Anda. - person Eric Lippert   schedule 04.09.2017