Jawaban yang diterima dengan benar menjelaskan bagaimana daftar harus dideklarasikan dan sangat direkomendasikan untuk sebagian besar skenario.
Tetapi saya menemukan skenario yang berbeda, yang juga mencakup pertanyaan yang diajukan. Bagaimana jika Anda harus menggunakan daftar objek yang ada, seperti ViewData["htmlAttributes"]
di MVC ? Bagaimana Anda dapat mengakses propertinya (biasanya dibuat melalui new { @style="width: 100px", ... }
)?
Untuk skenario yang sedikit berbeda ini, saya ingin berbagi dengan Anda apa yang saya temukan. Dalam solusi di bawah ini, saya mengasumsikan deklarasi berikut untuk nodes
:
List<object> nodes = new List<object>();
nodes.Add(
new
{
Checked = false,
depth = 1,
id = "div_1"
});
1. Solusi dengan dinamis
Di C # 4.0 dan versi yang lebih tinggi , Anda cukup mentransmisikan ke dinamis dan menulis:
if (nodes.Any(n => ((dynamic)n).Checked == false))
Console.WriteLine("found not checked element!");
Catatan: Ini menggunakan pengikatan akhir, yang berarti ia akan mengenali hanya pada waktu proses jika objek tidak memiliki Checked
properti dan RuntimeBinderException
dalam kasus ini melontarkan a - jadi jika Anda mencoba menggunakan properti yang tidak ada Checked2
, Anda akan mendapatkan pesan berikut di runtime: "'<>f__AnonymousType0<bool,int,string>' does not contain a definition for 'Checked2'"
.
2. Solusi dengan refleksi
Solusi dengan refleksi bekerja baik dengan kompiler C # lama dan baru versi . Untuk versi C # lama harap perhatikan petunjuk di akhir jawaban ini.
Latar Belakang
Sebagai titik awal, saya menemukan jawaban yang bagus di sini . Idenya adalah untuk mengubah tipe data anonim menjadi kamus dengan menggunakan refleksi. Kamus memudahkan untuk mengakses properti, karena namanya disimpan sebagai kunci (Anda dapat mengaksesnya sepertimyDict["myProperty"]
).
Terinspirasi oleh kode pada tautan di atas, saya membuat kelas ekstensi yang disediakan GetProp
, UnanonymizeProperties
dan UnanonymizeListItems
sebagai metode ekstensi, yang menyederhanakan akses ke properti anonim. Dengan kelas ini Anda cukup melakukan kueri sebagai berikut:
if (nodes.UnanonymizeListItems().Any(n => (bool)n["Checked"] == false))
{
Console.WriteLine("found not checked element!");
}
atau Anda dapat menggunakan ekspresi nodes.UnanonymizeListItems(x => (bool)x["Checked"] == false).Any()
sebagaiif
kondisi, yang memfilter secara implisit lalu memeriksa apakah ada elemen yang dikembalikan.
Untuk mendapatkan objek pertama yang berisi properti "Dicentang" dan mengembalikan properti "kedalaman", Anda dapat menggunakan:
var depth = nodes.UnanonymizeListItems()
?.FirstOrDefault(n => n.Contains("Checked")).GetProp("depth");
atau lebih pendek: nodes.UnanonymizeListItems()?.FirstOrDefault(n => n.Contains("Checked"))?["depth"];
Catatan: Jika Anda memiliki daftar objek yang tidak selalu berisi semua properti (misalnya, beberapa tidak berisi properti "Dicentang"), dan Anda masih ingin membuat kueri berdasarkan nilai "Dicentang", Anda dapat melakukan hal ini:
if (nodes.UnanonymizeListItems(x => { var y = ((bool?)x.GetProp("Checked", true));
return y.HasValue && y.Value == false;}).Any())
{
Console.WriteLine("found not checked element!");
}
Ini mencegah, yang KeyNotFoundException
terjadi jika properti "Dicentang" tidak ada.
Kelas di bawah ini berisi metode ekstensi berikut:
UnanonymizeProperties
: Digunakan untuk membatalkan anonimitas properti yang terdapat dalam suatu objek. Metode ini menggunakan refleksi. Ini mengubah objek menjadi kamus yang berisi properti dan nilainya.
UnanonymizeListItems
: Digunakan untuk mengubah daftar objek menjadi daftar kamus yang berisi properti. Ini mungkin secara opsional berisi ekspresi lambda untuk difilter sebelumnya.
GetProp
: Digunakan untuk mengembalikan satu nilai yang cocok dengan nama properti yang diberikan. Mengizinkan untuk memperlakukan properti yang tidak ada sebagai nilai null (benar) daripada sebagai KeyNotFoundException (salah)
Untuk contoh di atas, yang diperlukan hanyalah Anda menambahkan kelas ekstensi di bawah ini:
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;
}
}
}
Petunjuk: Kode di atas adalah dengan menggunakan null-bersyarat operator, tersedia sejak C # versi 6.0 - Jika Anda bekerja dengan lebih tua C # compiler (misalnya C # 3.0), cukup mengganti ?.
dengan .
dan ?[
oleh [
mana-mana, misalnya
var depth = nodes.UnanonymizeListItems()
.FirstOrDefault(n => n.Contains("Checked"))["depth"];
Jika Anda tidak dipaksa untuk menggunakan kompiler C # yang lebih lama, pertahankan apa adanya, karena menggunakan null-conditionals membuat penanganan null menjadi lebih mudah.
Catatan: Seperti solusi lain dengan dinamis, solusi ini juga menggunakan pengikatan akhir, tetapi dalam kasus ini Anda tidak mendapatkan pengecualian - solusi ini tidak akan menemukan elemen jika Anda merujuk ke properti yang tidak ada, selama saat Anda mempertahankan operator bersyarat null .
Apa yang mungkin berguna untuk beberapa aplikasi adalah bahwa properti tersebut dirujuk melalui string dalam solusi 2, sehingga dapat dijadikan parameter.