যে পদ্ধতিটি বর্তমান পদ্ধতি বলে তাকে কীভাবে খুঁজে পাব?


503

সি # তে লগ ইন করার সময়, আমি বর্তমান পদ্ধতির নামকরণ পদ্ধতিটির নাম কীভাবে শিখব? আমি সব সম্পর্কে জানি System.Reflection.MethodBase.GetCurrentMethod(), কিন্তু আমি স্ট্যাক ট্রেস এর নীচে এক ধাপ যেতে চাই। আমি স্ট্যাকের ট্রেসটি বিশ্লেষণের বিষয়টি বিবেচনা করেছি, তবে আমি আরও পরিষ্কারভাবে আরও পরিষ্কার উপায় খুঁজে পাওয়ার আশা করছি, Assembly.GetCallingAssembly()পদ্ধতিগুলির মতো তবে।


22
যদি আপনি .NET 4.5 বিটা + ব্যবহার করেন, আপনি কলার ইনফরমেশন এপিআই ব্যবহার করতে পারেন ।
রোহিত শর্মা

5
কলারের তথ্যও আরও দ্রুত
কবুতর

4
আমি একটি দ্রুত নির্মিত BenchmarkDotNet তিনটি প্রধান পদ্ধতি বেঞ্চমার্ক ( StackTrace, StackFrameএবং CallerMemberName) এবং পোস্ট একটি সারকথা যেমন ফলাফল অন্যদের এখানে দেখার জন্য: gist.github.com/wilson0x4d/7b30c3913e74adf4ad99b09163a57a1f
শন উইলসন

উত্তর:


512

এটা চেষ্টা কর:

using System.Diagnostics;
// Get call stack
StackTrace stackTrace = new StackTrace(); 
// Get calling method name
Console.WriteLine(stackTrace.GetFrame(1).GetMethod().Name);

এক রৈখিক:

(new System.Diagnostics.StackTrace()).GetFrame(1).GetMethod().Name

এটি প্রতিচ্ছবি [সি #] ব্যবহার করে কল কলিং পদ্ধতি থেকে এসেছে ।


12
আপনি সম্পূর্ণ স্ট্যাকের চেয়ে আপনার প্রয়োজনীয় ফ্রেমটিও তৈরি করতে পারেন:
জোয়েল কোহোর্ন

187
নতুন স্ট্যাকফ্রেম (1) .গেটমঠোদ ()। নাম;
জোয়েল কোহোর্ন 13

12
যদিও এটি পুরোপুরি নির্ভরযোগ্য নয়। দেখা যাক এটি কোনও মন্তব্যে কাজ করে কিনা! কনসোল অ্যাপ্লিকেশনটিতে নিম্নলিখিতটি চেষ্টা করুন এবং আপনি দেখতে পান যে সংকলক অপেশেশনগুলি এটি ভেঙে গেছে। স্ট্যাটিক অকার্যকর মূল (স্ট্রিং [] আরগস) {কলআইট (); } ব্যক্তিগত স্ট্যাটিক অকার্যকর কলআইটি () al ফাইনাল (); } স্ট্যাটিক অকার্যকর ফাইনাল () {স্ট্যাকট্রেস ট্রেস = নতুন স্ট্যাকট্রেস (); স্ট্যাকফ্রেম ফ্রেম = ট্রেস.গেটফ্রেম (1); কনসোল.ওরাইটলাইন ("{0}। {1} ()", ফ্রেম.গেটমথোড ()। ডিক্লারিংটাইপ.ফুলনাম, ফ্রেম.গেটমথোড () নাম); }
ব্ল্যাকওয়াস্প

10
কম্পাইলার ইনলাইনস বা টেল-কল পদ্ধতিটিকে সর্বোত্তম করে তোলে যখন এটি কাজ করে না, সেক্ষেত্রে স্ট্যাকটি ধসে পড়ে এবং আপনি প্রত্যাশার চেয়ে অন্যান্য মান খুঁজে পাবেন। আপনি যখন এটি কেবল ডিবাগ বিল্ডগুলিতে ব্যবহার করেন, এটি যদিও ভাল কাজ করবে।
আবেল

