C# 6 Yeni Özelliklere Genel Bakış
C# dilinin sürüm 6'sı, daha az ortak kod, geliştirilmiş netlik ve daha fazla tutarlılık sağlamak için dili geliştirmeye devam eder. Daha temiz başlatma söz dizimi, catch/finally bloklarında await özelliğini ve null koşullu ? işleci özellikle yararlıdır.
Not
C# dilinin en son sürümü (sürüm 7) hakkında bilgi için C# 7.0'daki Yenilikler makalesine bakın
Bu belgede C# 6'nın yeni özellikleri tanıtılmıştır. Mono derleyicisi tarafından tam olarak desteklenir ve geliştiriciler tüm Xamarin hedef platformlarında yeni özellikleri kullanmaya başlayabilir.
C# 6 videosundaki yenilikler
C# 6 kullanma
C# 6 derleyicisi, Mac için Visual Studio'nin tüm son sürümlerinde kullanılır.
Komut satırı derleyicileri kullananlar, 4.0 veya üzerini döndürdüğünü mcs --version
onaylamalıdır.
Mac için Visual Studio kullanıcılar mono 4 (veya daha yeni) yüklü olup olmadığını denetlemek için Ayrıntıları Gösterme Mac için Visual Studio > Mac için Visual Studio > hakkında.
Daha Az Ortak
statik kullanma
Numaralandırmalar ve gibi bazı sınıflar öncelikli olarak System.Math
statik değerlerin ve işlevlerin sahipleridir. C# 6'da, bir türün tüm statik üyelerini tek using static
bir deyimle içeri aktarabilirsiniz. C# 5 ve C# 6'daki tipik bir trigonometrik işlevi karşılaştırın:
// Classic C#
class MyClass
{
public static Tuple<double,double> SolarAngleOld(double latitude, double declination, double hourAngle)
{
var tmp = Math.Sin (latitude) * Math.Sin (declination) + Math.Cos (latitude) * Math.Cos (declination) * Math.Cos (hourAngle);
return Tuple.Create (Math.Asin (tmp), Math.Acos (tmp));
}
}
// C# 6
using static System.Math;
class MyClass
{
public static Tuple<double, double> SolarAngleNew(double latitude, double declination, double hourAngle)
{
var tmp = Asin (latitude) * Sin (declination) + Cos (latitude) * Cos (declination) * Cos (hourAngle);
return Tuple.Create (Asin (tmp), Acos (tmp));
}
}
using static
ve Math.E
gibi Math.PI
ortak const
alanları doğrudan erişilebilir yapmaz:
for (var angle = 0.0; angle <= Math.PI * 2.0; angle += Math.PI / 8) ...
//PI is const, not static, so requires Math.PI
Uzantı Yöntemleri ile statik kullanma
Tesis using static
, genişletme yöntemleriyle biraz farklı çalışır. Uzantı yöntemleri kullanılarak static
yazılmasına rağmen, üzerinde çalışılması gereken bir örnek olmadan anlamlı değildir. using static
Bu nedenle, uzantı yöntemlerini tanımlayan bir türle kullanıldığında, uzantı yöntemleri hedef türlerinde (yöntemin this
türü) kullanılabilir hale gelir. Örneğin, using static System.Linq.Enumerable
tüm LINQ türlerini getirmeden nesne API'sini IEnumerable<T>
genişletmek için kullanılabilir:
using static System.Linq.Enumerable;
using static System.String;
class Program
{
static void Main()
{
var values = new int[] { 1, 2, 3, 4 };
var evenValues = values.Where (i => i % 2 == 0);
System.Console.WriteLine (Join(",", evenValues));
}
}
Önceki örnekte davranış farkı gösterilmektedir: uzantı yöntemi Enumerable.Where
diziyle ilişkilendirilirken, statik yöntem String.Join
türüne String
başvurmadan çağrılabilir.
nameof İfadeleri
Bazen, bir değişken veya alan verdiğiniz ada başvurmak isteyebilirsiniz. C# 6'da nameof(someVariableOrFieldOrType)
dizesini "someVariableOrFieldOrType"
döndürür. Örneğin, bir ArgumentException
oluştururken hangi bağımsız değişkenin geçersiz olduğunu adlandırmak isteyebilirsiniz:
throw new ArgumentException ("Problem with " + nameof(myInvalidArgument))
İfadelerin nameof
en büyük avantajı, tür denetlenmeleri ve araç destekli yeniden düzenleme ile uyumlu olmalarıdır. İfadelerin nameof
tür denetimi, türleri dinamik olarak ilişkilendirmek için kullanılan durumlarda string
özellikle hoş karşılanır. Örneğin, iOS'ta bir string
içindeki nesnelerin prototipini UITableViewCell
oluşturmak için kullanılan türü belirtmek için a UITableView
kullanılır. nameof
bu ilişkilendirmenin yazım hatası veya dikkatsiz yeniden düzenleme nedeniyle başarısız olmadığından emin olabilir:
public override UITableViewCell GetCell (UITableView tableView, NSIndexPath indexPath)
{
var cell = tableView.DequeueReusableCell (nameof(CellTypeA), indexPath);
cell.TextLabel.Text = objects [indexPath.Row].ToString ();
return cell;
}
öğesine bir nitelenmiş ad nameof
geçirebilirsiniz ancak yalnızca son öğe (son .
öğeden sonra) döndürülür. Örneğin, Xamarin.Forms'da veri bağlaması ekleyebilirsiniz:
var myReactiveInstance = new ReactiveType ();
var myLabelOld.BindingContext = myReactiveInstance;
var myLabelNew.BindingContext = myReactiveInstance;
var myLabelOld.SetBinding (Label.TextProperty, "StringField");
var myLabelNew.SetBinding (Label.TextProperty, nameof(ReactiveType.StringField));
öğesine yapılan iki çağrı SetBinding
aynı değerleri geçiriyor: nameof(ReactiveType.StringField)
başlangıçta "StringField"
bekleyebileceğiniz gibi değil "ReactiveType.StringField"
.
Null koşullu İşleç
C# için yapılan önceki güncelleştirmelerde, null değer atanabilir değerleri işlerken ortak kod miktarını azaltmak için null atanabilir türler ve null birleşim işleci ??
kavramları tanıtılmıştır. C# 6 bu temaya "null-koşullu işleç" ?.
ile devam eder. İfadenin sağ tarafındaki bir nesnede kullanıldığında, null koşullu işleç nesne değilse null
ve null
değilse üye değerini döndürür:
var ss = new string[] { "Foo", null };
var length0 = ss [0]?.Length; // 3
var length1 = ss [1]?.Length; // null
var lengths = ss.Select (s => s?.Length ?? 0); //[3, 0]
(Hem hem de length0
length1
türünden int?
çıkarılır)
Önceki örnekteki son satır null koşullu işlecini null birleşim işleciyle birlikte ??
gösterir?
. Yeni C# 6 null koşullu işleci, dizideki 2. öğeyi döndürür null
; bu noktada null birleşim işleci devreye girip diziye lengths
bir 0 sağlar (bunun uygun olup olmadığı elbette soruna özgüdür).
Null koşullu işleç, birçok uygulamada gerekli olan ortak null denetimi miktarını büyük ölçüde azaltmalıdır.
Belirsizliklerden dolayı null koşullu işleçte bazı sınırlamalar vardır. Bir temsilciyle yapmak isteyebileceğiniz gibi, parantez içinde bağımsız değişken listesiyle hemen takip ?
edemezsiniz:
SomeDelegate?("Some Argument") // Not allowed
Ancak, Invoke
bağımsız değişken listesinden ?
ayırmak için kullanılabilir ve yine de bir -checking ortak bloğu üzerinde belirgin bir null
iyileştirmedir:
public event EventHandler HandoffOccurred;
public override bool ContinueUserActivity (UIApplication application, NSUserActivity userActivity, UIApplicationRestorationHandler completionHandler)
{
HandoffOccurred?.Invoke (this, userActivity.UserInfo);
return true;
}
Dize İlişkilendirme
String.Format
İşlev geleneksel olarak dizinleri biçim dizesinde yer tutucu olarak kullanmıştır; örneğin, String.Format("Expected: {0} Received: {1}.", expected, received
). Elbette, yeni bir değer eklemek her zaman bağımsız değişkenleri saymak, yer tutucuları yeniden numaralandırmak ve yeni bağımsız değişkeni bağımsız değişken listesinde doğru sırada eklemek için can sıkıcı küçük bir görevi içerir.
C# 6'nın yeni dize ilişkilendirme özelliği üzerinde String.Format
büyük ölçüde iyileştirir. Artık, ön eki olan $
bir dizedeki değişkenleri doğrudan adlandırabilirsiniz. Örneğin:
$"Expected: {expected} Received: {received}."
Değişkenler elbette işaretlidir ve yanlış yazılmış veya kullanılamayan bir değişken derleyici hatasına neden olur.
Yer tutucuların basit değişkenler olması gerekmez, herhangi bir ifade olabilir. Bu yer tutucuların içinde, bu tırnak işaretlerinden kaçmadan tırnak işaretlerini kullanabilirsiniz. Örneğin, aşağıdakilere "s"
dikkat edin:
var s = $"Timestamp: {DateTime.Now.ToString ("s", System.Globalization.CultureInfo.InvariantCulture )}"
Dize ilişkilendirme, hizalama ve biçimlendirme söz dizimini String.Format
destekler. Daha önce yazdığınız {index, alignment:format}
gibi, C# 6'da şunu yazarsınız {placeholder, alignment:format}
:
using static System.Linq.Enumerable;
using System;
class Program
{
static void Main ()
{
var values = new int[] { 1, 2, 3, 4, 12, 123456 };
foreach (var s in values.Select (i => $"The value is { i,10:N2}.")) {
Console.WriteLine (s);
}
Console.WriteLine ($"Minimum is { values.Min(i => i):N2}.");
}
}
sonuç:
The value is 1.00.
The value is 2.00.
The value is 3.00.
The value is 4.00.
The value is 12.00.
The value is 123,456.00.
Minimum is 1.00.
Dize ilişkilendirmesi için String.Format
söz dizimsel şekerdir: dize değişmez değerleriyle @""
kullanılamaz ve yer tutucu kullanılmasa bile ile const
uyumlu değildir:
const string s = $"Foo"; //Error : const requires value
Dize ilişkilendirmesi ile işlev bağımsız değişkenleri oluşturmanın yaygın kullanım örneğinde, yine de kaçış, kodlama ve kültür sorunları konusunda dikkatli olmanız gerekir. SQL ve URL sorguları elbette temizleme açısından kritik öneme sahiptir. gibi String.Format
dize ilişkilendirmesi de kullanır CultureInfo.CurrentCulture
. Kullanmak CultureInfo.InvariantCulture
biraz daha fazla sözcükle ifade edilir:
Thread.CurrentThread.CurrentCulture = new CultureInfo ("de");
Console.WriteLine ($"Today is: {DateTime.Now}"); //"21.05.2015 13:52:51"
Console.WriteLine ($"Today is: {DateTime.Now.ToString(CultureInfo.InvariantCulture)}"); //"05/21/2015 13:52:51"
Başlatma
C# 6 özellikleri, alanları ve üyeleri belirtmek için çeşitli kısa yollar sağlar.
Otomatik Özellik Başlatma
Otomatik özellikler artık alanlarla aynı kısa sürede başlatılabilir. Sabit otomatik özellikler yalnızca bir alıcıyla yazılabilir:
class ToDo
{
public DateTime Due { get; set; } = DateTime.Now.AddDays(1);
public DateTime Created { get; } = DateTime.Now;
Oluşturucuda, yalnızca alıcı otomatik özelliğinin değerini ayarlayabilirsiniz:
class ToDo
{
public DateTime Due { get; set; } = DateTime.Now.AddDays(1);
public DateTime Created { get; } = DateTime.Now;
public string Description { get; }
public ToDo (string description)
{
this.Description = description; //Can assign (only in constructor!)
}
Otomatik özelliklerin bu şekilde başlatılması hem genel bir alan tasarrufu özelliğidir hem de nesnelerinde değişmezliği vurgulama isteğinde bulunan geliştiriciler için bir boondur.
Dizin Başlatıcıları
C# 6, dizin başlatıcısı olan türlerde hem anahtarı hem de değeri ayarlamanıza olanak tanıyan dizin başlatıcılarını tanıtır. Bu genellikle -style veri yapıları içindir Dictionary
:
partial void ActivateHandoffClicked (WatchKit.WKInterfaceButton sender)
{
var userInfo = new NSMutableDictionary {
["Created"] = NSDate.Now,
["Due"] = NSDate.Now.AddSeconds(60 * 60 * 24),
["Task"] = Description
};
UpdateUserActivity ("com.xamarin.ToDo.edit", userInfo, null);
statusLabel.SetText ("Check phone");
}
İfade Gövdeli İşlev Üyeleri
Lambda işlevlerinin birkaç avantajı vardır ve bunlardan biri yalnızca alan tasarrufu sağlar. Benzer şekilde, ifade gövdeli sınıf üyeleri küçük işlevlerin C# 6'nın önceki sürümlerinde mümkün olandan biraz daha kısa ifade edilmesine olanak tanır.
İfade gövdeli işlev üyeleri, geleneksel blok söz dizimi yerine lambda ok söz dizimini kullanır:
public override string ToString () => $"{FirstName} {LastName}";
Lambda-ok söz diziminin açık return
bir kullanmadığını fark edin. döndüren void
işlevler için ifadenin de bir deyimi olması gerekir:
public void Log(string message) => System.Console.WriteLine($"{DateTime.Now.ToString ("s", System.Globalization.CultureInfo.InvariantCulture )}: {message}");
İfade gövdeli üyeler hala yöntemler için desteklenen kurala async
tabidir, ancak özelliklere tabi değildir:
//A method, so async is valid
public async Task DelayInSeconds(int seconds) => await Task.Delay(seconds * 1000);
//The following property will not compile
public async Task<int> LeisureHours => await Task.FromResult<char> (DateTime.Now.DayOfWeek.ToString().First()) == 'S' ? 16 : 5;
Özel durumlar
Bunun iki yolu yoktur: özel durum işlemeyi doğru yapmak zordur. C# 6'daki yeni özellikler, özel durum işlemeyi daha esnek ve tutarlı hale getirir.
Özel Durum Filtreleri
Tanım gereği, özel durumlar olağan dışı durumlarda ortaya çıkar ve belirli bir tür özel durumunun oluşabileceği tüm yöntemler hakkında mantık yürütmesi ve kodlanması çok zor olabilir. C# 6, çalışma zamanı tarafından değerlendirilen bir filtreyle yürütme işleyicisini koruma özelliğini tanıtır. Bu, normal catch(ExceptionType)
bildirimden sonra bir when (bool)
desen eklenerek yapılır. Aşağıdaki filtre, parametreyle ilgili ayrıştırma hatasını date
diğer ayrıştırma hatalarından farklı olarak ayırt eder.
public void ExceptionFilters(string aFloat, string date, string anInt)
{
try
{
var f = Double.Parse(aFloat);
var d = DateTime.Parse(date);
var n = Int32.Parse(anInt);
} catch (FormatException e) when (e.Message.IndexOf("DateTime") > -1) {
Console.WriteLine ($"Problem parsing \"{nameof(date)}\" argument");
} catch (FormatException x) {
Console.WriteLine ("Problem parsing some other argument");
}
}
yakalamada bekle... Sonunda...
async
C# 5'te sunulan özellikler, dil için bir oyun değiştirici olmuştur. C# 5'te ve await
finally
bloklarında catch
izin verilmedi, bu özellik değeri async/await
göz önüne alındığında bir sıkıntı. C# 6 bu sınırlamayı kaldırarak aşağıdaki kod parçacığında gösterildiği gibi program aracılığıyla zaman uyumsuz sonuçların tutarlı bir şekilde beklenmesine olanak tanır:
async void SomeMethod()
{
try {
//...etc...
} catch (Exception x) {
var diagnosticData = await GenerateDiagnosticsAsync (x);
Logger.log (diagnosticData);
} finally {
await someObject.FinalizeAsync ();
}
}
Özet
C# dili, geliştiricileri daha üretken hale getirmek için gelişmeye devam ederken, iyi uygulamaları ve destekleyici araçları da tanıtıyor. Bu belgede C# 6'daki yeni dil özelliklerine genel bir bakış verilmiş ve bunların nasıl kullanıldığı kısaca gösterilmiştir.