Eğer bile olabilir onları görmek nasılsa eşdeğer olarak onlar amaç tamamen farklı. Önce bir oyuncu kadrosunun ne olduğunu tanımlamaya çalışalım:
Çevrim, bir veri türündeki bir varlığı diğerine değiştirme eylemidir.
Bu biraz geneldir ve bir şekilde bir dönüşüme eşdeğerdir, çünkü bir oyuncu genellikle aynı dönüşüm sözdizimine sahiptir, bu nedenle soru , dil tarafından bir döküm (örtük veya açık) izin verildiğinde ve ne zaman a ( daha fazla) açık dönüşüm?
Önce aralarına basit bir çizgi çizeyim . Resmi olarak (dil sözdizimi için eşdeğer olsa bile), bir dönüşüm türü değiştirirken bir dönüşüm değeri değiştirir / değiştirebilir (sonunda türle birlikte ). Ayrıca bir dönüştürme tersine çevrilebilirken bir dönüşüm olmayabilir.
Bu konu oldukça geniş, bu yüzden özel cast operatörlerini oyundan çıkararak biraz daraltmaya çalışalım.
Örtülü yayınlar
C # 'da herhangi bir bilgiyi kaybetmediğinizde bir çevrim örtüktür (lütfen bu denetimin gerçek değerleriyle değil türlerle yapıldığını unutmayın ).
İlkel türler
Örneğin:
int tinyInteger = 10;
long bigInteger = tinyInteger;
float tinyReal = 10.0f;
double bigReal = tinyReal;
Bu türler örtüktür çünkü dönüştürme sırasında herhangi bir bilgiyi kaybetmezsiniz (sadece türü genişletirsiniz). Bunun tersi örtük atama izin verilmez çünkü gerçek değerlerine bakılmaksızın (çünkü bunlar yalnızca çalışma zamanında kontrol edilebilirler) dönüştürme sırasında bazı bilgileri kaybedebilirsiniz. Örneğin, bu kod derlenmez çünkü a double
, a ile temsil edilemeyen bir değer içerebilir (ve aslında içerir) float
:
double bigReal = Double.MaxValue;
float tinyReal = bigReal;
Nesneler
Bir nesne olması durumunda (bir işaretçi), derleyici kaynak türünün türetilmiş bir sınıf olduğundan (veya hedef sınıfın türünü uyguladığından) emin olabildiğinde çevrim her zaman örtüktür, örneğin:
string text = "123";
IFormattable formattable = text;
NotSupportedException derivedException = new NotSupportedException();
Exception baseException = derivedException;
Bu durumda derleyici bilir o string
uygular IFormattable
ve o NotSupportedException
(türetilmiştir) 'dir Exception
dökme örtülü yani. Nesneler türlerini değiştirmediği için hiçbir bilgi kaybolmaz (bu, struct
s ve ilkel türlerde farklıdır çünkü bir döküm ile başka türden yeni bir nesne yaratırsınız ), sizin onlara bakışınız ne değişir .
Açık yayınlar
Dönüştürme, derleyici tarafından dolaylı olarak yapılmadığında ve daha sonra cast operatörünü kullanmanız gerektiğinde, bir dönüştürme açıktır. Genellikle şu anlama gelir:
- Bilgi veya verileri kaybedebilirsiniz, bu yüzden bunların farkında olmanız gerekir.
- Dönüştürme başarısız olabilir (çünkü bir türü diğerine dönüştüremezsiniz) bu nedenle, yine, ne yaptığınızın farkında olmalısınız.
İlkel türler
İlkel türler için, dönüştürme sırasında bazı verileri kaybedebileceğiniz durumlarda, örneğin:
double precise = Math.Cos(Math.PI * 1.23456) / Math.Sin(1.23456);
float coarse = (float)precise;
float epsilon = (float)Double.Epsilon;
Her iki örnekte de, değerler float
aralık dahilinde olsa bile bilgileri kaybedersiniz (bu durumda hassasiyet), bu nedenle dönüşümün açık olması gerekir. Şimdi şunu dene:
float max = (float)Double.MaxValue;
Bu dönüşüm başarısız olacaktır, bu nedenle, bunun farkında olmanız için açık olmalıdır ve bir kontrol yapabilirsiniz (örnekte değer sabittir, ancak bazı çalışma zamanı hesaplamalarından veya G / Ç'den gelebilir). Örneğinize geri dönelim:
string text = "123";
double value = (double)text;
Derleyici metni sayılara dönüştüremediğinden bu derlenmez. Metin yalnızca sayıları değil, herhangi bir karakteri içerebilir ve bu, C # dilinde, açık bir tür için bile çok fazladır (ancak başka bir dilde izin verilebilir).
Nesneler
İşaretçilerden (nesnelere) dönüşümler, türler ilgisiz ise başarısız olabilir, örneğin bu kod derlenmez (çünkü derleyici olası bir dönüşüm olmadığını bilir):
string text = (string)AppDomain.Current;
Exception exception = (Exception)"abc";
Bu kod derlenir, ancak çalışma zamanında başarısız olabilir (etkili dönüştürülen nesnelerin türüne bağlıdır) bir InvalidCastException
:
object obj = GetNextObjectFromInput();
string text = (string)obj;
obj = GetNextObjectFromInput();
Exception exception = (Exception)obj;
Dönüşümler
Son olarak, eğer yayınlar dönüşüm ise, o zaman neden gibi sınıflara ihtiyacımız var Convert
? Gerçekleştirme Convert
ve IConvertible
uygulamalardan kaynaklanan ince farklılıkları görmezden gelmek, çünkü C # 'da derleyiciye şunu söylüyorsunuz:
güven bana, bu tip bu tip, şimdi bilmesen bile, bırak ben yapayım, göreceksin.
-veya-
Endişelenme, bu dönüşümde bir şeyin kaybolup kaybolmayacağı umurumda değil.
Diğer her şey için daha açık bir işleme ihtiyaç vardır ( kolay yayınların çıkarımlarını düşünün , bu yüzden C ++ onlar için uzun, ayrıntılı ve açık sözdizimi sundu). Bu, karmaşık bir işlemi içerebilir ( string
-> double
dönüştürme için bir ayrıştırma gerekli olacaktır). string
Örneğin, bir dönüştürme her zaman mümkündür ( ToString()
yöntem yoluyla ) ancak beklediğinizden farklı bir şey ifade edebilir, bu nedenle bir oyuncu kadrosundan daha açık olmalıdır (ne kadar çok yazarsanız, ne yaptığınızı daha çok düşünürsünüz ).
Bu dönüştürme, nesnenin içinde (bunun için bilinen IL talimatları kullanılarak), özel dönüştürme operatörleri (dönüştürülecek sınıfta tanımlanan) veya daha karmaşık mekanizmalar ( TypeConverter
lar veya sınıf yöntemleri, örneğin) kullanılarak yapılabilir. Bunun ne olacağının farkında değilsiniz, ancak başarısız olabileceğinin farkındasınız (bu nedenle, daha kontrollü bir dönüşüm mümkün olduğunda IMO kullanmalısınız). Sizin durumunuzda, dönüşüm basitçe ayrıştırarak string
a double
:
double value = Double.Parse(aStringVariable);
Elbette bu başarısız olabilir, bu yüzden yaparsanız, her zaman atabileceği istisnayı yakalamalısınız ( FormatException
). Burada konu dışıdır, ancak a TryParse
mevcut olduğunda onu kullanmalısınız (çünkü anlamsal olarak bunun bir sayı olmayabileceğini ve daha da hızlı olduğunu söylüyorsunuz ... başarısız olur).
.NET'teki dönüşümler birçok yerden gelebilir, TypeConverter
kullanıcı tanımlı dönüştürme operatörleri ile örtük / açık yayınlar, IConvertible
yöntemlerin uygulanması ve ayrıştırılması (bir şeyi unuttum mu?). Onlar hakkında daha fazla ayrıntı için MSDN'ye bir göz atın.
Bu uzun cevabı bitirmek için, kullanıcı tanımlı dönüştürme operatörleri hakkında sadece birkaç kelime. Programcının bir türü diğerine dönüştürmek için bir cast kullanmasına izin vermek sadece şekerdir . Bu, bir sınıf içinde (döküm yapılacak olan) bir yöntemdir ve "Hey, eğer bu türü o türe dönüştürmek istiyorsa, ben yapabilirim" diyor. Örneğin:
float? maybe = 10;
float sure1 = (float)maybe;
float sure2 = maybe.Value;
Bu durumda açıktır çünkü başarısız olabilir, ancak bu uygulamaya izin verilir (bununla ilgili yönergeler olsa bile). Bunun gibi özel bir dizgi sınıfı yazdığınızı hayal edin:
EasyString text = "123";
double value = (string)text;
Uygulamanızda "programcının hayatını kolaylaştırmaya" ve bu dönüşümü bir oyuncu kadrosu aracılığıyla ifşa etmeye karar verebilirsiniz (bunun daha az yazmak için bir kısayol olduğunu unutmayın). Hatta bazı diller buna izin verebilir:
double value = "123";
Herhangi bir türe örtük dönüşüme izin verme (kontrol çalışma zamanında yapılacaktır). Uygun seçeneklerle bu, örneğin VB.NET'te yapılabilir. Bu sadece farklı bir felsefe.
Onlarla ne yapabilirim?
Yani son soru, birini veya diğerini ne zaman kullanmanız gerektiğidir. Bakalım ne zaman açık bir döküm kullanabileceğinizi görelim:
- Temel türler arasındaki dönüşümler.
object
Başka herhangi bir türe dönüşümler (buna kutudan çıkarma da dahil olabilir).
- Türetilmiş bir sınıftan temel sınıfa (veya uygulanan bir arabirime) dönüşümler.
- Özel dönüştürme operatörleri aracılığıyla bir türden diğerine dönüşümler.
Sadece ilk dönüştürme yapılabilir, Convert
böylece diğerleri için başka seçeneğiniz yoktur ve açık bir döküm kullanmanız gerekir.
Şimdi ne zaman kullanabileceğinizi görelim Convert
:
- Herhangi bir temel türden başka bir temel türe dönüştürme (bazı sınırlamalarla, bkz. MSDN ).
IConvertible
Diğer (desteklenen) herhangi bir türe uygulanan herhangi bir türden dönüşümler .
- Bir
byte
diziden / diziye / dizeden dönüşümler .
Sonuçlar
IMO Convert
, bir dönüşümün başarısız olabileceğini bildiğiniz her seferde (format nedeniyle, aralık nedeniyle veya desteklenmeyebileceğinden), aynı dönüşüm bir dönüştürme ile yapılabilse bile (başka bir şey yoksa) kullanılmalıdır. Niyetinizin ne olduğunu ve başarısız olabileceğini (hata ayıklamayı basitleştirerek) kodunuzu kimin okuyacağını netleştirir .
Diğer her şey için bir alçı kullanmanız gerekir, seçim yok, ancak daha iyi bir yöntem varsa, o zaman kullanmanızı öneririm. Örneğinizde 'den' string
e dönüştürme, double
(özellikle kullanıcıdan metin geliyorsa) çok sık başarısız olacak bir şeydir, bu nedenle bunu olabildiğince açık hale getirmelisiniz (dahası üzerinde daha fazla kontrol sahibi olursunuz), örneğin bir TryParse
yöntem kullanarak .
Düzenleme: aralarındaki fark nedir?
Güncellenen soruya ve daha önce yazdıklarımı tutmaya göre ( ne zaman kullanabileceğiniz / kullanmanız gerektiğine kıyasla bir cast'ı ne zaman kullanabileceğiniz hakkında Convert
), netleştirilmesi gereken son nokta, aralarında fark olup olmadığıdır (dahası Convert
, işlemleri gerçekleştirebilmesi için kullanır IConvertible
ve IFormattable
arayüzler yayınlara izin verilmez).
Kısa cevap evet, farklı davranıyorlar . Convert
Sınıfı yardımcı yöntemler sınıfı olarak görüyorum, bu yüzden çoğu zaman bazı yararlar veya biraz farklı davranışlar sağlıyor. Örneğin:
double real = 1.6;
int castedInteger = (int)real;
int convertedInteger = Convert.ToInt32(real);
Oldukça farklı, değil mi? Atma kesilir (hepimizin beklediği şeydir) ancak Convert
en yakın tam sayıya yuvarlama yapar (ve bunun farkında değilseniz bu beklenmeyebilir). Her dönüştürme yöntemi farklılıklar getirir, bu nedenle genel bir kural uygulanamaz ve duruma göre görülmelidir ... Diğer türlere dönüştürmek için 19 temel tür ... liste oldukça uzun olabilir, durum!