c# - টুস্ট্রিং ওভাররাইডের মূল্যায়ন বন্ধ করার জন্য ভিজ্যুয়াল স্টুডিও ডিবাগারটি কী করে?



debugging visual-studio-2015 (1)

হালনাগাদ:

এই বাগটি ভিজ্যুয়াল স্টুডিও 2015 আপডেট 2 এ স্থির করা হয়েছে আমাকে আপডেট 2 বা তার পরে আপডেট ব্যবহার করে স্ট্রাক্ট মানগুলিতে টোস্ট্রিংয়ের মূল্যায়নে সমস্যা হয় কিনা তা আমাকে জানতে দিন।

আসল উত্তর:

আপনি ভিজ্যুয়াল স্টুডিও 2015 দিয়ে একটি পরিচিত বাগ / ডিজাইন সীমাবদ্ধতার মধ্যে চলেছেন এবং স্ট্রাক্ট প্রকারভেদে টসস্ট্রিংকে কল করছেন। System.DateTimeSpan সাথে কাজ করার সময় এটিও লক্ষ্য করা যায়। System.DateTimeSpan.ToString() ভিজ্যুয়াল স্টুডিও 2013 এর সাথে মূল্যায়ন উইন্ডোতে কাজ করে তবে 2015 সালে সর্বদা কাজ করে না।

আপনি যদি নিম্ন স্তরের বিশদগুলিতে আগ্রহী হন তবে এখানে যা চলছে তা এখানে:

ToString মূল্যায়ন করতে, ডিবাগার যা "ফাংশন মূল্যায়ন" হিসাবে পরিচিত তা করে। ব্যাপকভাবে সরল শর্তে, ডিবাগার বর্তমান থ্রেড ব্যতীত সমস্ত থ্রেড স্থগিত করে, বর্তমান থ্রেডের প্রসঙ্গটি ToString ফাংশনে ToString করে, একটি গোপন গার্ড ToString সেট করে, তারপরে প্রক্রিয়াটি চালিয়ে যাওয়ার অনুমতি দেয়। গার্ড ব্রেকপয়েন্টে আঘাত করা হলে, ডিবাগারটি প্রক্রিয়াটিকে তার আগের অবস্থায় পুনরুদ্ধার করে এবং ফাংশনের রিটার্ন মানটি উইন্ডোটি জনপ্রিয় করতে ব্যবহৃত হয়।

ল্যাম্বদা এক্সপ্রেশন সমর্থন করতে, আমাদের ভিজ্যুয়াল স্টুডিও 2015-এ সিএলআর এক্সপ্রেশন মূল্যায়ন সম্পূর্ণরূপে আবার লিখতে হয়েছিল। একটি উচ্চ স্তরে, বাস্তবায়নটি হ'ল:

  1. রোজলিন বিভিন্ন পরিদর্শন উইন্ডোতে মানগুলি প্রদর্শনের জন্য এক্সপ্রেশন / স্থানীয় ভেরিয়েবলের জন্য এমএসআইএল কোড উত্পন্ন করে।
  2. ডিবাগার ফলাফল পেতে আইএলকে ব্যাখ্যা করে।
  3. যদি কোনও "কল" নির্দেশাবলী থাকে তবে ডিবাগার উপরে বর্ণিত হিসাবে কোনও ফাংশন মূল্যায়ন কার্যকর করে।
  4. ডিবাগার / রোসলিন এই ফলাফলটি নেয় এবং ব্যবহারকারীর দেখানো গাছের মতো দৃশ্যে রূপ দেয়।

আইএল কার্যকর করার কারণে, ডিবাগার সর্বদা "বাস্তব" এবং "জাল" মানের একটি জটিল মিশ্রণ নিয়ে কাজ করে। ডিবাগ হওয়ার প্রক্রিয়াটিতে আসল মানগুলি আসলে বিদ্যমান। জাল মানগুলি কেবল ডিবাগার প্রক্রিয়াতেই বিদ্যমান। যথাযথ স্ট্রাক্ট শব্দার্থক প্রয়োগ করতে, ডিবাগারকে আইএল স্ট্যাকের স্ট্রাক্ট মানটি চাপানোর সময় সর্বদা মানটির একটি অনুলিপি তৈরি করতে হবে। অনুলিপি করা মানটি আর "আসল" মান হয় না এবং এখন কেবল ডিবাগার প্রক্রিয়াতেই বিদ্যমান। এর অর্থ যদি পরবর্তীতে আমাদের যদি ToString ফাংশন মূল্যায়ন করতে হয় তবে আমরা প্রক্রিয়াতে মানটির অস্তিত্ব না ToString আমরা তা করতে পারি না। মানটি চেষ্টা করে ToString জন্য আমাদের ToString পদ্ধতির ToString অনুকরণ করতে হবে। যদিও আমরা কিছু জিনিস অনুকরণ করতে পারি তবে অনেকগুলি সীমাবদ্ধতা রয়েছে। উদাহরণস্বরূপ, আমরা নেটিভ কোড অনুকরণ করতে পারি না এবং আমরা "বাস্তব" প্রতিনিধি মানগুলিতে কলগুলি বা প্রতিবিম্ব মানগুলিতে কল কার্যকর করতে পারি না।