46
আমি অতীতে যা করেছি তা হ'ল পদ্ধতিটির আগে সংযোজনকারী বৈশিষ্ট্য [মেথডিম্পলঅ্যাট্রিবিউট (মেথডিম্পলঅপশনস.নোইনলাইনিং)] যুক্ত করুন যা স্ট্যাকের সন্ধানগুলি সন্ধান করবে। এটি নিশ্চিত করে যে সংকলকটি পদ্ধতিটিকে ইন-লাইন করবে না এবং স্ট্যাক ট্রেসটিতে সত্যিকারের কলিং পদ্ধতি থাকবে (বেশিরভাগ ক্ষেত্রে আমি পুচ্ছ-পুনরাবৃত্তি সম্পর্কে উদ্বিগ্ন নই))
জর্ডান রিগার

363

সি # 5 এ আপনি কলার তথ্য ব্যবহার করে সেই তথ্যটি পেতে পারেন :

//using System.Runtime.CompilerServices;
public void SendError(string Message, [CallerMemberName] string callerName = "") 
{ 
    Console.WriteLine(callerName + "called me."); 
} 

এছাড়াও আপনি পেতে পারেন [CallerFilePath]এবং [CallerLineNumber]


13
হ্যালো, এটি সি # 5 নয়, এটি 4.5 এ পাওয়া যায়।
06

