Standart .NET olay desenleri
.NET olayları genellikle bilinen birkaç deseni takip eder. Bu düzenleri standart hale getirerek geliştiricilerin herhangi bir .NET olay programına uygulanarak bu standart desenler hakkında bilgi sahibi olması gerekir.
Şimdi bu standart düzenleri kullanarak standart olay kaynakları oluşturmak ve standart olaylara abone olmak ve kodunda standart olayları işlemeye devam etmek için ihtiyacınız olan tüm bilgilere sahip olabilirsiniz.
Olay Temsilcisi İmzaları
.NET olay temsilcisi için standart imza şöyledir:
void OnEventRaised(object sender, EventArgs args);
Dönüş türü geçersizdir. Olaylar temsilcilere dayalıdır ve çok noktaya yayın temsilcileridir. Bu, herhangi bir olay kaynağı için birden çok aboneyi destekler. Bir yöntemin tek dönüş değeri birden çok olay abonesi için ölçeklendirilen değil. Olay kaynağı bir olay verdikten sonra hangi dönüş değerini görüyor? Bu makalenin devamlarında, olay kaynağına bilgi bildiren olay abonelerini destekleyen olay protokolleri oluşturma hakkında bilgi edinebilirsiniz.
Bağımsız değişken listesi iki bağımsız değişken içerir: gönderen ve olay bağımsız değişkenleri. Büyük olasılıkla her zaman doğru olacak türetilmiş bir tür biliyor olsa bile derleme sender System.Object zamanı t türü olur. Kurala göre object kullanın.
İkinci bağımsız değişken genellikle türünden türetilen bir tür System.EventArgs oldu. (Sonraki bölümde bu kuralın artık zorunlu olmadığını göreceğiz.) Olay türünüz için ek bağımsız değişkene gerek yoksa her iki bağımsız değişkeni de sağlar.
Özel bir değer vardır ve olayda ek bilgi olmadığını ifade EventArgs.Empty etmek için bunu kullanabilirsiniz.
Şimdi bir dizinde veya bir desene göre alt dizinlerinde dosyaları listeleye bir sınıf derlemeye bakalım. Bu bileşen, bulunan her dosya için desenle eşleşen bir olay hazırlar.
Olay modeli kullanmak bazı tasarım avantajları sağlar. Aranan bir dosya bulunurken farklı eylemler gerçekleştiren birden çok olay dinleyicisi oluşturabilirsiniz. Farklı dinleyicileri birleştirerek daha sağlam algoritmalar oluşturabilirsiniz.
Aranan bir dosyayı bulmaya ilişkin ilk olay bağımsız değişkeni bildirimi şu şekildedir:
public class FileFoundArgs : EventArgs
{
public string FoundFile { get; }
public FileFoundArgs(string fileName)
{
FoundFile = fileName;
}
}
Bu tür küçük, yalnızca veri türü gibi görünüyor olsa da, kuralı izleli ve bir başvuru ( class ) türü olarak gösterebilirsiniz. Bu, bağımsız değişken nesnesinin başvuruyla geçirilemesi ve tüm veri güncelleştirmelerinin tüm aboneler tarafından görüntülemesi anlamına gelir. İlk sürüm sabit bir nesnedir. Olay bağımsız değişken türü özellikleri sabit yapmak tercih gerekir. Bu şekilde, bir abone değerleri başka bir abone görene kadar değiştiremez. (Aşağıda göreceğimiz gibi bunun özel durumları vardır.)
Ardından, FileSearcher sınıfında olay bildirimini oluşturmamız gerekir. Bu EventHandler<T> türden yararlanarak başka bir tür tanımı oluşturmanıza gerek yok demektir. Yalnızca genel bir uzmanlık kullanırsiniz.
Şimdi FileSearcher sınıfını bir desenle eşan dosyaları aramak ve bir eşleşme keşfedilende doğru olayı ortaya çıkararak dolduracak şekilde doldurabilirsiniz.
public class FileSearcher
{
public event EventHandler<FileFoundArgs> FileFound;
public void Search(string directory, string searchPattern)
{
foreach (var file in Directory.EnumerateFiles(directory, searchPattern))
{
FileFound?.Invoke(this, new FileFoundArgs(file));
}
}
}
Olayları Tanımlama Field-Like Yükseltme
Sınıfınıza bir olay eklemenin en basit yolu, önceki örnekte olduğu gibi bu olayı genel alan olarak bildirebilirsiniz:
public event EventHandler<FileFoundArgs> FileFound;
Bu, kötü nesne odaklı bir uygulama gibi görünen genel bir alan bildirmektedir. Özellikler veya yöntemler aracılığıyla veri erişimini korumak istediğiniz. Bu kötü bir uygulama gibi görünüyor olabilir, ancak derleyici tarafından oluşturulan kod sarmalayıcılar oluşturur, böylece olay nesnelerine yalnızca güvenli yollarla erişilebilir. Alana benzer bir olayda yalnızca işleyici ekleme işlemleri kullanılabilir:
EventHandler<FileFoundArgs> onFileFound = (sender, eventArgs) =>
{
Console.WriteLine(eventArgs.FoundFile);
filesFound++;
};
fileLister.FileFound += onFileFound;
ve işleyiciyi kaldırma:
fileLister.FileFound -= onFileFound;
İşleyici için bir yerel değişken olduğunu unutmayın. Lambdanın gövdeyi kullandıysanız, kaldırma düzgün çalışmaz. Temsilcinin farklı bir örneği olabilir ve sessizce hiçbir şey yapmaz.
Sınıf dışındaki kod olayı yükseltamaz ve başka işlemler gerçekleştiramaz.
Olay Abonelerinden Değer Döndüren
Basit sürümünüz çalışıyor. Başka bir özellik ek o zaman: İptal.
Bulunan olayı yükselterek, bu dosya en son aranan dosya ise dinleyiciler daha fazla işlemeyi durdurabilecektir.
Olay işleyicileri bir değer dönmez, bu nedenle bunu başka bir şekilde iletişim kurmanız gerekir. Standart olay düzeni, olay abonelerin iptali iletişim kurmak için kullanabileceği alanları eklemek için EventArgs nesnesini kullanır.
İptal sözleşmesinin semantiğine bağlı olarak kullanılmaktadır. Her iki durumda da, bulunan dosya olayı için EventArguments'a bir boole alanı eklersiniz.
Bir desen, herhangi bir abonenin işlemi iptal etmesine olanak sağlar.
Bu desen için, yeni alan olarak false başlatılır. Herhangi bir abone bunu olarak true değiştirebilir. Tüm aboneler olayı gördüklerinden sonra FileSearcher bileşeni boole değerini inceler ve eyleme geçer.
İkinci desen yalnızca tüm aboneler işlemi iptal etmek istediyseniz işlemi iptal eder. Bu düzende, yeni alan, işleminin iptal edilmesi gerektiğini belirtmek için başlatılır ve herhangi bir abone işlemi devam edeceğini belirtmek için bunu değiştirebilir. Tüm aboneler olayı gördüklerinden sonra FileSearcher bileşeni booleanını inceler ve eyleme geçer. Bu düzende fazladan bir adım daha vardır: bileşenin olayı gören abone olup olduğunu biliyor olması gerekir. Abone yoksa, alanı hatalı bir iptal olduğunu gösteriyor olabilir.
Şimdi bu örnek için ilk sürümü uygulayanın. türüne adlı bir boole alanı CancelRequested eklemeniz FileFoundArgs gerekir:
public class FileFoundArgs : EventArgs
{
public string FoundFile { get; }
public bool CancelRequested { get; set;}
public FileFoundArgs(string fileName)
{
FoundFile = fileName;
}
}
Bu yeni Alan, bir Boole alanı için varsayılan değer olan olarak otomatik olarak başlatılır, bu nedenle false yanlışlıkla iptal etmeyebilirsiniz. Bileşende yapılan tek değişiklik, abonelerden herhangi biri iptal isteğinde bulunduktan sonra bayrağını kontrol etmektir:
public void List(string directory, string searchPattern)
{
foreach (var file in Directory.EnumerateFiles(directory, searchPattern))
{
var args = new FileFoundArgs(file);
FileFound?.Invoke(this, args);
if (args.CancelRequested)
break;
}
}
Bu düzenin bir avantajı, bunun yeni bir değişiklik olmadığının bir avantajıdır. Abonelerden hiçbiri daha önce iptal isteğine neden olmamıştır ve yine de iptal etmeyer. Abone kodunun yeni iptal protokolünü desteklemek istemedikçe güncelleştirilmelerine gerek yoktur. Oldukça gevşek bir şekilde bir şekilde birletir.
İlk yürütülebilir dosyayı bulduğunda iptal isteğinde bulunacak şekilde aboneyi güncelleştirin:
EventHandler<FileFoundArgs> onFileFound = (sender, eventArgs) =>
{
Console.WriteLine(eventArgs.FoundFile);
eventArgs.CancelRequested = true;
};
Başka Bir Olay Bildirimi Ekleme
Şimdi bir özellik daha ekseriz ve olaylar için diğer dil deyimlerini gösterebilirsiniz. Şimdi dosya aramada tüm alt Search dizinlerden geçen yönteminin bir aşırı yüklemesine ek olarak bakalım.
Bu, çok sayıda alt dizine sahip bir dizinde uzun bir işlem olabilir. Şimdi her yeni dizin araması başladığında ortaya çıkar bir olay ekleriz. Bu, abonelerin ilerlemeyi izlemesini ve ilerleme durumu olarak kullanıcıyı güncelleştirmesini sağlar. Şu ana kadar oluşturduğunuz tüm örnekler geneldir. Şimdi bunu bir iç olay olarak bakalım. Başka bir ifadeyle bağımsız değişkenler için kullanılan türleri de iç olarak da kullanılmaktadır.
Yeni dizini ve ilerlemeyi raporlamak için yeni EventArgs türetilmiş sınıfını oluşturarak başlayacaktır.
internal class SearchDirectoryArgs : EventArgs
{
internal string CurrentSearchDirectory { get; }
internal int TotalDirs { get; }
internal int CompletedDirs { get; }
internal SearchDirectoryArgs(string dir, int totalDirs, int completedDirs)
{
CurrentSearchDirectory = dir;
TotalDirs = totalDirs;
CompletedDirs = completedDirs;
}
}
Olay bağımsız değişkenleri için sabit bir başvuru türü yapmak için önerileri yine takip edin.
Ardından olayı tanımlayın. Bu kez farklı bir söz dizimi kullan. Alan söz dizimlerini kullanmaya ek olarak, eklenti ve kaldırma işleyicileri ile özelliğini açıkça oluşturabilirsiniz. Bu örnekte, bu işleyicilerde ek koda ihtiyacınız olmayacaktır, ancak bu, bunları nasıl oluşturabilirsiniz gösterir.
internal event EventHandler<SearchDirectoryArgs> DirectoryChanged
{
add { directoryChanged += value; }
remove { directoryChanged -= value; }
}
private EventHandler<SearchDirectoryArgs> directoryChanged;
Birçok şekilde, burada yazarak kod daha önce gördünüz alan olay tanımları için derleyici tarafından oluşturulan kodu yansıtıyor. Olayı, özellikleri için kullanılana çok benzer bir söz dizimi kullanarak oluşturabilirsiniz. İşleyicilerin farklı adlara sahip olduğunu fark add vardır: ve remove . Bunlar, etkinliğe abone olmak veya olayın aboneliğini iptal etmek için çağrılır. Olay değişkenlerini depolamak için özel bir destek alanı da bildirebilirsiniz. Null olarak başlatılır.
Şimdi, alt dizinlerden geçen ve her iki olay Search da sağlayan yönteminin aşırı yüklemesine ek olarak. Bunu yapmanın en kolay yolu, tüm dizinlerde arama yapmak istediğinizi belirtmek için varsayılan bir bağımsız değişken kullanmaktır:
public void Search(string directory, string searchPattern, bool searchSubDirs = false)
{
if (searchSubDirs)
{
var allDirectories = Directory.GetDirectories(directory, "*.*", SearchOption.AllDirectories);
var completedDirs = 0;
var totalDirs = allDirectories.Length + 1;
foreach (var dir in allDirectories)
{
directoryChanged?.Invoke(this,
new SearchDirectoryArgs(dir, totalDirs, completedDirs++));
// Search 'dir' and its subdirectories for files that match the search pattern:
SearchDirectory(dir, searchPattern);
}
// Include the Current Directory:
directoryChanged?.Invoke(this,
new SearchDirectoryArgs(directory, totalDirs, completedDirs++));
SearchDirectory(directory, searchPattern);
}
else
{
SearchDirectory(directory, searchPattern);
}
}
private void SearchDirectory(string directory, string searchPattern)
{
foreach (var file in Directory.EnumerateFiles(directory, searchPattern))
{
var args = new FileFoundArgs(file);
FileFound?.Invoke(this, args);
if (args.CancelRequested)
break;
}
}
Bu noktada, tüm alt dizinlerde arama için aşırı yüklemeyi çağıran uygulamayı çalıştırabilirsiniz. Yeni olayda abone yoktur, ancak deyimini kullanmak bunun ChangeDirectory ?.Invoke() doğru şekilde çalışmalarını sağlar.
Şimdi konsol penceresinde ilerlemeyi gösteren bir satır yazmak için bir işleyici ekleniyor.
fileLister.DirectoryChanged += (sender, eventArgs) =>
{
Console.Write($"Entering '{eventArgs.CurrentSearchDirectory}'.");
Console.WriteLine($" {eventArgs.CompletedDirs} of {eventArgs.TotalDirs} completed...");
};
.NET ekosistemi genelinde takip edilen desenleri gördünüz. Bu desenleri ve kuralları öğrenerek, hızlı bir şekilde idiomatic C# ve .NET yazabilirsiniz.
Ardından bu desenlerde .NET'in en son yayınlarında bazı değişiklikler olduğunu göreceğiz.