Bagaimana cara mengirimkan tipe anonim sebagai parameter ke fungsi lain? Pertimbangkan contoh ini:
var query = from employee in employees select new { Name = employee.Name, Id = employee.Id };
LogEmployees(query);
Variabel di query
sini tidak memiliki tipe yang kuat. Bagaimana saya harus mendefinisikan LogEmployees
fungsi saya untuk menerimanya?
public void LogEmployees (? list)
{
foreach (? item in list)
{
}
}
Dengan kata lain, apa yang harus saya gunakan sebagai pengganti ?
tanda.
c#
function
parameters
anonymous-types
Saeed Neamati
sumber
sumber
Jawaban:
Saya pikir Anda harus membuat kelas untuk tipe anonim ini. Itu akan menjadi hal yang paling masuk akal untuk dilakukan menurut saya. Tetapi jika Anda benar-benar tidak menginginkannya, Anda dapat menggunakan dinamika:
public void LogEmployees (IEnumerable<dynamic> list) { foreach (dynamic item in list) { string name = item.Name; int id = item.Id; } }
Perhatikan bahwa ini tidak diketik dengan kuat, jadi jika, misalnya, Name berubah menjadi EmployeeName, Anda tidak akan tahu ada masalah hingga runtime.
sumber
dynamic
penggunaan. Saya benar-benar berguna bagi saya. Terima kasih :)Anda bisa melakukannya seperti ini:
public void LogEmployees<T>(List<T> list) // Or IEnumerable<T> list { foreach (T item in list) { } }
... tetapi Anda tidak akan bisa berbuat banyak dengan setiap item. Anda dapat memanggil ToString, tetapi Anda tidak akan dapat menggunakan (katakanlah)
Name
danId
secara langsung.sumber
where T : some type
di akhir baris pertama untuk mempersempit jenisnya. Namun, pada titik itu, mengharapkan jenis antarmuka umum tertentu akan lebih masuk akal untuk mengharapkan antarmuka. :)where T : some type
dengan jenis anonim, karena mereka tidak menerapkan jenis antarmuka apa pun ...Sayangnya, apa yang Anda coba lakukan tidak mungkin. Di balik terpal, variabel kueri diketik menjadi
IEnumerable
tipe anonim. Nama tipe anonim tidak dapat direpresentasikan dalam kode pengguna oleh karena itu tidak ada cara untuk menjadikannya parameter input ke suatu fungsi.Taruhan terbaik Anda adalah membuat jenis dan menggunakannya sebagai hasil dari kueri dan kemudian meneruskannya ke dalam fungsi. Sebagai contoh,
struct Data { public string ColumnName; } var query = (from name in some.Table select new Data { ColumnName = name }); MethodOp(query); ... MethodOp(IEnumerable<Data> enumerable);
Namun dalam kasus ini, Anda hanya memilih satu bidang, jadi mungkin lebih mudah untuk langsung memilih bidang tersebut. Ini akan menyebabkan kueri diketik sebagai
IEnumerable
jenis bidang. Dalam hal ini, nama kolom.var query = (from name in some.Table select name); // IEnumerable<string>
sumber
Equals
perilaku perubahan. Yaitu Anda harus menerapkannya. (Saya tahu tentang perbedaan ini tetapi masih berhasil melupakannya selama refactoring.)Anda tidak dapat meneruskan tipe anonim ke fungsi non generik, kecuali tipe parameternya adalah
object
.public void LogEmployees (object obj) { var list = obj as IEnumerable(); if (list == null) return; foreach (var item in list) { } }
Jenis anonim dimaksudkan untuk penggunaan jangka pendek dalam suatu metode.
Dari MSDN - Jenis Anonim :
(penekanan saya)
Memperbarui
Anda dapat menggunakan obat generik untuk mencapai apa yang Anda inginkan:
public void LogEmployees<T>(IEnumerable<T> list) { foreach (T item in list) { } }
sumber
object
- ordynamic
; pobject
tidak sama dengan membuat metode generik dalam tipe anonim, sesuai jawaban saya.Biasanya, Anda melakukan ini dengan obat generik, misalnya:
Kompilator kemudian harus menyimpulkan
T
kapan Anda memanggilMapEntToObj(query)
. Tidak begitu yakin apa yang ingin Anda lakukan di dalam metode ini, jadi saya tidak tahu apakah ini berguna ... masalahnya adalah di dalamMapEntToObj
Anda masih tidak dapat memberi namaT
- Anda juga dapat:T
T
untuk melakukan sesuatutetapi selain itu, cukup sulit untuk memanipulasi tipe anonim - paling tidak karena mereka tidak dapat diubah ;-p
Trik lain (saat mengekstrak data) adalah juga meneruskan selektor - yaitu sesuatu seperti:
Foo<TSource, TValue>(IEnumerable<TSource> source, Func<TSource,string> name) { foreach(TSource item in source) Console.WriteLine(name(item)); } ... Foo(query, x=>x.Title);
sumber
Anda dapat menggunakan obat generik dengan trik berikut (mentransmisikan ke tipe anonim):
public void LogEmployees<T>(IEnumerable<T> list) { foreach (T item in list) { var typedItem = Cast(item, new { Name = "", Id = 0 }); // now you can use typedItem.Name, etc. } } static T Cast<T>(object obj, T type) { return (T)obj; }
sumber
"dinamis" juga dapat digunakan untuk tujuan ini.
var anonymousType = new { Id = 1, Name = "A" }; var anonymousTypes = new[] { new { Id = 1, Name = "A" }, new { Id = 2, Name = "B" }; private void DisplayAnonymousType(dynamic anonymousType) { } private void DisplayAnonymousTypes(IEnumerable<dynamic> anonymousTypes) { foreach (var info in anonymousTypes) { } }
sumber
Alih-alih meneruskan tipe anonim, teruskan Daftar tipe dinamis:
var dynamicResult = anonymousQueryResult.ToList<dynamic>();
DoSomething(List<dynamic> _dynamicResult)
DoSomething(dynamicResult);
Terima kasih kepada Petar Ivanov !
sumber
Jika Anda tahu, bahwa hasil Anda mengimplementasikan antarmuka tertentu, Anda dapat menggunakan antarmuka sebagai tipe data:
public void LogEmployees<T>(IEnumerable<T> list) { foreach (T item in list) { } }
sumber
Saya akan gunakan
IEnumerable<object>
sebagai tipe untuk argumen. Namun bukan keuntungan besar untuk pemeran eksplisit yang tidak dapat dihindari. Bersulangsumber