35
@ আফ্রাক্ট ল্যাঙ্গুয়েজ (সি #) সংস্করণগুলি .NET সংস্করণ হিসাবে এক নয়।
kwesolowski

6
@ স্টার্টটি দেখে মনে হচ্ছে [CallerTypeName]বর্তমান থেকে নেমে গেছে N নেট ফ্রেমওয়ার্ক (4.6.2) এবং কোর সিএলআর
Ph0en1x

4
@ পিএইচএএনএক্স @ কাঠামোতে এটি কখনই ছিল না, আমার বক্তব্যটি হ'ল এটি যদি সহজ হয় তবে উদাহরণস্বরূপ একজন কলার মেম্বারের নাম কীভাবে পাবেন
স্টুয়ার্টড

3
@ ডিগোডেবার্ট - আমি পড়েছি যে এটি ব্যবহারের কোনও প্রতিচ্ছবি হ্রাস পাচ্ছে না কারণ এটি সংকলনের সময়ে সমস্ত কাজ করে। আমি বিশ্বাস করি যে পদ্ধতিটি কী নামে এটি সঠিক।
চেম্বারলাইন

109

আপনি কলার তথ্য এবং alচ্ছিক পরামিতি ব্যবহার করতে পারেন:

public static string WhoseThere([CallerMemberName] string memberName = "")
{
       return memberName;
}

এই পরীক্ষাটি এর উদাহরণ দেয়:

[Test]
public void Should_get_name_of_calling_method()
{
    var methodName = CachingHelpers.WhoseThere();
    Assert.That(methodName, Is.EqualTo("Should_get_name_of_calling_method"));
}

যদিও স্ট্যাকট্রেস উপরে বেশ দ্রুত কাজ করে এবং বেশিরভাগ ক্ষেত্রে কলারের তথ্যটি এখনও খুব দ্রুততর হয় a 1000 পুনরাবৃত্তির নমুনায়, আমি এটিকে 40 গুণ বেশি দ্রুত গতিতে রেখেছি।


শুধুমাত্র নেট নেট থেকে পাওয়া যায় 4.5 যদিও
ডেরাপে

1
মনে রাখবেন যে এটি কাজ করে না, যদি কলার একটি কৃষি পাস করে: CachingHelpers.WhoseThere("wrong name!");==> "wrong name!"কারণ এটি CallerMemberNameকেবলমাত্র ডিফল্ট মানকে প্রতিস্থাপন করে।
অলিভিয়ার জ্যাকট-ডেসকোম্বেস 16

@ অলিভিয়ার জাকোট-ডেসকোম্বস সেভাবে কাজ করে না আপনি যদি কোনও পরামিতি পাস করেন তবে কোনও এক্সটেনশন পদ্ধতি কাজ করবে না। আপনি অন্য স্ট্রিং প্যারামিটার ব্যবহার করতে পারেন যদিও। এছাড়াও মনে রাখবেন যে আপনি যদি আপনার মতো কোনও যুক্তি পাস করার চেষ্টা করেন তবে পুনরায় ভাগ আপনাকে একটি সতর্কতা দেয়।
কবুতর

1
@ প্রিয়ত আপনি thisকোনও এক্সটেনশন পদ্ধতিতে কোনও স্পষ্ট প্যারামিটার পাস করতে পারেন । এছাড়াও, অলিভিয়ার সঠিক, আপনি একটি মান পাস করতে পারেন এবং [CallerMemberName]প্রয়োগ করা হয় না; পরিবর্তে এটি একটি ওভাররাইড হিসাবে কাজ করে যেখানে ডিফল্ট মানটি সাধারণত ব্যবহৃত হত। প্রকৃতপক্ষে, আমরা যদি আইএলটির দিকে নজর রাখি তবে আমরা দেখতে পাই যে ফলস্বরূপ পদ্ধতিটি সাধারণত কোনও [opt]আর্গের জন্য নির্গত হয় তার চেয়ে আলাদা নয় , এর ইনজেকশনটি CallerMemberNameতাই সিএলআর আচরণ। সবশেষে, ডক্স: "কলার ইনফর্মেশন অ্যাট্রিবিউটগুলি [...] তর্কটি বাদ দিলে পাস হওয়া ডিফল্ট মানকে প্রভাবিত করে "
শন উইলসন

2
এটি নিখুঁত এবং asyncবন্ধুত্বপূর্ণ যা StackFrameআপনাকে সাহায্য করবে না। ল্যাম্বডা থেকে ডেকে আনাও প্রভাবিত করে না।
হারুন

65

গতি তুলনা গুরুত্বপূর্ণ অংশ হিসাবে 2 পদ্ধতির একটি দ্রুত পুনরুদ্ধার।

http://geekswithblogs.net/BlackRabbitCoder/archive/2013/07/25/c.net-little-wonders-getting-caller-information.aspx

সংকলন-সময়ে কলার নির্ধারণ করা

static void Log(object message, 
[CallerMemberName] string memberName = "",
[CallerFilePath] string fileName = "",
[CallerLineNumber] int lineNumber = 0)
{
    // we'll just use a simple Console write for now    
    Console.WriteLine("{0}({1}):{2} - {3}", fileName, lineNumber, memberName, message);
}

স্ট্যাকটি ব্যবহার করে কলার নির্ধারণ করা

static void Log(object message)
{
    // frame 1, true for source info
    StackFrame frame = new StackFrame(1, true);
    var method = frame.GetMethod();
    var fileName = frame.GetFileName();
    var lineNumber = frame.GetFileLineNumber();

    // we'll just use a simple Console write for now    
    Console.WriteLine("{0}({1}):{2} - {3}", fileName, lineNumber, method.Name, message);
}

2 পদ্ধতির তুলনা

Time for 1,000,000 iterations with Attributes: 196 ms
Time for 1,000,000 iterations with StackTrace: 5096 ms

সুতরাং আপনি দেখুন, গুণাবলী ব্যবহার করে অনেক অনেক দ্রুত! বাস্তবে প্রায় 25x দ্রুত।


এই পদ্ধতিটি উচ্চতর পদ্ধতির বলে মনে হচ্ছে। নেমস্পেসগুলি উপলব্ধ না হওয়ার কারণে এটি জামারিনেও কাজ করে।
লিন্ডন হুগেই

63

পুরো স্ট্যাকের চেয়ে আমাদের কেবল প্রয়োজন ফ্রেমটি ইনস্ট্যান্ট করে আমরা মিঃ আসাদের কোড (বর্তমান স্বীকৃত উত্তর) এর কিছুটা উন্নতি করতে পারি:

new StackFrame(1).GetMethod().Name;

এটি কিছুটা ভাল পারফর্ম করতে পারে, যদিও সমস্ত সম্ভাবনার মধ্যে এখনও সেই একক ফ্রেম তৈরি করতে পুরো স্ট্যাকটি ব্যবহার করতে হবে। এছাড়াও, এর এখনও অ্যালেক্স লাইম্যান নির্দেশিত একই সতর্কতা রয়েছে (অপ্টিমাইজার / নেটিভ কোড ফলাফলগুলিকে দূষিত করতে পারে)। অবশেষে, আপনি যে নিশ্চিত হন new StackFrame(1)বা .GetFrame(1)ফিরে আসবেন না তা নিশ্চিত হতে চেক করতে চাইতে পারেন null, সম্ভাবনাটি যতটা সম্ভবত মনে হতে পারে।

এই সম্পর্কিত প্রশ্নটি দেখুন: আপনি বর্তমানে সম্পাদনকারী পদ্ধতির নাম খুঁজতে প্রতিফলন ব্যবহার করতে পারেন?


1
এটি কি new ClassName(…)শূন্যের সমান?
নাম

1
খুব সুন্দর এটি হ'ল নেট। স্ট্যান্ডার্ড 2.0 তেও কাজ করে।
srsedate

60

সাধারণভাবে, আপনি System.Diagnostics.StackTraceক্লাসটি একটি পেতে ব্যবহার করতে পারেন System.Diagnostics.StackFrame, এবং তারপরে GetMethod()কোনও System.Reflection.MethodBaseজিনিস পেতে পদ্ধতিটি ব্যবহার করতে পারেন । তবে এই পদ্ধতির কিছু সতর্কতা রয়েছে :

  1. এটি রানটাইম স্ট্যাকের প্রতিনিধিত্ব করে - অপ্টিমাইজেশানগুলি কোনও পদ্ধতিকে ইনলাইন করতে পারে এবং আপনি স্ট্যাক ট্রেসে সেই পদ্ধতিটি দেখতে পাবেন না
  2. এটি কোনও নেটিভ ফ্রেম প্রদর্শন করবে না , সুতরাং আপনার পদ্ধতিটি একটি স্থানীয় পদ্ধতি দ্বারা কল করার একটি সুযোগ থাকলেও এটি কার্যকর হবে না এবং বাস্তবে এটি করার কোনও উপলভ্য উপায় নেই।

( দ্রষ্টব্য: আমি কেবল ফিরস আসাদের দেওয়া উত্তরটি প্রসারিত করছি ))


