Açık döküm işleç kullanımı benim için makul mü yoksa kötü bir saldırı mıdır?


24

Büyük bir nesnem var:

class BigObject{
    public int Id {get;set;}
    public string FieldA {get;set;}
    // ...
    public string FieldZ {get;set;}
}

ve özel, DTO benzeri bir nesne:

class SmallObject{
    public int Id {get;set;}
    public EnumType Type {get;set;}
    public string FieldC {get;set;}
    public string FieldN {get;set;}
}

Kişisel olarak açıkça BigObject'i SmallObject'e dökerek bir kavram buluyorum - bunun tek yönlü, veri kaybeden bir işlem olduğunu bilerek - çok sezgisel ve okunabilir:

var small = (SmallObject) bigOne;
passSmallObjectToSomeone(small);

Açık operatör kullanılarak uygulanır:

public static explicit operator SmallObject(BigObject big){
    return new SmallObject{
        Id = big.Id,
        FieldC = big.FieldC,
        FieldN = big.FieldN,
        EnumType = MyEnum.BigObjectSpecific
    };
}

Şimdi, bir yaratabilecek SmallObjectFactoryile sınıf FromBigObject(BigObject big), aynı şeyi bağımlılık enjeksiyon eklemek ve gerektiğinde çağırır yöntemi ... ama bana daha da fazla karmaşık ve gereksiz görünüyor.

PS Bunun konuyla alakalı olup olmadığından emin değilim, ancak bunun OtherBigObjectda SmallObjectfarklı bir hale getirilerek dönüştürülebileceği de olacaktır EnumType.


4
Neden bir kurucu değil?
edc65

2
Ya da statik bir fabrika yöntemi?
Brian Gordon

Neden bir fabrika sınıfına veya bağımlılık enjeksiyonuna ihtiyaç duyuyorsunuz? Orada sahte bir ikilik yarattın.
kullanıcı253751

1
@ immibis - çünkü bir şekilde @Telastyn'in önerdiği şey hakkında düşünmedim: .ToSmallObject()yöntem (veya GetSmallObject()). Anlık bir akıl yürütme sebebi
Düşüncemde bir

3
Bu, yalnızca BigObject tarafından kapsamlı veri / davranışlarının sınırlı bir setine erişim sağlama aracı olarak uygulanan bir ISmallObject arayüzü için mükemmel bir kullanım çantası gibi görünüyor. Özellikle @ Telastyn'in bir ToSmallObjectyöntem fikri ile birleştirildiğinde .
Marjan Venema

Yanıtlar:


0

Diğer cevapların hiçbiri alçakgönüllü görüşüme göre doğru değil. Bu yığın akışı sorusunda en yüksek oyu alan cevap, eşleme kodunun etki alanının dışında tutulması gerektiğini savunuyor. Sorunuzu cevaplamak için, hayır - cast operatörünü kullanmanız iyi değildir. DTO'nuz ile etki alanı nesnesinin arasına oturan bir eşleme hizmeti yapmanızı öneririm, ya da bunun için otomatikleştirici kullanabilirsiniz.


Bu müthiş bir fikir. Zaten Automapper yerinde, bu yüzden bir esinti olacak. Yanımda olan tek sorun: BigObject ve SmallObject'in bir şekilde birbirleriyle ilişkili olduğuna dair bir iz olmamalı mı?
Gerino

1
Hayır BigObject ve SmallObject'i haritalama hizmeti dışında bir araya getirerek herhangi bir avantaj görmüyorum.
Esben Skov Pedersen

7
Gerçekten mi? Bir otomatör, tasarım problemlerine çözümünüz mü?
Telastyn

1
BigObject, SmallObject ile eşlenebilir, klasik OOP anlamında birbirleriyle gerçekten ilişkili değillerdir ve kod bunu yansıtır (her iki nesne de etki alanında bulunur, eşleme yeteneği başkalarıyla birlikte eşleme yapılandırmasında ayarlanır). Şüpheli kodu kaldırıyor (talihsiz operatörüm geçersiz kılıyor), modelleri temiz bırakıyor (bunlarda yöntem yok), bu yüzden evet, bir çözüm gibi görünüyor.
Gerino

2
@EsbenSkovPedersen Bu çözüm, posta kutunuzu kurmak için bir çukur kazmak için buldozer kullanmak gibidir. Neyse ki OP yine de bahçeyi kazmak istedi, bu yüzden bir buldozer bu durumda çalışıyor. Ancak, genel olarak bu çözümü tavsiye etmem .
Neil

81

Bu ... Harika değil. Bu akıllıca numarayı yapan ve kargaşaya yol açan kodla çalıştım. Ne de olsa, nesneler onları yayınlayacak kadar ilişkiliyse , sadece BigObjectbir SmallObjectdeğişkene atayabileceğinizi umuyorsunuz. Yine de çalışmaz - tip sistemi söz konusu olduğunda denendiyseniz derleyici hataları alırsınız, ilgisizler. Ayrıca, döküm operatörünün yeni nesneler üretmesi de hafif derecede dengesizdir.

