স্ট্রাক টাইপের আউট প্যারামিটারগুলি বরাদ্দ করার দরকার নেই


9

কোড পর্যালোচনা চলাকালীন ঘটনাক্রমে কোনও কার্যক্রমে একটি লাইন মন্তব্য করার সময় আমি আমার কোডে কিছু উদ্ভট আচরণ লক্ষ্য করেছি। এটি পুনরুত্পাদন করা খুব কঠিন ছিল তবে আমি এখানে একটি অনুরূপ উদাহরণ চিত্রিত করব।

আমি এই পরীক্ষার ক্লাস পেয়েছি:

public class Test
{
    public void GetOut(out EmailAddress email)
    {
        try
        {
            Foo(email);
        }
        catch
        {
        }
    }

    public void Foo(EmailAddress email)
    {
    }
}

ইমেলের কোনও অ্যাসাইনমেন্ট নেই GetOutযা সাধারণত কোনও ত্রুটি ছুঁড়ে দেয়:

কন্ট্রোলটি বর্তমান পদ্ধতিটি ছাড়ার আগে আউট প্যারামিটার 'ইমেল' অবশ্যই বরাদ্দ করা উচিত

তবে যদি ইমেইলএড্রেস কোনও বিচ্ছিন্ন সমাবেশে কোনও কাঠামোতে থাকে তবে কোনও ত্রুটি তৈরি হয় না এবং সমস্ত কিছু সূক্ষ্মভাবে সংকলিত হয়।

public struct EmailAddress
{
    #region Constructors

    public EmailAddress(string email)
        : this(email, string.Empty)
    {
    }

    public EmailAddress(string email, string name)
    {
        this.Email = email;
        this.Name = name;
    }

    #endregion

    #region Properties

    public string Email { get; private set; }
    public string Name { get; private set; }

    #endregion
}

সংকলক কেন ইমেলটি অর্পণ করতে হবে তা প্রয়োগ করে না? এই কোডটি যদি পৃথক সমাবেশে স্ট্রাক্ট তৈরি করা হয় তবে এটি সংকলন করে না তবে বিদ্যমান সংঘে স্ট্রাকটি সংজ্ঞায়িত করা থাকলে তা সংকলন করে না?


2
আপনি যদি কোনও ক্লাস ব্যবহার করছেন তবে আপনাকে অবজেক্টের একটি উদাহরণ 'নতুন' করতে হবে। এটি স্ট্রাইকগুলির জন্য প্রয়োজনীয় নয়। ডকস.মাইক্রোসফট.ইন- ইউএস / ডটনেট / সিএসআরপি / প্রগ্রামগ্রামিং-গাইড ( ৮ ) এই পৃষ্ঠায় বিশেষভাবে এই পাঠ্যের জন্য অনুসন্ধান করুন: শ্রেণীর বিপরীতে, নতুন
— অপেরাটো

1
আপনার কুকুরের কাঠামোটি ভেরিয়েবল পাওয়ার সাথে সাথে এটি সংকলন করবে না :)
— আন্ড্রে স্যানসান

এই উদাহরণে, সাথে struct Dog{}, সবকিছু ঠিক আছে।
— হেন্ক হলটারম্যান

2
@ জননি 5 তারপরে উদাহরণটি দেখান।
— আন্দ্রে স্যানসন

1
ঠিক আছে, এটি আকর্ষণীয়। একটি কোর 3 কনসোল অ্যাপ্লিকেশন এবং একটি। স্ট্যান্ডার্ড বর্গ lib দিয়ে পুনরুত্পাদন করা।
— হেন্ক হলটারম্যান

উত্তর:


12

টিএলডিআর: এটি দীর্ঘস্থায়ী পরিচিত বাগ। আমি এটি সম্পর্কে প্রথম লিখেছিলাম ২০১০ সালে:

https://blogs.msdn.microsoft.com/ericlippert/2010/01/18/a-definite-assignment-anomaly/

এটি নিরীহ এবং আপনি এটি নিরাপদে উপেক্ষা করতে পারেন এবং কিছুটা অস্পষ্ট বাগ খুঁজে পাওয়ার জন্য নিজেকে অভিনন্দন জানাতে পারেন।

সংকলকটি Emailঅবশ্যই কার্যকর করা উচিত না কেন ?