2
অপ্টিমাইজেশন বন্ধ করে দিয়ে ডিবাগ মোডে, আপনি কী স্ট্যাক ট্রেসের মধ্যে পদ্ধতিটি দেখতে সক্ষম হবেন?
আক্রমণ হাবো

1
@ অ্যাটাকিংহোব: হ্যাঁ - যদি না পদ্ধতিটি ইনলাইন করা হয় (অপ্টিমাইজেশন করা থাকে) বা কোনও নেটিভ ফ্রেম না থাকে তবে আপনি এটি দেখতে পাবেন।
অ্যালেক্স লাইমান

38

নেট 4.5 হিসাবে আপনি কলার তথ্য বৈশিষ্ট্যগুলি ব্যবহার করতে পারেন :

  • CallerFilePath - উত্স ফাইল যা ফাংশন বলে;
  • CallerLineNumber - কোডের লাইন যা ফাংশন বলে;
  • CallerMemberName - সদস্য যে ফাংশন বলা হয়।

    public void WriteLine(
        [CallerFilePath] string callerFilePath = "", 
        [CallerLineNumber] long callerLineNumber = 0,
        [CallerMemberName] string callerMember= "")
    {
        Debug.WriteLine(
            "Caller File Path: {0}, Caller Line Number: {1}, Caller Member: {2}", 
            callerFilePath,
            callerLineNumber,
            callerMember);
    }

 

এই সুবিধাটি "। নেট কোর" এবং "। নেট স্ট্যান্ডার্ড" এও উপস্থিত।