Bunun .ToSmallObject()yerine bir yöntem tavsiye ederim . Aslında neler olup bittiği ve ayrıntılı olarak ne olduğu daha açık.


18
Doh ... ToSmallObject () en bariz seçenek gibi görünüyor. Bazen en belirgin olanı en zor olanıdır;)
Gerino

6
mildly distastefulbir understatement. Dilin bu tür bir şeyin bir tür tahmini gibi görünmesine izin vermesi talihsiz bir durumdur. Hiç kimse, kendileri yazmadıkça, gerçek bir nesne dönüşümü olduğunu tahmin edemezdi. Tek kişilik bir takımda, iyi. Herhangi biriyle işbirliği yaparsanız, en iyi durumda, bu zaman kaybıdır, çünkü gerçekten aldatma veya bu çılgın dönüşümlerden biri olup olmadığına karar vermeniz gerekir.
Kent A.

3
@Telastyn En korkunç kod kokusu olmadığını kabul etti. Ancak, programcıların çoğu programcının derleyiciye aynı nesneyi farklı bir tür olarak ele alma talimatı olarak anladıkları işlemden yeni bir nesnenin yaratılması, sizden sonra kodunuzla çalışmak zorunda olan herkes için açık değildir. :)
Kent A.

4
İçin +1 .ToSmallObject(). Operatörleri geçersiz kılmamalısınız.
ytoledano

6
@dorus - en azından. NET'te, Getvarolan bir şeyi iade etmek anlamına gelir. Küçük nesne üzerindeki işlemleri geçersiz Getkılmadığınız sürece, iki çağrı eşit olmayan nesneleri döndürerek karışıklığa / hatalara / wtfs'ye neden olur.
Telastyn,

11

Neden bir ihtiyaç duyduğunuzu SmallObjectanlayabilsem de, soruna farklı bir yaklaşımla yaklaşırım. Bu tür meselelere yaklaşımım Cephe kullanmak . Tek amacı, kapsüllemek BigObjectve sadece belirli üyeleri mümkün kılmaktır. Bu şekilde, aynı durumda yeni bir arayüzdür, bir kopya değildir. Elbette bir kopyasını da yapmak isteyebilirsiniz, ancak bunu Cephe ile birlikte (örneğin return new SmallObject(instance.Clone())) bu amaçla oluşturulan bir yöntemle yapmanızı tavsiye ederim .

Cephe, bir takım başka avantajlara sahiptir; yani, programınızın belirli bölümlerinin yalnızca kendi cephenizde bulunan üyelerden faydalanabilmesini sağlayarak etkin bir şekilde bilmemesi gerekenleri kullanamayacağının garantisidir. Buna ek olarak BigObject, programınız boyunca nasıl kullanıldığı hakkında çok fazla endişelenmenize gerek kalmadan gelecekteki bakımda değişiklik yapma konusunda daha fazla esnekliğe sahip olmanız da büyük bir avantaja sahiptir . Eski davranışı herhangi bir şekilde veya başka şekilde taklit edebildiğiniz sürece, SmallObjecther yerde BigObjectkullanılmış olan programınızı değiştirmek zorunda kalmadan daha önce olduğu gibi çalışabilirsiniz .

Not, bu araç BigObjectbağlı SmallObjectdeğil, aksine başka bir yol bağlıdır (benim düşünceme göre olması gerektiği gibi).


Bir cephenin yeni bir sınıfa kopya alanlarının üzerinde bulunduğundan bahsettiğiniz tek avantaj, kopyalamayı engellemektir (nesneler saçma alanlara sahip değilse büyük olasılıkla sorun olmaz). Öte yandan, statik bir dönüştürme yönteminin aksine, yeni bir sınıfa dönüştürmeniz gerektiğinde orijinal sınıfı değiştirmeniz gerekme dezavantajı vardır.
Doval

@Doval Sanırım konu bu. Yeni bir sınıfa dönüştürmezsin. İstediğin buysa başka bir cephe yaratırdın. BigObject’de yapılan değişikliklerin sadece Cephe sınıfına uygulanması gerekir, kullanıldığı her yerde kullanılmaz.
Neil

Bu yaklaşım ile Telastyn'in cevabı arasındaki ilginç bir ayrım , üretme sorumluluğunun ya da SmallObjectile yatıyor olup olmadığıdır . Varsayılan olarak, bu yaklaşım özel / korunan üyelerine bağımlılıktan kaçınmaya zorlar . Bir adım daha ileri gidebilir ve bir uzatma yöntemi kullanarak özel / korunan üyelere bağımlılıktan kaçınabiliriz . SmallObjectBigObjectSmallObjectBigObjectSmallObjectToSmallObject
Brian