এই সমস্ত বিষয় মাথায় রেখে, এখানে আপনি বিভিন্ন আচরণের কারণ দেখছেন:

  1. ডিবাগার NodaTime.Instant.ToString মূল্যায়ন করছে না NodaTime.Instant.ToString -> এটি কারণ এটি স্ট্রাক্ট ধরণের এবং উপরে বর্ণিত হিসাবে টুস্ট্রিংয়ের প্রয়োগটি ডিবাগার দ্বারা অনুকরণ করা যায় না।
  2. Thread.Sleep ToString মাধ্যমে ডাকা হলে শূন্য সময় Thread.Sleep বলে মনে হয় -> এটি কারণ এমুলেটরটি ToString । থ্রেড.স্লিপ একটি দেশীয় পদ্ধতি, তবে এমুলেটরটি এটি সম্পর্কে সচেতন এবং কেবল কলটিকে উপেক্ষা করে। আমরা চেষ্টা করে ব্যবহারকারীর কাছে দেখানোর জন্য একটি মান পেতে পারি। এক বিলম্ব এই ক্ষেত্রে সহায়ক হবে না।
  3. DisplayAttibute("ToString()") কাজ করে। -> বিভ্রান্তিকর। ToString এবং ToString অন্তর্নিহিত কলিংয়ের মধ্যে একমাত্র পার্থক্য ToString অন্তর্নিহিত ToString মূল্যায়নের যে কোনও সময়-আউট পরবর্তী ডিবাগ সেশন অবধি এই ধরণের জন্য সমস্ত ToString মূল্যায়ন অক্ষম করবে। আপনি সেই আচরণটি পর্যবেক্ষণ করছেন।

ডিজাইনের সমস্যা / বাগের ক্ষেত্রে, আমরা ভিজ্যুয়াল স্টুডিওর ভবিষ্যতে প্রকাশে এই বিষয়টিকেই সম্বোধন করার পরিকল্পনা করছি।

আশা করি বিষয়গুলি পরিষ্কার হয়ে যায়। আপনার আরও প্রশ্ন থাকলে আমাকে জানান। :-)

পরিবেশ: ভিজ্যুয়াল স্টুডিও 2015 আরটিএম। (আমি পুরানো সংস্করণ চেষ্টা করিনি।)

সম্প্রতি, আমি আমার নোডা টাইম কোডটি কিছু ডিবাগ করেছি এবং আমি লক্ষ্য করেছি যে যখন আমি NodaTime.Instant টাইপ একটি স্থানীয় ভেরিয়েবল পেয়েছি। NodaTime.Instant (নোদা সময়ের কেন্দ্রীয় NodaTime.Instant মধ্যে একটি), "স্থানীয়" এবং "দেখুন" উইন্ডোজগুলি এর ToString() ওভাররাইডকে কল করতে উপস্থিত হবে না। আমি যদি ওয়াচ উইন্ডোতে স্পষ্টভাবে ToString() কল করি তবে আমি উপযুক্ত উপস্থাপনাটি দেখতে পাচ্ছি, তবে অন্যথায় আমি কেবল দেখতে পাচ্ছি:

variableName       {NodaTime.Instant}

যা খুব কার্যকর নয়।

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

আমি স্থানীয়ভাবে এটি একটি সামান্য ডেমো অ্যাপ্লিকেশনে পুনরুত্পাদন করার সিদ্ধান্ত নিয়েছি এবং আমি এখানে যা নিয়ে এসেছি তা এখানে। (নোট করুন যে এই পোস্টের প্রারম্ভিক সংস্করণে, DemoStruct একটি শ্রেণি ছিল এবং DemoClass ক্লাসের কোনও অস্তিত্বই ছিল না - আমার দোষ, তবে এটি এমন কিছু মন্তব্য ব্যাখ্যা করে যা এখন দেখতে অদ্ভুত দেখাচ্ছে ...)

using System;
using System.Diagnostics;
using System.Threading;

public struct DemoStruct
{
    public string Name { get; }

    public DemoStruct(string name)
    {
        Name = name;
    }

    public override string ToString()
    {
        Thread.Sleep(1000); // Vary this to see different results
        return $"Struct: {Name}";
    }
}

public class DemoClass
{
    public string Name { get; }

    public DemoClass(string name)
    {
        Name = name;
    }

    public override string ToString()
    {
        Thread.Sleep(1000); // Vary this to see different results
        return $"Class: {Name}";
    }
}

public class Program
{
    static void Main()
    {
        var demoClass = new DemoClass("Foo");
        var demoStruct = new DemoStruct("Bar");
        Debugger.Break();
    }
}

ডিবাগারে, আমি এখন দেখছি:

demoClass    {DemoClass}
demoStruct   {Struct: Bar}

