Saya mencoba untuk menulis algoritma umum dalam C # yang dapat bekerja dengan entitas geometris dari dimensi yang berbeda.
Dalam contoh berikut yang saya buat Point2
dan Point3
, keduanya mengimplementasikan IPoint
antarmuka sederhana .
Sekarang saya memiliki fungsi GenericAlgorithm
yang memanggil fungsi GetDim
. Ada beberapa definisi fungsi ini berdasarkan jenisnya. Ada juga fungsi mundur yang didefinisikan untuk apa pun yang mengimplementasikan IPoint
.
Saya awalnya mengharapkan output dari program berikut ini menjadi 2, 3. Namun, itu adalah 0, 0.
interface IPoint {
public int NumDims { get; }
}
public struct Point2 : IPoint {
public int NumDims => 2;
}
public struct Point3 : IPoint {
public int NumDims => 3;
}
class Program
{
static int GetDim<T>(T point) where T: IPoint => 0;
static int GetDim(Point2 point) => point.NumDims;
static int GetDim(Point3 point) => point.NumDims;
static int GenericAlgorithm<T>(T point) where T : IPoint => GetDim(point);
static void Main(string[] args)
{
Point2 p2;
Point3 p3;
int d1 = GenericAlgorithm(p2);
int d2 = GenericAlgorithm(p3);
Console.WriteLine("{0:d}", d1); // returns 0 !!
Console.WriteLine("{0:d}", d2); // returns 0 !!
}
}
OK, jadi karena alasan tertentu informasi tipe konkret hilang GenericAlgorithm
. Saya tidak sepenuhnya mengerti mengapa ini terjadi, tetapi baik-baik saja. Jika saya tidak dapat melakukannya dengan cara ini, alternatif apa lagi yang saya miliki?
NumDims
properti tersedia. Mengapa Anda mengabaikannya dalam beberapa kasus?GetDim
(yaitu saya melewatiPoint4
tetapiGetDim<Point4>
tidak ada). Namun, tampaknya kompiler tidak peduli untuk mencari implementasi khusus.Jawaban:
Metode ini:
... akan selalu menelepon
GetDim<T>(T point)
. Resolusi kelebihan dilakukan pada waktu kompilasi , dan pada tahap itu tidak ada metode lain yang berlaku.Jika Anda ingin resolusi kelebihan dipanggil pada waktu eksekusi , Anda harus menggunakan pengetikan dinamis, mis
Tetapi umumnya ide yang lebih baik untuk menggunakan warisan untuk ini - dalam contoh Anda, jelas Anda hanya bisa memiliki satu metode dan kembali
point.NumDims
. Saya berasumsi dalam kode asli Anda ada beberapa alasan yang setara sulit dilakukan, tetapi tanpa lebih banyak konteks kami tidak dapat menyarankan tentang cara menggunakan warisan untuk melakukan spesialisasi. Itu adalah opsi Anda:sumber
AxisAlignedBoundingBox2
danAxisAlignedBoundingBox3
. Saya memilikiContains
metode statis yang digunakan untuk menentukan apakah kumpulan kotak berisiLine2
atauLine3
(yang mana tergantung pada jenis kotak). Logika algoritma antara kedua jenis ini persis sama, kecuali jumlah dimensi berbeda. Ada juga panggilan keIntersect
internal yang perlu dikhususkan untuk jenis yang benar. Saya ingin menghindari panggilan fungsi virtual / dinamis, itulah sebabnya saya menggunakan obat generik ... tentu saja, saya hanya dapat menyalin / menempelkan kode dan melanjutkan.Pada C # 8.0 Anda harus dapat memberikan implementasi default untuk antarmuka Anda, daripada membutuhkan metode generik.
Menerapkan metode umum dan kelebihan muatan per
IPoint
implementasi juga melanggar Prinsip Pergantian Liskov (L dalam SOLID). Anda akan lebih baik untuk mendorong algoritma ke dalam setiapIPoint
implementasi, yang berarti Anda hanya perlu satu panggilan metode:sumber
Pola Pengunjung
sebagai alternatif
dynamic
penggunaan, Anda mungkin ingin menggunakan pola Pengunjung seperti di bawah ini:sumber
Mengapa Anda tidak mendefinisikan fungsi GetDim di kelas dan antarmuka? Sebenarnya, Anda tidak perlu mendefinisikan fungsi GetDim, cukup gunakan properti NumDims.
sumber