@Brian Bu BigObjectşekilde karışıklık riski . Benzer bir şey yapmak isteseydiniz, ToAnotherObjectiçinde bir uzatma yöntemi yaratmaya karar verir miydiniz BigObject? Bunlar BigObject, muhtemelen olduğu gibi yeterince büyük olduğu için kaygılar olmamalıdır . Ayrıca BigObjectfabrikaları ve benzerlerini kullanabileceğiniz anlamına gelen bağımlılıklarının yaratılmasından ayrılmanıza da izin verir . Diğer yaklaşım kuvvetle çiftleşir BigObjectve SmallObject. Bu özel durumda bu iyi olabilir, ama benim düşünceme göre en iyi yöntem değildir.
Neil

1
@Neil Aslında Brian yanlış açıkladı, ama bir sağ - uzatma yöntemleri bağlantı kurtulurum. Artık BigObjecteşleşmiyor SmallObject, tartışmayı alan BigObjectve geri dönen statik bir yöntem SmallObject. Uzatma yöntemleri gerçekten, statik yöntemleri daha iyi bir şekilde çağırmak için sadece sözdizimsel şekerdir. Uzatma yöntemi değildir kısım ait BigObjecto tamamen ayrı bir statik yöntemi var. Aslında, uzatma yöntemlerinin oldukça iyi kullanımı ve özellikle DTO dönüşümleri için çok kullanışlı.
Luaan

6

Değişken referans türleri üzerindeki atmaların kimlik koruyucu olduğu konusunda çok güçlü bir kural vardır. Sistem genellikle kullanıcı tanımlı döküm operatörlerine, kaynak türünde bir nesnenin hedef tip referansına atanabileceği durumlarda izin vermediğinden, kullanıcı tanımlı döküm işlemlerinin değişken referans için makul olacağı birkaç durum vardır. türleri.

Söz konusu nesne iki yayın arasında değiştirilse bile, her ikisi de aynı nesneye uygulandığında, bir x=(SomeType)foo;süre sonra da takip edildiğinde y=(SomeType)foo;, x.Equals(y)her zaman ve her zaman doğru olması gerektiğini bir şart olarak önerebilirim . Böyle bir durum, örneğin birinin, her biri diğerine değişmez bir referansı olan ve her iki nesneyi diğer türüne çevirmek, eşleştirilmiş örneğini döndürürse, farklı türlerde bir çift nesneye sahipse uygulanabilir. Aynı zamanda, sarılmış nesnelerin kimlikleri değişmez olması koşuluyla değişken nesnelere sarıcı olarak hizmet veren türlerle de uygulanabilir ve aynı türde iki sarıcı, aynı koleksiyonu sarmaları durumunda kendilerini eşit olarak bildirir.

Özel örneğiniz değişken sınıflar kullanıyor, ancak hiçbir kimlik biçimini korumuyor; Bu nedenle, bir döküm operatörünün uygun bir kullanımı olmadığını söyleyebilirim.


1

Tamam olabilir.

Örneğinizle ilgili bir sorun, böyle örnek-ish isimleri kullanmanızdır. Düşünmek:

SomeMethod(long longNum)
{
  int num = (int)longNum;
  /* ... */

Eğer iyi bir fikrin olmasa da bunu Şimdi, neyi uzun ve int araçlar, daha sonra örtülü cast hem intetmek longve müstehcen dökme longiçin intoldukça anlaşılabilir. Ayrıca nasıl anlaşılır 3hale gelir 3ve birlikte çalışmak için sadece başka bir yoludur 3. Kontrollü int.MaxValue + 1bir bağlamda bunun nasıl başarısız olacağı anlaşılabilir . int.MaxValue + 1Sonuç olarak kontrol edilmeyen bir bağlamda nasıl çalışacağını bilmek bile int.MinValuezorlanacak en zor şey değil.

Benzer şekilde, açıkça bir temel türe veya açıkça türetilmiş bir türe attığınızda, mirasın nasıl olduğunu ve sonucun ne olacağını (veya nasıl başarısız olacağını) bilen herkes için anlaşılabilir.

Şimdi, BigObject ve SmallObject ile bu ilişkinin nasıl çalıştığı hakkında hiçbir fikrim yok. Döküm ilişkisinin açık olduğu yerlerde gerçek tipleriniz varsa, o zaman döküm gerçekten iyi bir fikir olabilir, ancak çoğu zaman, belki de büyük çoğunluğu, eğer durum buysa, o zaman sınıf hiyerarşisine ve kalıtım esaslı normal döküm yeterli olacaktır.


Aslında, söz konusu olandan çok daha fazlası değillerdir - örneğin bir BigObjecttanımlayabilir Employee {Name, Vacation Days, Bank details, Access to different building floors etc.}ve bir SmallObjectolabilir MoneyTransferRecepient {Name, Bank details}. Basit bir çeviri gelen yoktur Employeeiçin MoneyTransferRecepientve gerekenden daha bankacılık uygulamasına artık veri göndermek için hiçbir neden yoktur.
Gerino
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.