আমি ল্যাম্বডাস Func
এবং Action
প্রতিনিধিদের বুঝতে পারি । কিন্তু এক্সপ্রেশন আমাকে স্টম্প।
কোন পরিস্থিতিতে আপনি Expression<Func<T>>
একটি সরল পুরানো চেয়ে একটি ব্যবহার করবেন Func<T>
?
আমি ল্যাম্বডাস Func
এবং Action
প্রতিনিধিদের বুঝতে পারি । কিন্তু এক্সপ্রেশন আমাকে স্টম্প।
কোন পরিস্থিতিতে আপনি Expression<Func<T>>
একটি সরল পুরানো চেয়ে একটি ব্যবহার করবেন Func<T>
?
উত্তর:
আপনি যখন ল্যাম্বডা এক্সপ্রেশনটিকে এক্সপ্রেশন ট্রি হিসাবে চিকিত্সা করতে চান এবং সেগুলি কার্যকর করার পরিবর্তে তাদের ভিতরে সন্ধান করেন। উদাহরণস্বরূপ, লিনকিউ থেকে এসকিউএল অভিব্যক্তিটি পেয়ে যায় এবং এটিকে সমতুল্য এসকিউএল স্টেটমেন্টে রূপান্তরিত করে এবং সার্ভারে জমা দেয় (ল্যাম্বডা কার্যকর করার পরিবর্তে)।
ধারণার দিক থেকে, Expression<Func<T>>
হয় সম্পূর্ণ ভিন্ন থেকে Func<T>
। Func<T>
এমনটি বোঝায় delegate
যা কোনও পদ্ধতির কাছে অনেকটা পয়েন্টার এবং ল্যাম্বডা এক্সপ্রেশনের জন্য একটি ট্রি ডেটার কাঠামোকেExpression<Func<T>>
বোঝায় । এই গাছের কাঠামোটি বর্ণনা করে যে ল্যাম্বডা এক্সপ্রেশনটি আসল জিনিসটি না করে কী করে। এটি মূলত এক্সপ্রেশন, ভেরিয়েবল, মেথড কল, ... র সমন্বয় সম্পর্কে ডেটা ধারণ করে ... (উদাহরণস্বরূপ এটি এই ল্যাম্বডা কিছু ধ্রুবক + কিছু পরামিতি হিসাবে তথ্য ধারণ করে)। আপনি এই বিবরণটিকে একটি আসল পদ্ধতিতে (এর সাথে ) রূপান্তর করতে ব্যবহার করতে পারেন বা এর সাথে অন্যান্য স্টাফগুলি (যেমন লাইনকিউকে এসকিউএল উদাহরণে) করতে পারেন। বেনামে পদ্ধতি এবং অভিব্যক্তি গাছ হিসাবে ল্যাম্বডাসের আচরণ করার বিষয়টি নিখুঁতভাবে একটি সঙ্কলন কালীন জিনিস।Expression.Compile
Func<int> myFunc = () => 10; // similar to: int myAnonMethod() { return 10; }
কার্যকরভাবে কোনও আইএল পদ্ধতিতে সংকলন করবে যা কিছুই না পেয়ে 10 প্রদান করে।
Expression<Func<int>> myExpression = () => 10;
কোনও ডেটা স্ট্রাকচারে রূপান্তরিত হবে যা এমন একটি অভিব্যক্তি বর্ণনা করে যা কোনও পরামিতি পায় না এবং মান 10 ফেরায়:
সংকলনের সময় উভয়ই একই দেখায়, সংকলকটি যা উত্পন্ন করে তা সম্পূর্ণ আলাদা ।
Expression
একটিতে একটি নির্দিষ্ট প্রতিনিধি সম্পর্কে মেটা-তথ্য থাকে।
Expression<Func<...>>
পরিবর্তে ব্যবহার করেন তখন প্রতিনিধিটির অস্তিত্ব থাকে না Func<...>
।
(isAnExample) => { if(isAnExample) ok(); else expandAnswer(); }
জাতীয় অভিব্যক্তি একটি এক্সপ্রেশনট্রি, ইফ -স্টেটমেন্টের জন্য শাখা তৈরি করা হয়েছে।
আমি উত্তরের জন্য নুবস যুক্ত করছি কারণ এই উত্তরগুলি আমার মাথার উপরে অনুভূত হয়েছিল, যতক্ষণ না বুঝেছি এটি কতটা সহজ। কখনও কখনও এটি আপনার প্রত্যাশা যে এটি জটিল যে আপনাকে 'আপনার মাথাটি এটি মুড়ে রাখতে "অক্ষম করে তোলে।
আমি সত্যিই বিরক্তিকর 'বাগ'-এ লিনকু-টু-এসকিউএলকে সাধারণভাবে ব্যবহার করার চেষ্টা না করা পর্যন্ত তফাতটি বোঝার দরকার নেই:
public IEnumerable<T> Get(Func<T, bool> conditionLambda){
using(var db = new DbContext()){
return db.Set<T>.Where(conditionLambda);
}
}
বড় ডেটাসেটগুলিতে আমি আউট অফ মেমরিএক্সেপশন পেতে শুরু না করা পর্যন্ত এটি দুর্দান্ত কাজ করেছে। ল্যাম্বদার ভিতরে ব্রেকপয়েন্টগুলি সেট করে দেওয়া আমার বুঝতে পেরেছিল যে এটি আমার টেবিলের প্রতিটি সারিতে একের পর এক আমার ল্যাম্বডা অবস্থার সাথে ম্যাচ খুঁজছে ite এটি আমাকে কিছুক্ষণের জন্য স্ট্যাম্পড করেছিল, কেন হ্যাক কেন এটি ডেটা টেবিলটিকে লিনকু-টু-এসকিউএল করার পরিবর্তে লিঙ্ক-টু-এসকিউএল করার পরিবর্তে দৈত্য আইয়নামারেবল হিসাবে বিবেচনা করছে? এটি আমার লিনিকিউ-থেকে-মঙ্গোডিবি সমমনা অংশে ঠিক একই জিনিসটি করছিল।
ফিক্সটি কেবল Func<T, bool>
রূপান্তরিত করার জন্য ছিল Expression<Func<T, bool>>
, সুতরাং আমি এখানে শেষ পর্যন্ত কেন এটির Expression
পরিবর্তে এর প্রয়োজন হবে তা আমি গুগল করেছিলাম Func
।
একটি অভিব্যক্তি কেবল নিজের প্রতিনিধিদের নিজের সম্পর্কে একটি ডেটাতে পরিণত করে। সুতরাং a => a + 1
এমন কিছু হয়ে যায় "বাম দিকে একটি রয়েছে int a
the ডানদিকে আপনি এতে 1 যুক্ত করেন।" এটাই. আপনি এখন বাড়িতে যেতে পারেন। এটি অবশ্যই তার থেকে আরও কাঠামোগত, তবে এটি মূলত সমস্ত অভিব্যক্তি গাছই হ'ল - আপনার মাথাটি প্রায় জড়িয়ে রাখার কিছুই নেই।
এটি বুঝতে পেরে, লাইনকিউ-এসকিউএল কেন দরকার Expression
এবং Func
এটি পর্যাপ্ত নয় তা স্পষ্ট হয়ে যায় । Func
এটি কীভাবে কোনও এসকিউএল / মঙ্গোডিবি / অন্যান্য ক্যোয়ারিতে অনুবাদ করা যায় তার মূর্খতা দেখতে, নিজের মধ্যে toোকার উপায় নিয়ে আসে না। আপনি এটি দেখতে পাচ্ছেন না এটি সংযোজন বা গুণফল বা বিয়োগফল করছে কিনা। আপনি যা করতে পারেন তা এটি চালানো। Expression
অন্যদিকে, আপনাকে প্রতিনিধিটির অভ্যন্তরে দেখতে এবং এটি করতে চায় এমন সমস্ত কিছু দেখতে দেয়। এটি আপনাকে এসকিউএল কোয়েরির মতো প্রতিনিধিটিকে যা খুশি তাই অনুবাদ করার ক্ষমতা দেয়। Func
কাজ করেনি কারণ আমার DbContext ল্যাম্বডা এক্সপ্রেশনটির বিষয়বস্তুতে অন্ধ ছিল। এর কারণে, এটি ল্যাম্বডা এক্সপ্রেশনটিকে এসকিউএলে রূপান্তর করতে পারে না; তবে এটি পরবর্তী সেরা কাজটি করেছিল এবং আমার টেবিলে প্রতিটি সারি জুড়ে শর্তসাপেক্ষ পুনরুক্তি করেছে।
সম্পাদনা: জন পিটারের অনুরোধে আমার শেষ বাক্যটি ব্যাখ্যা করে:
আইকিউয়েরেবল আইএনউম্যারেবলকে প্রসারিত করে, তাই আইনিউমারেবলের পদ্ধতিগুলি Where()
ওভারলোডগুলি গ্রহণ করে যা গ্রহণ করে Expression
। আপনি এটি পাস Expression
করার পরে, আপনি ফলস্বরূপ একটি আইকিউয়ারেবল রাখেন, কিন্তু আপনি যখন একটি পাস করেন Func
, তখন আপনি বেস বেসের উপর পিছিয়ে যাবেন এবং ফলস্বরূপ আপনি একটি আইনুমারেবল পাবেন। অন্য কথায়, লক্ষ্য না করেই আপনি আপনার ডেটাসেটটিকে ক্যুরিয়ার কোনও কিছুর বিপরীতে পুনরাবৃত্ত হওয়ার একটি তালিকায় পরিণত করেছেন। আপনি স্বাক্ষরগুলিতে হুডের নিচে ততক্ষণ তাকান না হওয়া পর্যন্ত একটি পার্থক্য লক্ষ্য করা শক্ত।
এক্সপ্রেশন বনাম ফানক বাছাইয়ের ক্ষেত্রে একটি অত্যন্ত গুরুত্বপূর্ণ বিবেচনাটি হ'ল লিনকিউ থেকে সত্তাগুলির মতো আইকোয়্যারেবল সরবরাহকারী আপনার এক্সপ্রেশনটিতে যা পাস করবে তা 'হজম' করতে পারে, তবে আপনি ফানকে যা পাস তা এড়িয়ে যাবেন। বিষয়টিতে আমার দুটি ব্লগ পোস্ট রয়েছে:
এক্সপ্রেশন বনাম সত্তা ফ্রেমওয়ার্ক Func আরো এবং LINQ প্রেমে পতনশীল - পার্ট 7: এক্সপ্রেশন এবং Funcs (শেষ অধ্যায়)
আমি এর ভিন্নতা নিয়ে কিছু নোট যোগ করতে চান Func<T>
এবং Expression<Func<T>>
:
Func<T>
এটি একটি সাধারণ পুরাতন স্কুল মাল্টিকাস্টডেলিগেট;Expression<Func<T>>
এক্সপ্রেশন ট্রি আকারে ল্যাম্বডা এক্সপ্রেশন একটি প্রতিনিধিত্ব;Func<T>
;ExpressionVisitor
;Func<T>
;Expression<Func<T>>
।কোডের নমুনাগুলির সাথে বিশদ বর্ণনা করে এমন একটি নিবন্ধ রয়েছে:
লিনক: ফানক <টি> বনাম এক্সপ্রেশন <ফানক <টি>> ।
আশা করি এটি সহায়ক হবে।
ক্রিজিস্তফ ক্লওয়িনার বই ( ফ্রেমওয়ার্ক ডিজাইনের গাইডলাইন: কনভেনশন, আইডিয়ামস এবং পুনরায় ব্যবহারযোগ্য। নেট গ্রন্থাগারসমূহের প্যাটার্নস ) থেকে এ সম্পর্কে আরও দার্শনিক ব্যাখ্যা রয়েছে ;
নন-চিত্র সংস্করণের জন্য সম্পাদনা করুন:
বেশিরভাগ সময় আপনি ফানক বা অ্যাকশন চাইলে যা হওয়ার দরকার তা যদি কিছু কোড চালানো হয়। কোডটি চালানোর আগে বিশ্লেষণ, সিরিয়ালাইজড বা অনুকূলিতকরণের প্রয়োজন হলে আপনার এক্সপ্রেশন দরকার । এক্সপ্রেশন কোড সম্পর্কে চিন্তাভাবনা করার জন্য, ফানক / অ্যাকশন এটি চালানোর জন্য।
database.data.Where(i => i.Id > 0)
হিসাবে মৃত্যুদন্ড কার্যকর করা প্রয়োজন SELECT FROM [data] WHERE [id] > 0
। আপনি শুধুমাত্র একটি Func মধ্যে পাস, তাহলে আপনি আপনার চালক উপর অন্ধ রেখেছি এবং সমস্ত এটা করতে পারেন হয় SELECT *
প্রতিটি এবং ফিল্টার মাধ্যমে এবং তারপর একবার এটি মেমরিতে যে সমস্ত ডেটা লোড করছে, বারবার আইডি> 0. আপনার মোড়ানো সঙ্গে সবকিছু Func
মধ্যে Expression
ক্ষমতা ড্রাইভারটি বিশ্লেষণ করতে Func
এবং এটিকে একটি এসকিউএল / মঙ্গোডিবি / অন্যান্য অনুসন্ধানে রূপান্তর করতে।
Expression
তবে যখন আমি ছুটিতে যাব তখনই এটি হবে Func/Action
;)
লিনকিউ হ'ল প্রামাণ্য উদাহরণ (উদাহরণস্বরূপ, একটি ডাটাবেসের সাথে কথা বলা), তবে সত্যিকার অর্থে যে কোনও সময় আপনি এটি করার পরিবর্তে কী করা উচিত তা প্রকাশ করার বিষয়ে বেশি চিন্তা করেন। উদাহরণস্বরূপ, আমি প্রোটোবুফ-নেট (কোড-জেনারেশন ইত্যাদি এড়ানোর জন্য) এর আরপিসি স্ট্যাকে এই পদ্ধতিটি ব্যবহার করি - সুতরাং আপনি একটি পদ্ধতিটি কল করে:
string result = client.Invoke(svc => svc.SomeMethod(arg1, arg2, ...));
এটি সমাধান করতে এক্সপ্রেশন ট্রিটিকে SomeMethod
(এবং প্রতিটি আর্গুমেন্টের মান) ডিকনস্ট্রাক্ট করে, আরপিসি কল সঞ্চালন করে, কোনও ref
/ out
আরগ আপডেট করে এবং রিমোট কল থেকে ফলাফলটি দেয়। এটি কেবল এক্সপ্রেশন ট্রি দ্বারা সম্ভব। আমি এখানে আরও কভার ।
অন্য উদাহরণটি হ'ল যখন আপনি জেনেরিক অপারেটর কোড দ্বারা সম্পন্ন ল্যাম্বডায় সংকলনের উদ্দেশ্যে ম্যানুয়ালি এক্সপ্রেশন ট্রি তৈরি করছেন ।
আপনি যখন নিজের ফাংশনটিকে কোড হিসাবে নয়, ডেটা হিসাবে বিবেচনা করতে চান তখন আপনি একটি অভিব্যক্তি ব্যবহার করবেন। আপনি কোডটি (ডেটা হিসাবে) ম্যানিপুলেট করতে চাইলে আপনি এটি করতে পারেন। বেশিরভাগ সময় যদি আপনি ভাবের প্রয়োজন না দেখেন তবে সম্ভবত আপনাকে এটি ব্যবহারের প্রয়োজন হবে না।
প্রাথমিক কারণ হ'ল আপনি যখন কোডটি সরাসরি চালাতে চান না, বরং এটি পরীক্ষা করতে চান। এটি যে কোনও কারণেই হতে পারে:
Expression
একটি প্রতিনিধি হিসাবে সিরিয়াল করা ঠিক যেমন অসম্ভব হতে পারে, যেহেতু যে কোনও অভিব্যক্তিতে একটি স্বেচ্ছাসেবীর প্রতিনিধি / পদ্ধতি রেফারেন্সের অনুরোধ থাকতে পারে। "সহজ" অবশ্যই আপেক্ষিক।
পারফরম্যান্সের উল্লেখ করে আমি এখনও কোনও উত্তর দেখতে পাচ্ছি না। Func<>
এর মধ্যে পাস করা Where()
বা Count()
খারাপ। বাস্তব খারাপ। আপনি যদি এটি ব্যবহার করেন Func<>
তবে এটি IEnumerable
পরিবর্তে লিনকিউ স্টাফকে কল করে IQueryable
, যার অর্থ পুরো টেবিলগুলি টানতে হবে এবং তারপরে ফিল্টার করা হবে। Expression<Func<>>
উল্লেখযোগ্যভাবে দ্রুততর, বিশেষত যদি আপনি এমন একটি ডাটাবেস অনুসন্ধান করছেন যা অন্য সার্ভারে বাস করে।