මට ලැම්බඩාස් Func
සහ Action
නියෝජිතයන් තේරෙනවා . නමුත් ප්රකාශන මට බාධා කරයි.
Expression<Func<T>>
සාමාන්ය පැරණි තත්වයට වඩා ඔබ භාවිතා කරන්නේ කුමන තත්වයන් යටතේද Func<T>
?
මට ලැම්බඩාස් Func
සහ Action
නියෝජිතයන් තේරෙනවා . නමුත් ප්රකාශන මට බාධා කරයි.
Expression<Func<T>>
සාමාන්ය පැරණි තත්වයට වඩා ඔබ භාවිතා කරන්නේ කුමන තත්වයන් යටතේද Func<T>
?
Answers:
ඔබට ලැම්බඩා ප්රකාශන ප්රකාශන ගස් ලෙස සැලකීමට අවශ්ය වූ විට ඒවා ක්රියාත්මක කිරීම වෙනුවට ඒවා දෙස බලන්න. උදාහරණයක් ලෙස, SQL වෙත LINQ මඟින් ප්රකාශනය ලබාගෙන එය සමාන SQL ප්රකාශයක් බවට පරිවර්තනය කර සේවාදායකයට ඉදිරිපත් කරයි (ලැම්බඩා ක්රියාත්මක කරනවාට වඩා).
සංකල්පමය, Expression<Func<T>>
ය සම්පූර්ණයෙන්ම වෙනස් සිට Func<T>
. Func<T>
එය හැඳින්වේ delegate
එච්චරමයි ගැනීමට ක්රමයක් අවධානය යොමුකළ අතර වන Expression<Func<T>>
යම් සතුටයි ගසක් දත්ත ව්යුහය සඳහා ලැම්ඩා ප්රකාශනය සඳහා. මෙම ගස් ව්යුහය විස්තර කරන්නේ ලැම්බඩා ප්රකාශනය සත්ය දේ කරනවාට වඩා කරන දෙයයි. එය මූලික වශයෙන් ප්රකාශනවල සංයුතිය, විචල්යයන්, ක්රම ඇමතුම්, ... (උදාහරණයක් ලෙස මෙම ලැම්බඩා වැනි නියත + සමහර පරාමිතීන් වැනි තොරතුරු දරයි). ඔබට මෙම විස්තරය සත්ය ක්රමයක් බවට පරිවර්තනය කිරීමට (සමඟ Expression.Compile
) හෝ වෙනත් දේවල් (LINQ සිට SQL උදාහරණය දක්වා) කළ හැකිය. ලැම්බඩාස් නිර්නාමික ක්රම සහ ප්රකාශන ගස් ලෙස සැලකීමේ ක්රියාව තනිකරම සම්පාදනය කරන කාලයකි.
Func<int> myFunc = () => 10; // similar to: int myAnonMethod() { return 10; }
කිසිවක් ලබා නොගෙන 10 ආපසු ලබා දෙන IL ක්රමයකට effectively ලදායී ලෙස සම්පාදනය කරනු ඇත.
Expression<Func<int>> myExpression = () => 10;
පරාමිතීන් නොලැබෙන සහ 10 අගය ලබා දෙන ප්රකාශනයක් විස්තර කරන දත්ත ව්යුහයක් බවට පරිවර්තනය වේ:
සම්පාදක වේලාවේදී ඔවුන් දෙදෙනාම එක හා සමානව පෙනුනද, සම්පාදකයා ජනනය කරන දෙය මුළුමනින්ම වෙනස් වේ.
Expression
එක්තරා නියෝජිතයෙකු පිළිබඳ මෙටා තොරතුරු අඩංගු වේ.
Expression<Func<...>>
සාධාරණ වෙනුවට භාවිතා කරන විට නියෝජිතයා නොපවතී Func<...>
.
(isAnExample) => { if(isAnExample) ok(); else expandAnswer(); }
එවැනි ප්රකාශනයක් ප්රකාශන ගසක් වන අතර, if -statement සඳහා ශාඛා නිර්මාණය වේ.
මම නොබොබ්ස් සඳහා පිළිතුරක් එක් කරන්නේ මෙම පිළිතුරු මගේ හිසට ඉහළින් පෙනෙන නිසා එය කෙතරම් සරලදැයි මට වැටහෙන තුරු ය. සමහර විට එය සංකීර්ණ බව ඔබේ අපේක්ෂාව වන අතර එමඟින් 'ඔබේ හිස වටා එතීමට' නොහැකි වේ.
LINQ-to-SQL සාමාන්යයෙන් භාවිතා කිරීමට උත්සාහ කරන ඇත්තෙන්ම කරදරකාරී 'දෝෂයකට' යන තෙක් මට වෙනස තේරුම් ගැනීමට අවශ්ය නොවීය:
public IEnumerable<T> Get(Func<T, bool> conditionLambda){
using(var db = new DbContext()){
return db.Set<T>.Where(conditionLambda);
}
}
මම විශාල දත්ත කට්ටලවල OutofMemoryException ලබා ගැනීමට පටන් ගන්නා තෙක් මෙය විශිෂ්ටයි. ලැම්බඩා තුළ බ්රේක්පොයින්ට් සැකසීම මගේ මේසයේ සෑම පේළියක්ම එකින් එක මගේ ලැම්බඩා තත්වයට ගැලපෙන බව සොයමින් සිටින බව මට වැටහුණි. මෙය මා කලක සිට කම්පනයට පත් කළේය, මන්ද යත්, මගේ දත්ත වගුව දැවැන්ත IEnumerable ලෙස සලකන්නේ LINQ-to-SQL කිරීම වෙනුවට එය කළ යුත්තේ ඇයි? එය මගේ LINQ-to-MongoDb සහකරු තුළද එකම දේ කරමින් සිටියේය.
දෝෂ නිවැරදි හැරී හුදෙක් Func<T, bool>
බවට Expression<Func<T, bool>>
, ඒ නිසා එය අවශ්ය ඇයි මම googled Expression
වෙනුවට Func
මෙතන අවසන්.
ප්රකාශනයක් හුදෙක් නියෝජිතයෙකු තමා පිළිබඳ දත්ත බවට හරවයි. එබැවින් a => a + 1
"වම් පැත්තේ එකක් ඇත int a
. දකුණු පැත්තේ ඔබ එයට 1 ක් එක් කරයි." ඒක තමයි. ඔබට දැන් ගෙදර යා හැකිය. එය පැහැදිලිවම ඊට වඩා ව්යුහාත්මක ය, නමුත් එය අත්යවශ්යයෙන්ම ප්රකාශන ගසක් ඇත්තෙන්ම - ඔබේ හිස වටා එතීමට කිසිවක් නැත.
එය වටහා ගැනීමෙන්, LINQ-to-SQL ට අවශ්ය වන්නේ ඇයිද යන්න පැහැදිලි වන Expression
අතර Func
එය ප්රමාණවත් නොවේ. Func
එය SQL / MongoDb / වෙනත් විමසුමකට පරිවර්තනය කරන්නේ කෙසේද යන්න පිළිබඳ විකාරරූපී බවක් දැකීමට එය තුළට ඇතුළු වීමට මාර්ගයක් ගෙන යන්නේ නැත. එය එකතු කිරීමක්ද, ගුණ කිරීමක්ද, අඩු කිරීමක්ද යන්න ඔබට නොපෙනේ. ඔබට කළ හැක්කේ එය ක්රියාත්මක කිරීමයි. Expression
, අනෙක් අතට, නියෝජිතයා ඇතුළත බැලීමට සහ එය කිරීමට අවශ්ය සියල්ල බැලීමට ඔබට ඉඩ සලසයි. SQL විමසුමක් මෙන් ඔබට අවශ්ය ඕනෑම දෙයකට නියෝජිතයා පරිවර්තනය කිරීමට මෙය ඔබට බලය ලබා දෙයි. Func
මගේ DbContext ලැම්බඩා ප්රකාශනයේ අන්තර්ගතය අන්ධ බැවින් එය ක්රියාත්මක නොවීය. මේ නිසා, එයට ලැම්බඩා ප්රකාශනය SQL බවට හැරවීමට නොහැකි විය; කෙසේ වෙතත්, එය ඊළඟ හොඳම දේ කළ අතර මගේ වගුවේ එක් එක් පේළිය හරහා එම කොන්දේසිය නැවත ප්රකාශ කළේය.
සංස්කරණය කරන්න: ජෝන් පීටර්ගේ ඉල්ලීම පරිදි මගේ අවසාන වාක්යය පැහැදිලි කිරීම:
IQueryable IEnumerable දිගු කරයි, එබැවින් IEnumerable හි ක්රම Where()
පිළිගන්නා අධික බර පැටවීම වැනි Expression
. ඔබ ඒ සඳහා සමත් වූ Expression
විට, ඔබ එහි ප්රති I ලයක් ලෙස IQueryable එකක් තබා ගනී, නමුත් ඔබ සමත් වූ විට Func
, ඔබ IEnumerable පදනම මතට වැටෙන අතර එහි ප්රති I ලයක් ලෙස ඔබට IEnumerable ලැබෙනු ඇත. වෙනත් වචන වලින් කිවහොත්, ඔබ නොදැනුවත්වම ඔබේ දත්ත කට්ටලය විමසීමට යමක් වෙනුවට නැවත සැකසිය යුතු ලැයිස්තුවක් බවට පත් කර ඇත. ඔබ අත්සන් දෙස බැලූ විට වෙනසක් දැකීම දුෂ්කර ය.
එක්ස්ප්රස්ෂන් එදිරිව ෆන්ක් තෝරා ගැනීමේදී අතිශයින්ම වැදගත් කරුණක් නම්, ලින්ක් ටු එන්ටිටීස් වැනි IQuery කළ හැකි සැපයුම්කරුවන්ට ඔබ ප්රකාශනයකින් සම්මත කරන දේ 'ජීර්ණය' කළ හැකි නමුත් ඔබ විනෝදය තුළ සම්මත කරන දේ නොසලකා හරිනු ඇත. මෙම විෂය පිළිබඳ මට බ්ලොග් සටහන් දෙකක් තිබේ:
ප්රකාශන එදිරිව Func with Entity Framework සහ LINQ සමඟ ආදරයෙන් බැඳීම - 7 වන කොටස: ප්රකාශන සහ කාර්යයන් (අවසාන කොටස)
ක්රයිස්ටොෆ් ක්වාලිනාගේ පොතෙන් ( රාමු සැලසුම් මාර්ගෝපදේශ: සම්මුතීන්, අයිඩියම් සහ නැවත භාවිතා කළ හැකි රටා .නෙට් පුස්තකාල ) වෙතින් ඒ පිළිබඳව වඩාත් දාර්ශනික පැහැදිලි කිරීමක් තිබේ ;
රූප නොවන අනුවාදය සඳහා සංස්කරණය කරන්න:
සිදුවිය යුතු සියල්ල යම් කේතයක් ධාවනය කිරීම නම් බොහෝ විට ඔබට Func හෝ Action අවශ්ය වනු ඇත. කේතය විශ්ලේෂණය කිරීමට, අනුක්රමික කිරීමට හෝ එය ක්රියාත්මක කිරීමට පෙර ප්රශස්තිකරණය කිරීමට අවශ්ය වූ විට ඔබට ප්රකාශනය අවශ්ය වේ. ප්රකාශනය යනු කේතය ගැන සිතීම සඳහා වන අතර, එය ක්රියාත්මක කිරීම සඳහා Func / Action වේ.
database.data.Where(i => i.Id > 0)
ලෙස ක්රියාත්මක කළ යුතුයි SELECT FROM [data] WHERE [id] > 0
. ඔබ පමණක් Func සමත් නම්, ඔබ blinders ඔබේ රියදුරු දමා ඇති අතර එය කරන්න පුළුවන් සියළු SELECT *
ඒ සියල්ල සිදු එක් එක් හා පෙරහන හරහා id> 0 ඔතන ඔබගේ සහ එය මතකය සියල්ල දත්ත පටවා වෙනවා වරක්, අවංකව Func
දී Expression
තේමා විශ්ලේෂණය කර Func
එය SQL / MongoDb / වෙනත් විමසුමක් බවට පත් කිරීමේ ධාවක.
Expression
නමුත් මම නිවාඩුවක් ගත කරන විට එය එසේ වනු ඇත Func/Action
;)
Func<T>
සහ අතර ඇති වෙනස්කම් ගැන සටහන් කිහිපයක් එක් කිරීමට මම කැමතියි Expression<Func<T>>
:
Func<T>
සාමාන්ය පැරණි පාසැල් බහුකාස්ට් ඩෙලිගේට් එකක් පමණි;Expression<Func<T>>
ප්රකාශන ගස ස්වරූපයෙන් ලැම්බඩා ප්රකාශනය නිරූපණය කිරීමකි;Func<T>
;ExpressionVisitor
;Func<T>
;Expression<Func<T>>
.කේත සාම්පල සමඟ විස්තර විස්තර කරන ලිපියක් ඇත:
LINQ: Func <T> එදිරිව ප්රකාශනය <Func <T>> .
එය ප්රයෝජනවත් වේ යැයි සිතමි.
ලින්ක් යනු කැනොනිකල් උදාහරණයයි (නිදසුනක් ලෙස, දත්ත සමුදායක් සමඟ කථා කිරීම), නමුත් ඇත්ත වශයෙන්ම, ඔබ ඇත්ත වශයෙන්ම එය කරනවාට වඩා කළ යුතු දේ ප්රකාශ කිරීමට වැඩි සැලකිල්ලක් දක්වයි. උදාහරණයක් ලෙස, මම මෙම ප්රවේශය ප්රොටොබුෆ්-නෙට් හි ආර්පීසී තොගයේ භාවිතා කරමි (කේත උත්පාදනය ආදිය වළක්වා ගැනීම සඳහා) - එබැවින් ඔබ මේ සමඟ ක්රමයක් අමතන්න:
string result = client.Invoke(svc => svc.SomeMethod(arg1, arg2, ...));
මෙය විසඳීම සඳහා ප්රකාශන ගස විසංයෝජනය කරයි SomeMethod
(සහ එක් එක් තර්කයේ වටිනාකම), ආර්පීසී ඇමතුම සිදු කරයි, ඕනෑම ref
/ out
ආර්ග් යාවත්කාලීන කරයි, සහ දුරස්ථ ඇමතුමෙන් ප්රති result ලය ලබා දෙයි. මෙය කළ හැක්කේ ප්රකාශන ගස හරහා පමණි. මම මෙය තවත් මෙහි ආවරණය කරමි .
තවත් උදාහරණයක් නම්, සාමාන්ය මෙහෙයුම්කරුවන්ගේ කේතය මඟින් සිදු කරන පරිදි, ලැම්බඩයකට සම්පාදනය කිරීමේ අරමුණින් ඔබ ප්රකාශන ගස් අතින් සාදන විට .
ඔබේ ශ්රිතය කේතයක් ලෙස නොව දත්ත ලෙස සැලකීමට අවශ්ය විට ඔබ ප්රකාශනයක් භාවිතා කරනු ඇත. ඔබට කේතය හැසිරවීමට අවශ්ය නම් (දත්ත ලෙස) ඔබට මෙය කළ හැකිය. බොහෝ විට ඔබට ප්රකාශන අවශ්යතාවයක් නොපෙනේ නම් ඔබට එය භාවිතා කිරීමට අවශ්ය නොවනු ඇත.
මූලික හේතුව වන්නේ ඔබට කේතය කෙලින්ම ක්රියාත්මක කිරීමට අවශ්ය නැති නමුත් එය පරීක්ෂා කිරීමට අවශ්ය වීමයි. මෙය හේතු ගණනාවක් නිසා විය හැකිය:
Expression
කල, ඕනෑම ප්රකාශනයකට අත්තනෝමතික නියෝජිතයෙකු / ක්රමවේද යොමු කිරීමක් ඉල්ලා සිටිය හැකි බැවින්, නියෝජිතයෙකු ලෙස අනුක්රමිකකරණය කළ නොහැකි ය. "පහසු" සාපේක්ෂයි.
කාර්ය සාධනය සඳහන් කරන කිසිදු පිළිතුරක් මා තවම දකින්නේ නැත. Func<>
ඒ තුළට යාම Where()
හෝ Count()
නරක ය. ඇත්ත නරකයි. ඔබ භාවිතා කරන්නේ නම් Func<>
එය ආමන්ත්රණය IEnumerable
LINQ දේවල් වෙනුවට IQueryable
, එයින් අදහස් මුළු වගු තුළ ඇද ගැනීමට බව පසුව පෙරීම. Expression<Func<>>
සැලකිය යුතු වේගයකින්, විශේෂයෙන් ඔබ වෙනත් සේවාදායකයක ජීවත්වන දත්ත සමුදායක් විමසන්නේ නම්.