Beralih dari lambda ke Expression mudah menggunakan metode panggilan ...
public void GimmeExpression(Expression<Func<T>> expression)
{
((MemberExpression)expression.Body).Member.Name; // "DoStuff"
}
public void SomewhereElse()
{
GimmeExpression(() => thing.DoStuff());
}
Tapi saya ingin mengubah Func menjadi ekspresi, hanya dalam kasus yang jarang terjadi ...
public void ContainTheDanger(Func<T> dangerousCall)
{
try
{
dangerousCall();
}
catch (Exception e)
{
// This next line does not work...
Expression<Func<T>> DangerousExpression = dangerousCall;
var nameOfDanger =
((MemberExpression)dangerousCall.Body).Member.Name;
throw new DangerContainer(
"Danger manifested while " + nameOfDanger, e);
}
}
public void SomewhereElse()
{
ContainTheDanger(() => thing.CrossTheStreams());
}
Garis yang tidak berfungsi memberi saya kesalahan waktu kompilasi Cannot implicitly convert type 'System.Func<T>' to 'System.Linq.Expressions.Expression<System.Func<T>>'
. Pemeran eksplisit tidak menyelesaikan situasi. Apakah ada fasilitas untuk melakukan ini yang saya abaikan?
at lambda_method(Closure )
untuk pemanggilan delegasi yang dikompilasi.Jawaban:
Ooh, itu tidak mudah sama sekali.
Func<T>
mewakilidelegate
ekspresi generik dan bukan. Jika ada cara untuk melakukannya (karena pengoptimalan dan hal lain yang dilakukan oleh compiler, beberapa data mungkin dibuang, jadi mungkin tidak mungkin untuk mendapatkan kembali ekspresi aslinya), itu akan membongkar IL dengan cepat dan menyimpulkan ungkapan (yang sama sekali tidak mudah). Memperlakukan ekspresi lambda sebagai data (Expression<Func<T>>
) adalah keajaiban yang dilakukan oleh kompilator (pada dasarnya kompilator membangun pohon ekspresi dalam kode alih-alih mengkompilasinya ke IL).Fakta terkait
Inilah sebabnya mengapa bahasa yang mendorong lambda hingga ekstrem (seperti Lisp) seringkali lebih mudah diimplementasikan sebagai penerjemah . Dalam bahasa tersebut, kode dan data pada dasarnya adalah hal yang sama (bahkan saat dijalankan ), tetapi chip kami tidak dapat memahami bentuk kode tersebut, jadi kami harus meniru mesin seperti itu dengan membangun interpreter di atasnya yang memahaminya ( pilihan yang dibuat oleh Lisp seperti bahasa) atau mengorbankan kekuatan (kode tidak akan lagi persis sama dengan data) sampai batas tertentu (pilihan dibuat oleh C #). Dalam C #, kompilator memberikan ilusi memperlakukan kode sebagai data dengan mengizinkan lambda diinterpretasikan sebagai kode (
Func<T>
) dan data (Expression<Func<T>>
) pada waktu kompilasi .sumber
eval
Anda perlu memulai kompilator, tetapi selain itu, tidak ada masalah sama sekali untuk melakukan itu.Expression
tentang tindakan pembungkus Anda, tetapi itu tidak akan memiliki info pohon ekspresi tentang internaldangerousCall
delegasi.sumber
Func
akan disembunyikan di Expression baru. Ini hanya menambahkan satu lapisan data di atas kode; Anda dapat melintasi satu lapisan hanya untuk menemukan parameter Andaf
tanpa detail lebih lanjut, jadi Anda tepat di tempat Anda memulai.Apa yang mungkin harus Anda lakukan adalah membalikkan metode. Ambil Expression>, lalu kompilasi dan jalankan. Jika gagal, Anda sudah memiliki Expression untuk diperiksa.
Jelas Anda perlu mempertimbangkan implikasi kinerja dari ini, dan menentukan apakah itu sesuatu yang benar-benar perlu Anda lakukan.
sumber
Anda bisa pergi ke arah lain melalui metode .Compile () - tidak yakin apakah ini berguna untuk Anda:
sumber
Jika terkadang Anda membutuhkan ekspresi dan terkadang membutuhkan delegasi, Anda memiliki 2 opsi:
Expression<...>
versinya, dan hanya.Compile().Invoke(...)
jika Anda ingin delegasi. Jelas ini membutuhkan biaya.sumber
NJection.LambdaConverter adalah pustaka yang mengubah delegasi menjadi ekspresi
sumber
sumber
call.Target
bagian yang membunuh saya. Ini bekerja selama bertahun-tahun, dan kemudian tiba-tiba berhenti bekerja dan mulai mengeluh tentang bla bla statis / non-statis. Terima kasih!JB Evain dari tim Cecil Mono sedang melakukan beberapa kemajuan untuk mengaktifkannya
http://evain.net/blog/articles/2009/04/22/converting-delegates-to-expression-trees
sumber
Perubahan
Untuk
sumber