ওহ, এটি একটি ফ্যাশন করে। এটির শর্তটি কীভাবে বোঝায় যে ভেরিয়েবলটি অবশ্যই নির্ধারিত হয়েছে সে সম্পর্কে এটির একটি ভুল ধারণা রয়েছে, যা আমরা দেখব।

এই কোডটি যদি পৃথক সমাবেশে স্ট্রাক্ট তৈরি করা হয় তবে এটি সংকলন করে না তবে বিদ্যমান সংঘে স্ট্রাকটি সংজ্ঞায়িত করা থাকলে তা সংকলন করে না?

এটাই বাগের কর্কট। বাগ কীভাবে সি # সংকলক স্ট্রাক্টগুলিতে সুনির্দিষ্ট অ্যাসাইনমেন্ট পরীক্ষা করে এবং সংকলকটি কিভাবে লাইব্রেরি থেকে মেটাডেটা লোড করে তার ছেদ করার একটি পরিণতি।

এই বিবেচনা:

struct Foo 
{ 
  public int x; 
  public int y; 
}
// Yes, public fields are bad, but this is just 
// to illustrate the situation.
void M(out Foo f)
{

ঠিক আছে, এই মুহুর্তে আমরা কী জানি? fপ্রকারের পরিবর্তনের জন্য একটি উপাধি Foo, তাই স্টোরেজটি ইতিমধ্যে বরাদ্দ করা হয়েছে এবং এটি অবশ্যই স্টোরেজ বরাদ্দকারী থেকে বেরিয়ে এসেছিল এমন রাজ্যে অবশ্যই রয়েছে। যদি কলারের দ্বারা চলকটিতে কোনও মান স্থাপন করা হত তবে সেই মানটি সেখানে।

আমাদের কী দরকার? আমাদের প্রয়োজনীয়তা fঅবশ্যই নিয়ন্ত্রণের Mস্বাভাবিকভাবে ছেড়ে যায় এমন যে কোনও সময়ে নিযুক্ত করা উচিত । সুতরাং আপনি যেমন কিছু আশা করতে হবে:

void M(out Foo f)
{
  f = new Foo();
}

যা সেট f.xএবং f.yতাদের ডিফল্ট মান। তবে এই কি?

void M(out Foo f)
{
  f = new Foo();
  f.x = 123;
  f.y = 456;
}

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

void M(out Foo f)
{
  f.x = 123;
  f.y = 456;
}

এবং কেন এটি আইনী হওয়া উচিত নয়? এটি একটি মান ধরণের। fএকটি পরিবর্তনশীল, এবং এটি ইতিমধ্যে প্রকারের একটি বৈধ মান রয়েছে Foo, সুতরাং আসুন কেবল ক্ষেত্রগুলি সেট করুন, এবং আমরা শেষ করেছি, তাই না?

ঠিক। তাহলে বাগ কি?

আপনি যে বাগটি আবিষ্কার করেছেন তা হ'ল: ব্যয় সাশ্রয় হিসাবে, সি # সংকলক রেফারেন্সযুক্ত লাইব্রেরিতে থাকা স্ট্রাইকগুলির ব্যক্তিগত ক্ষেত্রগুলির জন্য মেটাডেটা লোড করে না । এই মেটাডেটা বিশাল হতে পারে এবং প্রতিবার মেমরিতে এগুলি লোড করার জন্য খুব কম জয়ের জন্য সংকলকটি ধীর করে দেয়।

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

যেমনটি আমি বলেছিলাম, এই বাগটি এক দশকেরও বেশি সময় ধরে চলেছে এবং আপনার মতো লোকেরা মাঝে মধ্যে এটি পুনরায় আবিষ্কার করে এবং এটি প্রতিবেদন করে। এটি নির্দোষ, এবং এটি ঠিক হওয়ার সম্ভাবনা নেই কারণ এটি স্থির করা প্রায় শূন্যের উপকারের তবে একটি বড় কর্মক্ষমতা ব্যয়।

এবং অবশ্যই আপনার প্রকল্পের উত্স কোডে থাকা স্ট্রাইকগুলির ব্যক্তিগত ক্ষেত্রগুলির জন্য বাগটি ত্রুটিযুক্ত নয়, কারণ স্পষ্টতই সংকলকটির হাতে থাকা ব্যক্তিগত ক্ষেত্রগুলি সম্পর্কে ইতিমধ্যে তথ্য রয়েছে।


@ জননি 5: আপনার ত্রুটি হওয়া উচিত নয়। Dotnetfiddle.net/ZEKiUk দেখুন । আপনি কি একটি সাধারণ তিরস্কার পোস্ট করতে পারেন?
— এরিক লিপার্ট

1
ফিডলের জন্য ধন্যবাদ কারণ এটি ছিল যে আমি সদস্যের পরিবর্তে x এবং y সম্পত্তি হিসাবে সংজ্ঞায়িত করেছি
— j

1
@ জননি 5: আপনি যদি কেবলমাত্র একটি সাধারণ সি # 1.0 শৈলীর সম্পত্তি নির্ধারণ করেন তবে সুনির্দিষ্ট অ্যাসাইনমেন্ট চেকারের দৃষ্টিকোণ থেকে, এটি একটি পদ্ধতি নয়, ক্ষেত্র নয়। আপনি যদি একটি সি # 3.0+ স্টাইলের স্বয়ংক্রিয় সম্পত্তি সংজ্ঞায়িত করেন তবে সংকলক জানে যে এটির কোনও বেসরকারী ক্ষেত্র ব্যাক করছে; এই জিনিসটির নির্দিষ্ট দায়িত্বের নিয়মগুলি বছরের পর বছর ধরে টুইট করা হয়েছে এবং আমি এখন সঠিক নিয়মগুলি মনে করতে পারি না।
— এরিক লিপার্ট

আপনি যদি এর System.TimeSpanপরিবর্তে ব্যবহার করেন তবে ত্রুটিগুলি আসে: error CS0269: Use of unassigned out parameter 'email'এবং error CS0177: The out parameter 'email' must be assigned to before control leaves the current method। এর একমাত্র স্থিতিশীল ক্ষেত্র রয়েছে TimeSpan, যথা _ticks। এটি internalএর সমাবেশে মস্কোরলিব। এই সমাবেশ কি বিশেষ? একই System.DateTime, এবং এর ক্ষেত্রটি হ'লprivate
— জেপ্পে স্টিগ নীলসেন

@ জেপ্পস্টিগ নিলসন: আমি জানি না যে কী ঘটেছে! যদি আপনি এটি বুঝতে পারেন, দয়া করে আমাকে জানান।
— এরিক লিপার্ট

1

এটি কোনও বাগের মতো দেখতে এটি কিছুটা অর্থপূর্ণ করে তোলে।

'অনুপস্থিত ত্রুটি' কেবলমাত্র ক্লাস লাইব্রেরি ব্যবহার করার সময় উপস্থিত হয়। এবং ক্লাসের গ্রন্থাগারটি অন্য। নেট ভাষায় লেখা যেতে পারে, যেমন ভিবি.নেট। 'নির্দিষ্ট অ্যাসাইনমেন্ট ট্র্যাকিং' ফ্রেমওয়ার্কের নয়, সি # এর একটি বৈশিষ্ট্য।

সুতরাং সামগ্রিকভাবে আমি এটি একটি ত্রুটি মনে করি না তবে আমি এটির জন্য কোনও অনুমোদনমূলক বিবৃতি সম্পর্কে জানি না।


আপনি যদি অ্যাসেম্বলিটি সি # তে আমদানি করেন, যদিও স্ট্রাক্টটি অন্য ভাষায় লিখিত একটি অ্যাসেমব্লিতে থাকতে পারে, এটি ব্যবহার করে কোডটি এখনও সি # তে রয়েছে তাই এটি নির্দিষ্ট অ্যাসাইনমেন্ট ট্র্যাকিং ব্যবহার করা উচিত নয়।
— জননি 5

1
অগত্যা। সি # আপনাকে ইউনিটিয়ালাইজড (স্থানীয়) ভেরিয়েবল ব্যবহার করতে দেয় না তবে একই সাথে ফ্রেমওয়ার্ক গ্যারান্টি দেয় যে এটি 0 ( default(T)) এ সেট করা হবে । সুতরাং মেমোরি-সুরক্ষা বা অনুরূপ কোনও লঙ্ঘন নেই।
— হেন্ক হলটারম্যান

3
আমি এই ধরনের একটি অনুমোদনমূলক বিবৃতি দিতে পারেন। :) এটি একটি দীর্ঘস্থায়ী পরিচিত বাগ।
— এরিক লিপার্ট

1
@ এরিকলিপার্ট ধন্যবাদ, আমি আশা করছিলাম আপনি এটিকে কিছু সময় দেখতে পাবেন
— জননি 5
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.