Saya memiliki objek besar:
class BigObject{
public int Id {get;set;}
public string FieldA {get;set;}
// ...
public string FieldZ {get;set;}
}
dan objek khusus, seperti DTO:
class SmallObject{
public int Id {get;set;}
public EnumType Type {get;set;}
public string FieldC {get;set;}
public string FieldN {get;set;}
}
Saya pribadi menemukan konsep yang secara eksplisit memasukkan BigObject ke dalam SmallObject - mengetahui bahwa itu adalah operasi satu arah, kehilangan data - sangat intuitif dan mudah dibaca:
var small = (SmallObject) bigOne;
passSmallObjectToSomeone(small);
Diimplementasikan menggunakan operator eksplisit:
public static explicit operator SmallObject(BigObject big){
return new SmallObject{
Id = big.Id,
FieldC = big.FieldC,
FieldN = big.FieldN,
EnumType = MyEnum.BigObjectSpecific
};
}
Sekarang, saya dapat membuat SmallObjectFactory
kelas dengan FromBigObject(BigObject big)
metode, yang akan melakukan hal yang sama, menambahkannya ke injeksi dependensi dan memanggilnya saat diperlukan ... tetapi bagi saya sepertinya lebih rumit dan tidak perlu.
PS Saya tidak yakin apakah ini relevan, tetapi akan ada OtherBigObject
yang juga akan dapat dikonversi menjadi SmallObject
, pengaturan berbeda EnumType
.
c#
object-oriented
.net
type-casting
Gerino
sumber
sumber
.ToSmallObject()
metode (atauGetSmallObject()
). Sebuah alasan sesaat - saya tahu ada sesuatu yang salah dengan pemikiran saya, jadi saya sudah bertanya kepada kalian :)ToSmallObject
metode.Jawaban:
Tidak ada jawaban lain yang benar menurut pendapat saya. Dalam pertanyaan stackoverflow ini, jawaban dengan suara terbanyak berpendapat bahwa kode pemetaan harus dijauhkan dari domain. Untuk menjawab pertanyaan Anda, tidak - penggunaan operator pemeran Anda tidak bagus. Saya akan menyarankan untuk membuat layanan pemetaan yang terletak di antara DTO Anda dan objek domain Anda, atau Anda bisa menggunakan automapper untuk itu.
sumber
Itu ... Tidak hebat. Saya telah bekerja dengan kode yang melakukan trik pintar ini dan itu menyebabkan kebingungan. Setelah semua, Anda akan berharap untuk dapat hanya menetapkan variabel
BigObject
ke dalam suatu objekSmallObject
jika objek cukup terkait untuk melemparkannya. Itu tidak berfungsi - Anda mendapatkan kesalahan kompiler jika Anda mencoba karena sejauh menyangkut sistem tipe, mereka tidak berhubungan. Juga agak tidak disukai bagi operator casting untuk membuat objek baru.Saya akan merekomendasikan
.ToSmallObject()
metode sebagai gantinya. Lebih jelas tentang apa yang sebenarnya terjadi dan tentang sebagai verbose.sumber
mildly distasteful
adalah pernyataan yang meremehkan. Sangat disayangkan bahwa bahasa ini memungkinkan hal semacam ini terlihat seperti tipografi. Tidak ada yang akan menduga itu adalah transformasi objek yang sebenarnya kecuali mereka menulisnya sendiri. Dalam tim satu orang, baik-baik saja. Jika Anda berkolaborasi dengan siapa pun, dalam kasus terbaik itu adalah buang-buang waktu karena Anda harus berhenti dan mencari tahu apakah itu benar-benar pemain, atau jika itu salah satu dari transformasi gila itu..ToSmallObject()
. Hampir tidak pernah Anda menimpa operator.Get
menyiratkan mengembalikan sesuatu yang sudah ada. Kecuali jika Anda mengganti operasi pada objek kecil, duaGet
panggilan akan mengembalikan objek yang tidak setara, menyebabkan kebingungan / bug / wtfs.Sementara saya dapat melihat mengapa Anda perlu memiliki
SmallObject
, saya akan mendekati masalahnya secara berbeda. Pendekatan saya untuk masalah jenis ini adalah menggunakan Facade . Tujuan utamanya adalah untuk merangkumBigObject
dan hanya menyediakan anggota khusus. Dengan cara ini, ini adalah antarmuka baru pada instance yang sama, dan bukan salinan. Tentu saja Anda juga bisa ingin melakukan salinan, tetapi saya akan merekomendasikan Anda melakukannya melalui metode yang dibuat untuk tujuan itu dalam kombinasi dengan Facade (misalnyareturn new SmallObject(instance.Clone())
).Facade memiliki sejumlah keunggulan lain, yaitu memastikan bahwa bagian-bagian tertentu dari program Anda hanya dapat memanfaatkan anggota yang disediakan melalui fasad Anda, secara efektif menjamin bahwa ia tidak dapat memanfaatkan apa yang seharusnya tidak diketahui. Selain itu, ini juga memiliki keuntungan luar biasa karena Anda memiliki lebih banyak fleksibilitas dalam mengubah
BigObject
pemeliharaan di masa mendatang tanpa harus terlalu khawatir tentang bagaimana itu digunakan di seluruh program Anda. Selama Anda bisa meniru perilaku lama dalam beberapa bentuk atau lainnya, Anda dapat membuatSmallObject
pekerjaan sama seperti sebelumnya tanpa harus mengubah program Anda di mana punBigObject
akan digunakan.Catatan, ini berarti
BigObject
tidak tergantung padaSmallObject
melainkan sebaliknya (seperti yang seharusnya menurut pendapat saya yang sederhana).sumber
SmallObject
kebohongan denganSmallObject
atauBigObject
. Secara default, pendekatan ini memaksaSmallObject
untuk menghindari ketergantungan pada anggota pribadi / terlindungiBigObject
. Kita dapat melangkah lebih jauh dan menghindari ketergantungan pada anggota pribadi / yang dilindungiSmallObject
dengan menggunakanToSmallObject
metode ekstensi.BigObject
. Jika Anda ingin melakukan hal serupa, Anda akan dijamin untuk membuatToAnotherObject
metode ekstensi di dalamBigObject
? Ini seharusnya tidak menjadi perhatianBigObject
karena, mungkin sudah cukup besar. Ini juga memungkinkan Anda untuk terpisahBigObject
dari penciptaan dependensinya, artinya Anda dapat menggunakan pabrik dan sejenisnya. Pendekatan lain sangat pasanganBigObject
danSmallObject
. Itu mungkin baik-baik saja dalam kasus khusus ini, tetapi itu bukan praktik terbaik menurut pendapat saya yang sederhana.BigObject
digabungkan keSmallObject
, itu hanya metode statis di suatu tempat yang mengambil argumenBigObject
dan kembaliSmallObject
. Metode penyuluhan sebenarnya hanyalah gula sintaksis untuk memanggil metode statis dengan cara yang lebih baik. Metode ekstensi bukan bagian dariBigObject
, itu adalah metode statis yang sepenuhnya terpisah. Ini sebenarnya penggunaan metode ekstensi yang cukup bagus, dan sangat berguna untuk konversi DTO secara khusus.Ada konvensi yang sangat kuat yang menggunakan tipe referensi yang bisa berubah adalah pelestarian identitas. Karena sistem umumnya tidak mengizinkan operator casting yang ditentukan pengguna dalam situasi di mana objek dari tipe sumber dapat ditugaskan ke referensi dari tipe tujuan, hanya ada beberapa kasus di mana operasi casting yang ditentukan pengguna akan masuk akal untuk referensi yang bisa berubah-ubah jenis.
Saya akan menyarankan sebagai persyaratan yang, diberikan
x=(SomeType)foo;
diikuti beberapa saat kemudiany=(SomeType)foo;
, dengan kedua gips diterapkan pada objek yang sama,x.Equals(y)
harus selalu dan selamanya benar, bahkan jika objek tersebut dimodifikasi di antara dua gips. Situasi seperti itu dapat berlaku jika misalnya satu memiliki sepasang objek dari jenis yang berbeda, masing-masing memiliki referensi yang tidak dapat diubah ke yang lain, dan melemparkan salah satu objek ke jenis lainnya akan mengembalikan instance yang dipasangkan. Itu juga bisa berlaku dengan tipe yang berfungsi sebagai pembungkus untuk objek yang bisa berubah, asalkan identitas objek yang dibungkus tidak dapat diubah, dan dua pembungkus dari tipe yang sama akan melaporkan diri mereka sama jika mereka membungkus koleksi yang sama.Contoh khusus Anda menggunakan kelas yang bisa berubah, tetapi tidak mempertahankan bentuk identitas apa pun; dengan demikian, saya akan menyarankan bahwa ini bukan penggunaan yang tepat dari operator casting.
sumber
Mungkin baik-baik saja.
Masalah dengan contoh Anda adalah bahwa Anda menggunakan nama contoh-ish tersebut. Mempertimbangkan:
Sekarang, ketika Anda punya ide yang baik apa yang panjang dan int berarti, maka kedua pemain implisit
int
untuklong
dan cor eksplisit darilong
keint
cukup dimengerti. Ini juga bisa dimengerti bagaimana3
menjadi3
dan hanya cara lain untuk bekerja dengannya3
. Dapat dimengerti bagaimana ini akan gagal denganint.MaxValue + 1
dalam konteks yang diperiksa. Bahkan bagaimana itu akan bekerja denganint.MaxValue + 1
dalam konteks yang tidak dicentang untuk menghasilkanint.MinValue
bukanlah hal yang paling sulit untuk dilakukanDemikian juga, ketika Anda melemparkan secara implisit ke tipe basis atau secara eksplisit ke tipe turunan, hal ini dapat dimengerti oleh siapa pun yang tahu cara kerja pewarisan apa yang terjadi, dan apa hasilnya nanti (atau bagaimana itu mungkin gagal).
Sekarang, dengan BigObject dan SmallObject saya tidak memiliki perasaan tentang bagaimana hubungan ini bekerja. Jika tipe nyata Anda di mana sedemikian rupa sehingga hubungan casting di mana jelas, maka casting mungkin memang ide yang baik, meskipun banyak waktu, mungkin sebagian besar, jika ini yang terjadi maka harus tercermin dalam hierarki kelas dan casting berbasis warisan yang normal akan cukup.
sumber
BigObject
mungkin menggambarkanEmployee {Name, Vacation Days, Bank details, Access to different building floors etc.}
, danSmallObject
mungkin aMoneyTransferRecepient {Name, Bank details}
. Ada terjemahan langsung dariEmployee
keMoneyTransferRecepient
, dan tidak ada alasan untuk mengirim ke aplikasi perbankan lebih dari data yang diperlukan.