তথ্যসূত্র

  1. মাইক্রোসফ্ট - কলার তথ্য (সি #)
  2. মাইক্রোসফ্ট - CallerFilePathAttributeক্লাস
  3. মাইক্রোসফ্ট - CallerLineNumberAttributeক্লাস
  4. মাইক্রোসফ্ট - CallerMemberNameAttributeক্লাস

15

নোট করুন যে এটি করা অপটিমাইজেশনের কারণে রিলিজ কোডে অবিশ্বাস্য হবে। অতিরিক্তভাবে, স্যান্ডবক্স মোডে অ্যাপ্লিকেশনটি চালানো (নেটওয়ার্ক শেয়ার) আপনাকে স্ট্যাক ফ্রেমটি মোটেও দখল করতে দেয় না।

পোস্টশার্পের মতো, দৃষ্টিভঙ্গিযুক্ত প্রোগ্রামিং (এওপি) বিবেচনা করুন যা আপনার কোড থেকে ডাকার পরিবর্তে আপনার কোডটি সংশোধন করে এবং এটি সর্বদা কোথায় তা জানে।


আপনি একেবারে সঠিক যে এটি প্রকাশে কার্যকর হবে না। আমি নিশ্চিত নই যে আমি কোড ইঞ্জেকশনটির ধারণাটি পছন্দ করি তবে আমি অনুমান করি যে কোনও অর্থে একটি ডিবাগ স্টেটমেন্টের কোড সংশোধন প্রয়োজন, তবে এখনও। কেন শুধু সি ম্যাক্রোগুলিতে ফিরে যাব না? এটি অন্তত এমন কিছু যা আপনি দেখতে পাচ্ছেন
ebyrob

9

অবশ্যই এটি একটি দেরিতে উত্তর, তবে আপনি। নেট 4.5 বা আরও বেশি ব্যবহার করতে পারেন তবে আমার কাছে আরও ভাল বিকল্প রয়েছে:

internal static void WriteInformation<T>(string text, [CallerMemberName]string method = "")
{
    Console.WriteLine(DateTime.Now.ToString() + " => " + typeof(T).FullName + "." + method + ": " + text);
}

এটি বর্তমান নাম এবং সময় মুদ্রণ করবে, তারপরে "নেমস্পেস.ক্লাসনাম.মথোডনাম" এবং ": পাঠ্য" দিয়ে শেষ হবে।
নমুনা আউটপুট:

6/17/2016 12:41:49 PM => WpfApplication.MainWindow..ctor: MainWindow initialized

নমুনা ব্যবহার:

Logger.WriteInformation<MainWindow>("MainWindow initialized");

8
/// <summary>
/// Returns the call that occurred just before the "GetCallingMethod".
/// </summary>
public static string GetCallingMethod()
{
   return GetCallingMethod("GetCallingMethod");
}

/// <summary>
/// Returns the call that occurred just before the the method specified.
/// </summary>
/// <param name="MethodAfter">The named method to see what happened just before it was called. (case sensitive)</param>
/// <returns>The method name.</returns>
public static string GetCallingMethod(string MethodAfter)
{
   string str = "";
   try
   {
      StackTrace st = new StackTrace();
      StackFrame[] frames = st.GetFrames();
      for (int i = 0; i < st.FrameCount - 1; i++)
      {
         if (frames[i].GetMethod().Name.Equals(MethodAfter))
         {
            if (!frames[i + 1].GetMethod().Name.Equals(MethodAfter)) // ignores overloaded methods.
            {
               str = frames[i + 1].GetMethod().ReflectedType.FullName + "." + frames[i + 1].GetMethod().Name;
               break;
            }
         }
      }
   }
   catch (Exception) { ; }
   return str;
}

ওহো, আমার "মেথোডএফটার" পরমকে আরও ভালভাবে ব্যাখ্যা করা উচিত ছিল। সুতরাং আপনি যদি এই পদ্ধতিটিকে "লগ" টাইপ ফাংশনে কল করছেন তবে আপনি "লগ" ফাংশনের ঠিক পরে এই পদ্ধতিটি পেতে চাইবেন। সুতরাং আপনি getCallingMethod ("লগ") কল করবেন। -চিয়ার্স
ফ্ল্যান্ডার্স

6

আপনি এই জাতীয় কিছু খুঁজছেন হতে পারে:

StackFrame frame = new StackFrame(1);
frame.GetMethod().Name; //Gets the current method name

MethodBase method = frame.GetMethod();
method.DeclaringType.Name //Gets the current class name

4
private static MethodBase GetCallingMethod()
{
  return new StackFrame(2, false).GetMethod();
}

private static Type GetCallingType()
{
  return new StackFrame(2, false).GetMethod().DeclaringType;
}

চমত্কার ক্লাসটি এখানে: http://www.csharp411.com/c-get-calling-method/


স্ট্যাকফ্রেম নির্ভরযোগ্য নয়। "2 ফ্রেম" উপরে উঠলে খুব সহজেই পদ্ধতি কলগুলি ফিরে যেতে পারে।
ব্যবহারকারী 2864740

2

আমি ব্যবহার করেছি আরেকটি পদ্ধতি হল প্রশ্নে পদ্ধতিতে একটি প্যারামিটার যুক্ত করা। উদাহরণস্বরূপ, পরিবর্তে void Foo(), ব্যবহার করুন void Foo(string context)। তারপরে কিছু অনন্য স্ট্রিংয়ে পাস করুন যা কলিং প্রসঙ্গে নির্দেশ করে।

আপনার যদি বিকাশের জন্য কেবল কলার / প্রসঙ্গের প্রয়োজন হয় তবে আপনি paramশিপিংয়ের আগে সরাতে পারেন ।


2

পদ্ধতির নাম এবং শ্রেণীর নাম পাওয়ার জন্য এটি ব্যবহার করে দেখুন:

    public static void Call()
    {
        StackTrace stackTrace = new StackTrace();

        var methodName = stackTrace.GetFrame(1).GetMethod();
        var className = methodName.DeclaringType.Name.ToString();

        Console.WriteLine(methodName.Name + "*****" + className );
    }

1
StackFrame caller = (new System.Diagnostics.StackTrace()).GetFrame(1);
string methodName = caller.GetMethod().Name;

যথেষ্ট হবে, আমি মনে করি।


1

.NETলগিং পদ্ধতির নামটি একবার দেখুন । এটি প্রোডাকশন কোডে ব্যবহার করার বিষয়ে সতর্ক থাকুন। স্ট্যাকফ্রেম নির্ভরযোগ্য নাও হতে পারে ...


5
সামগ্রীর সংক্ষিপ্ত বিবরণটি দুর্দান্ত হবে।
পিটার মর্টেনসেন

1

কলারের সন্ধানের জন্য আমরা ল্যাম্বডা ব্যবহার করতে পারি।

ধরুন আপনার দ্বারা নির্ধারিত একটি পদ্ধতি রয়েছে:

public void MethodA()
    {
        /*
         * Method code here
         */
    }

এবং আপনি এটি আহ্বানকারী খুঁজে পেতে চান।

। পদ্ধতিটির স্বাক্ষরটি পরিবর্তন করুন যাতে আমাদের কাছে টাইপ অ্যাকশনের একটি প্যারামিটার থাকে (ফানক এছাড়াও কাজ করবে):

public void MethodA(Action helperAction)
        {
            /*
             * Method code here
             */
        }

। ল্যাম্বদা নামগুলি এলোমেলোভাবে তৈরি করা হয় না। বিধিটি মনে হচ্ছে:> <কলারমাঠোদনেম> __X যেখানে কলারমেথডনামটি পূর্ববর্তী ফাংশন দ্বারা প্রতিস্থাপন করা হয়েছিল এবং এক্স একটি সূচক।

private MethodInfo GetCallingMethodInfo(string funcName)
    {
        return GetType().GetMethod(
              funcName.Substring(1,
                                funcName.IndexOf("&gt;", 1, StringComparison.Ordinal) - 1)
              );
    }

। আমরা যখন মেথোডাকে কল করি তখন কলকারী পদ্ধতিতে অ্যাকশন / ফানক প্যারামিটার তৈরি করা উচিত। উদাহরণ:

MethodA(() => {});

4 । মেথডোর অভ্যন্তরে আমরা এখন উপরের সংজ্ঞায়িত সহায়ক ফাংশনটি কল করতে পারি এবং কলার পদ্ধতির মেথডইনফোটি জানতে পারি।

উদাহরণ:

MethodInfo callingMethodInfo = GetCallingMethodInfo(serverCall.Method.Name);

0

অতিরিক্ত তথ্য ফিরস আসাদ উত্তর।

আমি new StackFrame(1).GetMethod().Name;নির্ভর করে ইনজেকশন সহ। নেট কোর 2.1 ব্যবহার করেছি এবং আমি 'স্টার্ট' হিসাবে কল করার পদ্ধতিটি পাচ্ছি।

আমি চেষ্টা করেছি [System.Runtime.CompilerServices.CallerMemberName] string callerName = "" এবং এটি আমাকে সঠিক কলিং পদ্ধতি দেয়


-1
var callingMethod = new StackFrame(1, true).GetMethod();
string source = callingMethod.ReflectedType.FullName + ": " + callingMethod.Name;

1
আমি ডাউনওয়েট করি নি, তবে লক্ষ্য রাখতে চেয়েছিলাম যে কেন আপনি খুব অনুরূপ তথ্য পোস্ট করেছেন (কয়েক বছর পরে) আপনাকে ব্যাখ্যা করার জন্য কিছু পাঠ্য যুক্ত করা প্রশ্নের প্রশ্নের মান বাড়িয়ে তুলতে পারে এবং আরও নিম্নমানকে এড়াতে পারে।
শন উইলসন
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.