তবে, যদি আমি Thread.Sleep হ্রাস করি Thread.Sleep কলটি 1 সেকেন্ড থেকে 900ms এ নামিয়ে আনুন, একটি ছোট বিরতি এখনও রয়েছে, তবে তারপরে আমি Class: Foo এর মান হিসাবে দেখছি। DemoStruct.ToString() Thread.Sleep কলটি কতক্ষণ তা বিবেচনা করে মনে হচ্ছে না, এটি সর্বদা সঠিকভাবে প্রদর্শিত হয় - এবং DemoStruct.ToString() ঘুম শেষ হওয়ার আগেই মানটি প্রদর্শন করে। (এটি যেন Thread.Sleep নিষ্ক্রিয়।

এখন Instant.ToString() মোটামুটি কাজ করে, তবে এটি অবশ্যই পুরো দ্বিতীয়টি নেয় না - সম্ভবত সম্ভবত আরও কিছু শর্ত রয়েছে যেগুলি ToString() একটি ToString() মূল্যায়ন করতে দেয়। এবং অবশ্যই এটি যাইহোক একটি কাঠামো।

আমি এটি স্ট্যাকের সীমা আছে কিনা তা দেখার জন্য পুনরাবৃত্তি করার চেষ্টা করেছি, তবে এটি তেমনটি ঘটেনি বলে মনে হয়।

সুতরাং, কীভাবে আমি Instant.ToString() সম্পূর্ণ মূল্যায়ন করা থেকে Instant.ToString() থামিয়ে দিচ্ছি তা নিয়ে কাজ করব? নীচে উল্লিখিত হিসাবে, DebuggerDisplayAttribute সাহায্য করার জন্য উপস্থিত হয়, তবে কেন তা না জেনে আমি কখনই আমার প্রয়োজন যখন এবং কখনই আমার প্রয়োজন হয় না সে সম্পর্কে পুরোপুরি আত্মবিশ্বাসী হতে পারি না।

হালনাগাদ

আমি যদি DebuggerDisplayAttribute ব্যবহার করি তবে জিনিসগুলি পরিবর্তন হয়:

// For the sample code in the question...
[DebuggerDisplay("{ToString()}")]
public class DemoClass

আমাকে দেয়:

demoClass      Evaluation timed out

আমি যখন নোডা সময় এটি প্রয়োগ করি:

[DebuggerDisplay("{ToString()}")]
public struct Instant

একটি সাধারণ পরীক্ষা অ্যাপ্লিকেশন আমাকে সঠিক ফলাফল দেখায়:

instant    "1970-01-01T00:00:00Z"

সুতরাং সম্ভবতঃ নোডা টাইমের সমস্যাটি এমন কিছু শর্ত যা DebuggerDisplayAttribute জোর করে - যদিও এটি সময়সীমা পেরিয়ে যায় না। (এটি আমার প্রত্যাশার সাথে Instant.ToString যে Instant.ToString খুব সহজেই একটি টাইমআউট এড়ানোর জন্য দ্রুত।

এটি একটি ভাল যথেষ্ট সমাধান হতে পারে - তবে আমি এখনও যা চলছে তা জানতে চাই এবং নোডা সময়ের সমস্ত মান ধরণের বৈশিষ্ট্যটি না রেখে এটিকে আমি কোডটি পরিবর্তন করতে পারি কিনা।

কুরিউসার এবং কুরিউসার

যেটি ডিবাগারকে বিভ্রান্ত করছে তা কেবল কখনও কখনও বিভ্রান্ত করে। আসুন একটি ক্লাস তৈরি করুন যা একটি Instant ধারণ করে এবং এটি তার নিজস্ব ToString() পদ্ধতির জন্য ব্যবহার করে:

using NodaTime;
using System.Diagnostics;

public class InstantWrapper
{
    private readonly Instant instant;

    public InstantWrapper(Instant instant)
    {
        this.instant = instant;
    }

    public override string ToString() => instant.ToString();
}

public class Program
{
    static void Main()
    {
        var instant = NodaConstants.UnixEpoch;
        var wrapper = new InstantWrapper(instant);

        Debugger.Break();
    }
}

এখন আমি দেখতে শেষ:

instant    {NodaTime.Instant}
wrapper    {1970-01-01T00:00:00Z}

যাইহোক, মন্তব্যগুলিতে ইরেনের পরামর্শে, যদি আমি InstantWrapper স্ট্রাক্ট হিসাবে পরিবর্তন করি তবে আমি পাই:

instant    {NodaTime.Instant}
wrapper    {InstantWrapper}

সুতরাং এটি Instant.ToString() মূল্যায়ন করতে পারে - যতক্ষণ না এটি অন্য ToString পদ্ধতি দ্বারা ToString ... যা শ্রেণীর মধ্যে রয়েছে। শ্রেণি / কাঠামোর অংশটি ভেরিয়েবলের ধরণের ভিত্তিতে গুরুত্বপূর্ণ বলে মনে হচ্ছে, ফলাফল পাওয়ার জন্য কোন কোডটি কার্যকর করা দরকার।

এর অন্য উদাহরণ হিসাবে, যদি আমরা ব্যবহার করি:

object boxed = NodaConstants.UnixEpoch;

... তবে এটি সঠিক মান প্রদর্শন করে, সূক্ষ্মভাবে কাজ করে। রঙিন আমাকে বিভ্রান্ত।





visual-studio-2015