এটিও সম্পূর্ণ উত্তর নয়, তবে আমার কয়েকটি ধারণা রয়েছে।
আমি বিশ্বাস করি যে আমি। নেট জেআইটি টিমের উত্তর না দিয়ে কাউকে না পেয়ে যেমন ব্যাখ্যা পেয়েছি ততই ভাল পেয়েছি।
হালনাগাদ
আমি কিছুটা গভীর থেকে তাকালাম এবং আমি বিশ্বাস করি যে আমি সমস্যার উত্স খুঁজে পেয়েছি। এটি জেআইটি টাইপ-ইনিশিয়ালাইজেশন লজিকের মধ্যে একটি বাগের সংমিশ্রণ এবং সি # সংকলক পরিবর্তনের ফলে জেআইটি কাজ করে যে ধারণাটি নির্ভর করে তা নির্ভর করে বলে মনে হয়। আমি মনে করি জেআইটি বাগটি নেট নেট in.০ এ বিদ্যমান ছিল, কিন্তু .NET 4.5 এর জন্য সংকলক পরিবর্তনের মাধ্যমে তা উন্মোচিত হয়েছিল।
আমি beforefieldinit
এখানে একমাত্র ইস্যু বলে মনে করি না । আমি মনে করি এটি এর চেয়ে সহজ।
টাইপ System.String
.NET 4.0 থেকে mscorlib.dll একটি স্ট্যাটিক কন্সট্রাকটর রয়েছে:
.method private hidebysig specialname rtspecialname static
void .cctor() cil managed
{
// Code size 11 (0xb)
.maxstack 8
IL_0000: ldstr ""
IL_0005: stsfld string System.String::Empty
IL_000a: ret
} // end of method String::.cctor
Mscorlib.dll .NET 4.5 সংস্করণে String.cctor
(স্থির নির্মাতা ) সুস্পষ্টভাবে অনুপস্থিত:
..... কোনও স্থির নির্মাতা নেই :( .....
উভয় সংস্করণে String
টাইপটি শোভিত হয় beforefieldinit
:
.class public auto ansi serializable sealed beforefieldinit System.String
আমি একটি প্রকার তৈরির চেষ্টা করেছি যা একইভাবে আইএলকে সংকলিত করতে পারে (যাতে এটিতে স্ট্যাটিক ক্ষেত্র রয়েছে তবে কোনও স্ট্যাটিক নির্মাণকারী নেই .cctor
), তবে আমি এটি করতে পারিনি। এই সমস্ত ধরণের .cctor
আইএল-তে একটি পদ্ধতি রয়েছে:
public class MyString1 {
public static MyString1 Empty = new MyString1();
}
public class MyString2 {
public static MyString2 Empty = new MyString2();
static MyString2() {}
}
public class MyString3 {
public static MyString3 Empty;
static MyString3() { Empty = new MyString3(); }
}
আমার অনুমান যে নেট। 4.0 এবং 4.5 এর মধ্যে দুটি জিনিস পরিবর্তিত হয়েছে:
প্রথম: EE পরিবর্তন করা হয়েছিল যাতে এটি পরিচালনা করা String.Empty
কোড থেকে স্বয়ংক্রিয়ভাবে আরম্ভ হবে । এই পরিবর্তনটি সম্ভবত। নেট 4.0 এর জন্য করা হয়েছিল।
দ্বিতীয়: সংকলকটি পরিবর্তিত হয়েছে যাতে এটি স্ট্রিংয়ের জন্য কোনও স্ট্যাটিক নির্মাণকারী নির্গত করে না, জেনেও যে String.Empty
এটি পরিচালনা না করা দিক থেকে নির্ধারিত হবে। এই পরিবর্তনটি .NET 4.5 এর জন্য করা হয়েছে বলে মনে হয়।
এটি প্রদর্শিত হয় যে EE কয়েকটি অপ্টিমাইজেশন পাথের সাথে শীঘ্রই পর্যাপ্ত পরিমাণ বরাদ্দ দেয় নাString.Empty
। সংকলকটিতে করা পরিবর্তন (বা String.cctor
অদৃশ্য হয়ে যা কিছু পরিবর্তিত হয়েছিল ) প্রত্যাশা করেছিল যে কোনও ব্যবহারকারী কোড কার্যকর করার আগে EE এই অ্যাসাইনমেন্টটি তৈরি করবে, তবে এটি প্রদর্শিত হয় যে String.Empty
রেফারেন্স টাইপ রিফাইড জেনেরিক ক্লাসের পদ্ধতিগুলিতে ব্যবহৃত হওয়ার আগে EE এই অ্যাসাইনমেন্টটি তৈরি করে না ।
সবশেষে, আমি বিশ্বাস করি যে জেআইটি টাইপ-ইনিশিয়ালাইজেশন যুক্তিটিতে বাগটি আরও গভীর সমস্যার সূচক। এটি প্রদর্শিত হয় যে সংকলকটির পরিবর্তনটি একটি বিশেষ ক্ষেত্রে System.String
, তবে আমি সন্দেহ করি যে এখানে জেআইটি একটি বিশেষ মামলা করেছে System.String
।
মূল
প্রথমত, WOW ছাত্রলীগের লোকেরা কিছু পারফরম্যান্স অপটিমাইজেশন দিয়ে খুব সৃজনশীল অর্জন করেছে। অনেক এর String
পদ্ধতি এখন একটি থ্রেড স্ট্যাটিক ক্যাশে ব্যবহার সঞ্চালিত হয় StringBuilder
অবজেক্ট।
আমি সেই সীসাটি কিছু সময়ের জন্য অনুসরণ করেছিলাম, তবে কোডের পথে StringBuilder
ব্যবহার করা হয়নি Trim
, তাই আমি স্থির করেছি যে এটি কোনও থ্রেড স্ট্যাটিক সমস্যা হতে পারে না।
আমি মনে করি যদিও আমি একই বাগের একটি অদ্ভুত প্রকাশ পেয়েছি।
এই কোডটি অ্যাক্সেস লঙ্ঘনের সাথে ব্যর্থ হয়:
class A<T>
{
static A() { }
public A(out string s) {
s = string.Empty;
}
}
class B
{
static void Main() {
string s;
new A<object>(out s);
//new A<int>(out s);
System.Console.WriteLine(s.Length);
}
}
যাইহোক, যদি আপনি অসুবিধা //new A<int>(out s);
না করেন Main
তবে কোডটি ঠিক কাজ করে। আসলে, যদি A
কোনও রেফারেন্স টাইপ দিয়ে রিফাইড করা হয় তবে প্রোগ্রামটি ব্যর্থ হয়, তবে যদি A
কোনও মান প্রকারের সাথে সংশোধিত হয় তবে কোডটি ব্যর্থ হয় না। এছাড়াও যদি আপনি A
স্থিতিশীল নির্মাতাকে মন্তব্য করেন তবে কোডটি কখনও ব্যর্থ হয় না। Trim
এবং Format
এটি খননের পরে , এটি স্পষ্ট যে সমস্যাটি হ'ল Length
ইনলাইন করা হচ্ছে, এবং এই String
ধরণের উপরে নমুনাগুলি শুরু করা হয়নি। বিশেষ করে, শরীরের ভিতরে A
এর কন্সট্রাকটর, string.Empty
সঠিকভাবে নির্ধারিত হয় না, যদিও শরীরের ভিতরে Main
, string.Empty
সঠিকভাবে নির্ধারিত হয়।
এটা আমার কাছে আশ্চর্যজনক যে কোনও ধরণের প্রারম্ভিককরণ String
কোনও A
মান প্রকারের সাথে সংশোধিত কিনা তা নির্ভর করে । আমার একমাত্র তত্ত্বটি হ'ল জেনেরিক টাইপ-ইনিশিয়ালাইজেশনের জন্য কিছু সংশোধনযোগ্য জেআইটি কোড পাথ রয়েছে যা সব ধরণের মধ্যে ভাগ করা হয় এবং সেই পথটি বিসিএল রেফারেন্স টাইপগুলি ("বিশেষ ধরণের?") এবং তাদের অবস্থা সম্পর্কে অনুমান করে। সঙ্গে যদিও অন্যান্য ছাত্রলীগের শ্রেণীর একটি দ্রুত বর্ণন public static
ক্ষেত্র শো মূলত সব তাদের একটি স্ট্যাটিক কন্সট্রাক্টর (এমনকি যারা খালি কনস্ট্রাকটর এবং কোন ডেটা, মতো বাস্তবায়ন System.DBNull
এবং System.Empty
সঙ্গে। ছাত্রলীগের মান ধরনের public static
ক্ষেত্র একটি স্ট্যাটিক কন্সট্রাক্টর (বাস্তবায়ন বলে মনে হচ্ছে না System.IntPtr
, উদাহরণস্বরূপ) এটি দেখে মনে হয় যে বিসিএল রেফারেন্স ধরণের সূচনা সম্পর্কে জেআইটি কিছু অনুমান করে।
এফওয়াইআই দুটি সংস্করণের জন্য এখানে জেআইটিড কোডটি রয়েছে:
A<object>.ctor(out string)
:
public A(out string s) {
00000000 push rbx
00000001 sub rsp,20h
00000005 mov rbx,rdx
00000008 lea rdx,[FFEE38D0h]
0000000f mov rcx,qword ptr [rcx]
00000012 call 000000005F7AB4A0
s = string.Empty;
00000017 mov rdx,qword ptr [FFEE38D0h]
0000001e mov rcx,rbx
00000021 call 000000005F661180
00000026 nop
00000027 add rsp,20h
0000002b pop rbx
0000002c ret
}
A<int32>.ctor(out string)
:
public A(out string s) {
00000000 sub rsp,28h
00000004 mov rax,rdx
s = string.Empty;
00000007 mov rdx,12353250h
00000011 mov rdx,qword ptr [rdx]
00000014 mov rcx,rax
00000017 call 000000005F691160
0000001c nop
0000001d add rsp,28h
00000021 ret
}
বাকি কোডটি ( Main
দুটি) দুটি সংস্করণের মধ্যে অভিন্ন।
সম্পাদনা
উপরন্তু, দুটি সংস্করণ থেকে আইএল থেকে কল ছাড়া অভিন্ন A.ctor
মধ্যে B.Main()
, যেখানে প্রথম সংস্করণের জন্য আইএল রয়েছে:
newobj instance void class A`1<object>::.ctor(string&)
বনাম
... A`1<int32>...
দ্বিতীয় মধ্যে।
আরেকটি বিষয় লক্ষণীয় A<int>.ctor(out string)
: এর জন্য জেআইটিড কোড : নন-জেনেরিক সংস্করণের মতো।