Kabul edilen cevap, listenin nasıl açıklanması gerektiğini doğru bir şekilde açıklar ve çoğu senaryo için şiddetle tavsiye edilir.
Ama sorulan soruyu da kapsayan farklı bir senaryo ile karşılaştım. Eğer gibi, varolan nesne listesini kullanmak için ne varsa ViewData["htmlAttributes"]
içinde MVC ? Özelliklerine nasıl erişebilirsiniz (genellikle aracılığıyla oluşturulurlar new { @style="width: 100px", ... }
)?
Bu biraz farklı senaryo için öğrendiklerimi sizinle paylaşmak istiyorum. Aşağıdaki çözümlerde, aşağıdaki beyanı varsayıyorum nodes
:
List<object> nodes = new List<object>();
nodes.Add(
new
{
Checked = false,
depth = 1,
id = "div_1"
});
1. Dinamik çözüm
İçinde C # 4.0 ve daha yüksek sürümleri, sadece dinamik ve yazma yayın yapabilirsiniz:
if (nodes.Any(n => ((dynamic)n).Checked == false))
Console.WriteLine("found not checked element!");
Not: Bu, geç bağlamayı kullanıyor , yani yalnızca çalışma zamanında nesnenin bir Checked
özelliği yoksa ve birRuntimeBinderException
bu durumda - bu nedenle, mevcut olmayan bir Checked2
özelliği kullanmaya çalışırsanız şu mesajı alırsınız : Çalışma zamanı: "'<>f__AnonymousType0<bool,int,string>' does not contain a definition for 'Checked2'"
.
2. Yansımalı çözüm
Yansımalı çözüm işe yarıyor hem eski hem de yeni C # derleyici sürümleriyle çalışır. Eski C # sürümleri için lütfen bu cevabın sonundaki ipucunu dikkate alın.
Arka fon
Başlangıç noktası olarak burada iyi bir cevap buldum . Buradaki fikir, anonim veri türünü yansıma kullanarak bir sözlüğe dönüştürmektir. Sözlük, isimleri anahtar olarak saklandığından (istediğiniz gibi erişebilirsiniz myDict["myProperty"]
) özelliklere erişimi kolaylaştırır .
Yukarıdaki linkte kod esinlenerek, ben sağlayan bir uzatma sınıfını yarattı GetProp
, UnanonymizeProperties
ve UnanonymizeListItems
uzatma yöntemleri anonim özelliklerine basitleştirmek erişim gibi. Bu sınıfla, sorguyu aşağıdaki gibi yapabilirsiniz:
if (nodes.UnanonymizeListItems().Any(n => (bool)n["Checked"] == false))
{
Console.WriteLine("found not checked element!");
}
veya ifadeyi koşul nodes.UnanonymizeListItems(x => (bool)x["Checked"] == false).Any()
olarak kullanabilirsiniz; if
bu, örtük olarak filtreler ve sonra döndürülen herhangi bir öğe olup olmadığını kontrol eder.
"Kontrol Edildi" özelliğini içeren ilk nesneyi almak ve "derinlik" özelliğini döndürmek için şunları kullanabilirsiniz:
var depth = nodes.UnanonymizeListItems()
?.FirstOrDefault(n => n.Contains("Checked")).GetProp("depth");
veya daha kısa: nodes.UnanonymizeListItems()?.FirstOrDefault(n => n.Contains("Checked"))?["depth"];
Not: Tüm özellikleri içermesi gerekmeyen nesnelerin bir listeniz varsa (örneğin, bazıları "Kontrol edilen" özelliği içermiyorsa) ve yine de "Kontrol edilen" değerlere dayalı bir sorgu oluşturmak istiyorsanız, Bunu yap:
if (nodes.UnanonymizeListItems(x => { var y = ((bool?)x.GetProp("Checked", true));
return y.HasValue && y.Value == false;}).Any())
{
Console.WriteLine("found not checked element!");
}
Bu KeyNotFoundException
, "Kontrol Edildi" özelliği yoksa a oluşmasını engeller .
Aşağıdaki sınıf, aşağıdaki uzatma yöntemlerini içerir:
UnanonymizeProperties
: Bir nesnede bulunan özelliklerin anonim hale getirilmesi için kullanılır . Bu yöntem yansıma kullanır. Nesneyi, özellikleri ve değerlerini içeren bir sözlüğe dönüştürür.
UnanonymizeListItems
: Nesnelerin bir listesini, özellikleri içeren bir sözlükler listesine dönüştürmek için kullanılır. Önceden filtrelemek için isteğe bağlı olarak bir lambda ifadesi içerebilir .
GetProp
: Verilen özellik adıyla eşleşen tek bir değer döndürmek için kullanılır. Var olmayan özellikleri KeyNotFoundException (false) yerine boş değerler (doğru) olarak değerlendirmeye izin verir
Yukarıdaki örnekler için gereken tek şey, aşağıdaki uzantı sınıfını eklemenizdir:
public static class AnonymousTypeExtensions
{
// makes properties of object accessible
public static IDictionary UnanonymizeProperties(this object obj)
{
Type type = obj?.GetType();
var properties = type?.GetProperties()
?.Select(n => n.Name)
?.ToDictionary(k => k, k => type.GetProperty(k).GetValue(obj, null));
return properties;
}
// converts object list into list of properties that meet the filterCriteria
public static List<IDictionary> UnanonymizeListItems(this List<object> objectList,
Func<IDictionary<string, object>, bool> filterCriteria=default)
{
var accessibleList = new List<IDictionary>();
foreach (object obj in objectList)
{
var props = obj.UnanonymizeProperties();
if (filterCriteria == default
|| filterCriteria((IDictionary<string, object>)props) == true)
{ accessibleList.Add(props); }
}
return accessibleList;
}
// returns specific property, i.e. obj.GetProp(propertyName)
// requires prior usage of AccessListItems and selection of one element, because
// object needs to be a IDictionary<string, object>
public static object GetProp(this object obj, string propertyName,
bool treatNotFoundAsNull = false)
{
try
{
return ((System.Collections.Generic.IDictionary<string, object>)obj)
?[propertyName];
}
catch (KeyNotFoundException)
{
if (treatNotFoundAsNull) return default(object); else throw;
}
}
}
İpucu: Yukarıdaki kod kullanarak boş-koşullu C # sürüm 6.0 beri mevcut operatörler, - eğer Birlikte olduğun çalışma eski C # derleyicileri (örneğin C # 3.0), basitçe yerine ?.
göre .
ve ?[
tarafından [
örn her yerde
var depth = nodes.UnanonymizeListItems()
.FirstOrDefault(n => n.Contains("Checked"))["depth"];
Eğer ediyorsanız değil eski bir C # derleyicisi kullanmak zorunda boş-conditionals kullanarak çok daha kolay taşıma null adlı yapar, çünkü o kadar olduğunu tutun.
Not: Dinamikli diğer çözüm gibi, bu çözüm de geç bağlama kullanıyor, ancak bu durumda bir istisna almıyorsunuz - mevcut olmayan bir mülke atıfta bulunuyorsanız öğeyi bulamayacağı sürece boş koşullu tuttuğunuzda operatörleri.
Bazı uygulamalar için faydalı olabilecek şey, özelliğe çözüm 2'de bir dizge aracılığıyla başvurulması, dolayısıyla parametreleştirilebilmesidir.