সি # ঠিক আছে মান ধরণের সাথে তুলনা সঙ্গে


85

আমি আজ এটিতে ছুটে এসেছি এবং কেন সি # সংকলক ত্রুটি ছুঁড়ে ফেলছে তা জানিনা।

Int32 x = 1;
if (x == null)
{
    Console.WriteLine("What the?");
}

এক্স কীভাবে সম্ভবত নাল হতে পারে সে সম্পর্কে আমি বিভ্রান্ত। বিশেষত যেহেতু এই কার্যভারটি স্পষ্টতই একটি সংকলক ত্রুটি ছুঁড়েছে:

Int32 x = null;

এটি কি সম্ভব যে এক্স নাল হয়ে যেতে পারে, মাইক্রোসফ্ট কেবল এই চেকটি সংকলকটিতে না রাখার সিদ্ধান্ত নিয়েছে, বা এটি পুরোপুরি মিস হয়েছে?

আপডেট: এই নিবন্ধটি লেখার জন্য কোডটি নিয়ে গোলযোগের পরে, হঠাৎ সংকলকটি একটি সতর্কতা নিয়ে এসেছিল যে অভিব্যক্তিটি কখনই সত্য হবে না। এখন আমি সত্যিই হারিয়েছি। আমি বস্তুকে ক্লাসে রেখেছি এবং এখন সতর্কতাটি চলে গেছে তবে প্রশ্নটি রেখে গেছে, কোনও মান টাইপ নাল হয়ে যেতে পারে।

public class Test
{
    public DateTime ADate = DateTime.Now;

    public Test ()
    {
        Test test = new Test();
        if (test.ADate == null)
        {
            Console.WriteLine("What the?");
        }
    }
}

9
আপনি if (1 == 2)পাশাপাশি লিখতে পারেন । কোড পাথ বিশ্লেষণ সম্পাদন করা সংকলকের কাজ নয়; স্থির বিশ্লেষণ সরঞ্জাম এবং ইউনিট পরীক্ষার জন্য এটি।
অ্যারোনআউট

কেন সতর্কতা চলে গেল, আমার উত্তর দেখুন; এবং না - এটি শূন্য হতে পারে না।
মার্ক গ্র্যাভেল

4
(1 == 2) এ সম্মত, আমি পরিস্থিতি সম্পর্কে আরও ভাবছিলাম (1 == নাল)
জোশুয়া বেলডেন

ধন্যবাদ যে প্রত্যেকে। এখন সব বোঝার।
জোশুয়া বেলডেন

সতর্কবার্তা বা কোনও সতর্কবার্তা সম্পর্কিত সমস্যা সম্পর্কিত: যদি প্রশ্নে কাঠামোটি তথাকথিত "সাধারণ ধরণের" হয় তবে, intসংকলকটি দুর্দান্ত সতর্কতা উত্পন্ন করে। সাধারণ প্রকারের জন্য ==অপারেটরকে সি # ভাষার স্পেসিফিকেশন দ্বারা সংজ্ঞায়িত করা হয়। অন্যান্য (সাধারণ ধরণের নয়) স্ট্রাইকগুলির জন্য, সংকলক একটি সতর্কতা নির্গত করতে ভুলে যায়বিশদটির সাথে স্ট্রাক্টের তুলনা করার সময় ভুল সংকলক সতর্কতা দেখুন । সরল ধরণের নয় এমন স্ট্রাইকগুলির জন্য, ==অপারেটরটিকে এমন কোনও opeartor ==পদ্ধতি দ্বারা ওভারলোড করা আবশ্যক যা স্ট্রাক্টের সদস্য (অন্যথায় ==অনুমতি দেওয়া হয় না)।
জেপ্প স্টিগ নীলসেন

উত্তর:


119

এটি আইনী কারণ অপারেটর ওভারলোড রেজোলিউশনের চয়ন করার জন্য একটি অনন্য সেরা অপারেটর রয়েছে। এখানে একটি == অপারেটর রয়েছে যা দুটি নালীর মতো ints নেয়। স্থানীয় অভ্যন্তরীণ স্থানীয় একটি nlalable int পরিবর্তনযোগ্য। নাল আক্ষরিক একটি nullable int এ রূপান্তরযোগ্য। অতএব এটি == অপারেটরের একটি আইনী ব্যবহার এবং সর্বদা মিথ্যা হতে পারে।

একইভাবে, আমরা আপনাকে "যদি (x == 12.6)" বলতে পারি, যা সর্বদা মিথ্যাও থাকবে। স্থানীয় স্থানীয় লোকটি একটি ডাবলকে রূপান্তরিত করতে পারে, আক্ষরিক দ্বিগুণে রূপান্তরিত হয় এবং সম্ভবত তারা সমান হবে না be


4
আপনার মন্তব্যটি পুনরায় দিন: কানেক্ট
করুন.মাইক্রোসফট / ভিজ্যুয়াল স্টুডিও

4
@ জেমস: (আমি আমার পূর্ববর্তী ভুল মন্তব্যটি প্রত্যাহার করে নিয়েছি, যা আমি মুছে ফেলেছি default) ব্যবহারকারী-সংজ্ঞায়িত মান ধরণের যা ব্যবহারকারী-সংজ্ঞায়িত সমতা অপারেটর ডিফল্টরূপে সংজ্ঞায়িত হয় তাদের জন্য উত্পন্ন উত্সাহিত ব্যবহারকারী-সংজ্ঞায়িত সমতা অপারেটর রয়েছে have উত্তোলিত ব্যবহারকারী-সংজ্ঞায়িত সমতা অপারেটরটি আপনি যে কারণে বলেছেন তার জন্য প্রযোজ্য: সমস্ত মান প্রকারগুলি যথাযথভাবে নাল আক্ষরিক মতো, তাদের সম্পর্কিত নালামযোগ্য প্রকারের সাথে রূপান্তরিত হয়। এটি এমন নয় যে কোনও ব্যবহারকারী-সংজ্ঞায়িত মান ধরণের যেটিতে কোনও ব্যবহারকারী-সংজ্ঞায়িত তুলনা অপারেটর অভাব থাকে তা নাল আক্ষরিকের সাথে তুলনীয়।
এরিক লিপার্ট

4
@ জেমস: অবশ্যই, আপনি নিজের অপারেটর == এবং অপারেটরকে প্রয়োগ করতে পারেন! = যা অযোগ্য স্ট্রাক্ট নেয়। যদি সেগুলি বিদ্যমান থাকে তবে সংকলক স্বয়ংক্রিয়ভাবে আপনার জন্য এগুলি তৈরি করার পরিবর্তে সেগুলি ব্যবহার করবে। (এবং ঘটনাক্রমে আমি আক্ষেপ করছি যে অ-অপ্রয়োজনীয় অপারেন্ডগুলিতে অর্থহীন উত্তোলনকারী অপারেটরের জন্য সতর্কতা কোনও সতর্কতা তৈরি করে না; এটি সংকলকটিতে একটি ত্রুটি যা আমরা ফিক্সিংয়ের আশেপাশে পাইনি।)
এরিক লিপার্ট

4
আমরা আমাদের সতর্কতা চাই! আমাদের এটা প্রাপ্য.
জেপ্প স্টিগ নীলসেন

4
@ জেমসডুন: static bool operator == (SomeID a, String b)এটিকে সংজ্ঞায়িত করার সাথে এটি ট্যাগ করার বিষয়ে কী Obsolete? দ্বিতীয় অপারেন্ডটি যদি একটি টাইপযুক্ত আক্ষরিক nullহয় তবে এটি যে কোনও রূপের তুলনায় উত্তোলনযোগ্য অপারেটরগুলির ব্যবহারের চেয়ে ভাল ম্যাচ হতে পারে, তবে এটি যদি SomeID?সমান হয় nullতবে লিফট অপারেটর জিততে পারে।
সুপারক্যাট

17

এটি কোনও ত্রুটি নয়, কারণ এখানে ( int?) রূপান্তর রয়েছে; এটি প্রদত্ত উদাহরণে একটি সতর্কতা তৈরি করে:

এক্সপ্রাইজের ফলাফলটি সর্বদা 'মিথ্যা' হয় কারণ 'টাইপ' টাইপের মান কখনই 'টাইপের' নাল 'এর সমান হয় না?'

আপনি যদি আইএলটি পরীক্ষা করেন, আপনি দেখতে পাবেন এটি সম্পূর্ণরূপে অ্যাক্সেসযোগ্য শাখাটি সরিয়ে ফেলবে - এটি কোনও রিলিজ বিল্ডে নেই।

তবে নোট করুন যে এটি সাম্যতা অপারেটরগুলির সাথে কাস্টম স্ট্রাক্টগুলির জন্য এই সতর্কতা তৈরি করে না । এটি 2.0 তে ব্যবহৃত হয়েছিল, তবে 3.0 সংকলকটিতে নয়। কোডটি এখনও মুছে ফেলা হয়েছে (সুতরাং এটি জানেন যে কোডটি অ্যাক্সেসযোগ্য নয়) তবে কোনও সতর্কতা উত্পন্ন হয়নি:

using System;

struct MyValue
{
    private readonly int value;
    public MyValue(int value) { this.value = value; }
    public static bool operator ==(MyValue x, MyValue y) {
        return x.value == y.value;
    }
    public static bool operator !=(MyValue x, MyValue y) {
        return x.value != y.value;
    }
}
class Program
{
    static void Main()
    {
        int i = 1;
        MyValue v = new MyValue(1);
        if (i == null) { Console.WriteLine("a"); } // warning
        if (v == null) { Console.WriteLine("a"); } // no warning
    }
}

আইএল (for Main) - এর সাথে নোট করুন (যা পার্শ্ব প্রতিক্রিয়া থাকতে পারে ) বাদে সবকিছুMyValue(1) মুছে ফেলা হয়েছে:

.method private hidebysig static void Main() cil managed
{
    .entrypoint
    .maxstack 2
    .locals init (
        [0] int32 i,
        [1] valuetype MyValue v)
    L_0000: ldc.i4.1 
    L_0001: stloc.0 
    L_0002: ldloca.s v
    L_0004: ldc.i4.1 
    L_0005: call instance void MyValue::.ctor(int32)
    L_000a: ret 
}

এটি মূলত:

private static void Main()
{
    MyValue v = new MyValue(1);
}

4
অভ্যন্তরীণভাবে কেউ সম্প্রতি আমার কাছে এটি জানায়। কেন আমরা সেই সতর্কতা তৈরি করা বন্ধ করেছি তা আমি জানি না। আমরা এটি বাগ হিসাবে প্রবেশ করেছি।
এরিক লিপার্ট


5

তুলনা কখনই সত্য হতে পারে না তার অর্থ এই নয় যে এটি অবৈধ। যাইহোক, না, একটি মান টাইপ সর্বদা হতে পারে null


4
কিন্তু একটি মান টাইপ হতে পারে সমান করতে null। বিবেচনা করুন int?, যা সিনট্যাকটিক চিনির জন্য Nullable<Int32>, যা একটি মান ধরণের। ধরণের একটি পরিবর্তনশীল int?অবশ্যই এর সমান হতে পারে null
গ্রেগ

4
@ গ্রেগ: হ্যাঁ, এটি নাল সমান হতে পারে, ধরে নেওয়া যে আপনি যে "সমান" উল্লেখ করছেন সেটি ==অপারেটরের ফলাফল । এটি লক্ষ করা গুরুত্বপূর্ণ যে উদাহরণটি আসলে নাল নয়, যদিও।
অ্যাডাম রবিনসন

3

না, Int32 xকখনই হয়ে উঠবে না null

আপনি যদি কোনও শূন্যের সাথে কোনও তুলনা করছেন তবে তুলনা অপারেটর যা দুটি ইন্টিএস গ্রহণ করে তা প্রযোজ্য।

"নাল সাথে কোনও মানের ধরণের তুলনা কেন একটি সতর্কতা?" নিবন্ধ আপনাকে সাহায্য করবে।


1

একটি মান ধরণের হতে পারে না null, যদিও এটি সমান null(বিবেচনা Nullable<>) হতে পারে । আপনার ক্ষেত্রে intপরিবর্তনশীল এবং nullস্পষ্টতই কাস্ট করা হয় Nullable<Int32>এবং তুলনা করা হয়।


0

আমি সন্দেহ করি যে আপনার নির্দিষ্ট পরীক্ষাটি কেবল সংকলক দ্বারা অনুকূলিত করা হচ্ছে যখন এটি আইএল তৈরি করে যেহেতু পরীক্ষা কখনই ভুল হবে না।

পার্শ্ব দ্রষ্টব্য: একটি nullable Int32 ব্যবহার করা সম্ভব 32? পরিবর্তে এক্স


0

আমার ধারণা এটি কারণ কারণ "==" একটি সিনট্যাক্স চিনির যা পরামিতি System.Object.Equalsগ্রহণ করার জন্য পদ্ধতিতে কল উপস্থাপন করে System.Object। নাল বাই ইসিএমএ স্পেসিফিকেশন একটি বিশেষ ধরণের যা অবশ্যই উত্পন্ন System.Object

সে কারণেই কেবল একটি সতর্কতা রয়েছে।


এটি দুটি কারণে সঠিক নয় for প্রথমত, == এর অবজেক্টের মতো শব্দার্থক শব্দগুলি থাকে না quএকটি আর্গুমেন্টের মধ্যে যখন একটি রেফারেন্স টাইপ থাকে qu দ্বিতীয়ত, নাল কোনও প্রকার নয়। রেফারেন্স সমতা অপারেটর কীভাবে কাজ করে তা আপনি যদি বুঝতে চান তবে স্পেসিফিকেশনের 7..৯..6 অংশটি দেখুন।
এরিক লিপার্ট

"নাল আক্ষরিক (§৯.৪..4..6) নাল মানকে মূল্যায়ন করে, যা কোনও বস্তু বা অ্যারেগুলিকে নির্দেশ না করে কোনও রেফারেন্স বোঝাতে ব্যবহার করা হয় বা মানটির অনুপস্থিতি। নাল টাইপের একটি মান রয়েছে যা নাল মান। সুতরাং একটি অভিব্যক্তি যার প্রকার নাল প্রকারটি কেবল নাল মানকে মূল্যায়ন করতে পারে exp স্পষ্টভাবে নাল প্রকারটি লেখার কোনও উপায় নেই এবং অতএব, ঘোষিত প্রকারে এটি ব্যবহার করার কোনও উপায় নেই। " - এটি ইসমা থেকে প্রাপ্ত উদ্ধৃতি। আপনি কি বিষয়ে কথা হয়? এছাড়াও আপনি ইসিএমএর কোন সংস্করণ ব্যবহার করেন? আমি আমার 7.9.6 দেখতে পাচ্ছি না।
ভাইটালি

0

[সম্পাদনা করুন: ত্রুটিগুলিতে সতর্কবার্তা তৈরি করেছে এবং স্ট্রিং হ্যাকের চেয়ে অপারেটরগুলি নমনীয় সম্পর্কে স্পষ্ট করে দিয়েছে]]

উপরের মন্তব্যে @ সুপারকার্টের চতুর পরামর্শ অনুসারে, নিম্নলিখিত অপারেটর ওভারলোডগুলি আপনাকে আপনার কাস্টম মান ধরণের তুলনা সম্পর্কে ত্রুটি তৈরি করতে দেয়।

অপারেটরগুলি প্রয়োগ করে যা আপনার ধরণের নালাগুলি সংস্করণগুলির সাথে তুলনা করে, তুলনার সাথে নাল ব্যবহার অপারেটরের শূন্য সংস্করণের সাথে মেলে যা আপনাকে অপ্রচলিত বৈশিষ্ট্যের মাধ্যমে ত্রুটি তৈরি করতে দেয়।

মাইক্রোসফ্ট আমাদের সংকলক সতর্কতা ফিরে না দেওয়া পর্যন্ত আমি এই কর্মসূচীর সাথে যাচ্ছি, ধন্যবাদ @ শুক্র্যাট!

public struct Foo
{
    private readonly int x;
    public Foo(int x)
    {
        this.x = x;
    }

    public override string ToString()
    {
        return string.Format("Foo {{x={0}}}", x);
    }

    public override int GetHashCode()
    {
        return x.GetHashCode();
    }

    public override bool Equals(Object obj)
    {
        return x.Equals(obj);
    }

    public static bool operator ==(Foo a, Foo b)
    {
        return a.x == b.x;
    }

    public static bool operator !=(Foo a, Foo b)
    {
        return a.x != b.x;
    }

    [Obsolete("The result of the expression is always 'false' since a value of type 'Foo' is never equal to 'null'", true)]
    public static bool operator ==(Foo a, Foo? b)
    {
        return false;
    }
    [Obsolete("The result of the expression is always 'true' since a value of type 'Foo' is never equal to 'null'", true)]
    public static bool operator !=(Foo a, Foo? b)
    {
        return true;
    }
    [Obsolete("The result of the expression is always 'false' since a value of type 'Foo' is never equal to 'null'", true)]
    public static bool operator ==(Foo? a, Foo b)
    {
        return false;
    }
    [Obsolete("The result of the expression is always 'true' since a value of type 'Foo' is never equal to 'null'", true)]
    public static bool operator !=(Foo? a, Foo b)
    {
        return true;
    }
}

আমি যদি কিছু মিস করি না, তবে আপনার পদ্ধতির ফলে সংকলকটি এলোমেলো হয়ে উঠবে Foo a; Foo? b; ... if (a == b)..., যদিও এই জাতীয় তুলনা পুরোপুরি বৈধ হওয়া উচিত। আমি "স্ট্রিং হ্যাক" এর পরামর্শ দেওয়ার কারণটি এটি উপরের তুলনাটিকে অনুমতি দেবে তবে এটিকে ঘৃণা করবে if (a == null)। ব্যবহারের পরিবর্তে string, এক Objectবা অন্য যে কোনও রেফারেন্স টাইপ বিকল্পযুক্ত করতে পারে ValueType; যদি ইচ্ছা হয় তবে একটি প্রাইভেট কনস্ট্রাক্টরের সাথে একটি ডামি ক্লাস সংজ্ঞায়িত করা যেতে পারে যা কখনই ডাকা যায় না এবং এটি এনটাইটেল করা যায় না ReferenceThatCanOnlyBeNull
সুপারক্যাট

আপনি একেবারে সঠিক। আমার স্পষ্ট করে দেওয়া উচিত ছিল যে আমার পরামর্শটি নালাগুলির ব্যবহারকে ভেঙে দেয় ... যে কোডবেসে আমি কাজ করছি তা যাইহোক পাপ হিসাবে বিবেচিত হয় (অযাচিত বক্সিং ইত্যাদি)। ;)
yoyo

0

আমি মনে করি যে সংকলকটি কেন জেনেরিক ক্লাসগুলির জন্য এটি গ্রহণ করে তার সেরা উত্তর । নিম্নলিখিত ক্লাসটি বিবেচনা করুন ...

public class NullTester<T>
{
    public bool IsNull(T value)
    {
        return (value == null);
    }
}

সংকলক যদি nullমান ধরণের জন্য তুলনাগুলি গ্রহণ না করে , তবে এটির মূলত এই শ্রেণিটি ভেঙে ফেলা হবে, এর টাইপ প্যারামিটারের সাথে একটি অন্তর্নিহিত সীমাবদ্ধতা রয়েছে (যেমন এটি কেবল অ-মান-ভিত্তিক প্রকারের সাথে কাজ করবে)।


0

সংকলক আপনাকে ==শূন্য থেকে বাস্তবায়িত যে কোনও কাঠামোর তুলনা করতে দেয় । এমনকি এটি আপনাকে কোনও শূন্যের সাথে তুলনা করতে দেয় (যদিও আপনি একটি সতর্কতা পাবেন)।

আপনি যদি কোডটি বিচ্ছিন্ন করেন তবে আপনি দেখতে পাবেন যে কোডটি সংকলিত হওয়ার সাথে তুলনাটি সমাধান হচ্ছে। সুতরাং, উদাহরণস্বরূপ, এই কোড (যেখানে Fooএকটি স্ট্রাক্ট বাস্তবায়ন ==):

public static void Main()
{
    Console.WriteLine(new Foo() == new Foo());
    Console.WriteLine(new Foo() == null);
    Console.WriteLine(5 == null);
    Console.WriteLine(new Foo() != null);
}

এই আইএল উত্পাদন করে:

.method public hidebysig static void  Main() cil managed
{
  .entrypoint
  // Code size       45 (0x2d)
  .maxstack  2
  .locals init ([0] valuetype test3.Program/Foo V_0)
  IL_0000:  nop
  IL_0001:  ldloca.s   V_0
  IL_0003:  initobj    test3.Program/Foo
  IL_0009:  ldloc.0
  IL_000a:  ldloca.s   V_0
  IL_000c:  initobj    test3.Program/Foo
  IL_0012:  ldloc.0
  IL_0013:  call       bool test3.Program/Foo::op_Equality(valuetype test3.Program/Foo,
                                                           valuetype test3.Program/Foo)
  IL_0018:  call       void [mscorlib]System.Console::WriteLine(bool)
  IL_001d:  nop
  IL_001e:  ldc.i4.0
  IL_001f:  call       void [mscorlib]System.Console::WriteLine(bool)
  IL_0024:  nop
  IL_0025:  ldc.i4.1
  IL_0026:  call       void [mscorlib]System.Console::WriteLine(bool)
  IL_002b:  nop
  IL_002c:  ret
} // end of method Program::Main

আপনি দেখতে পারেন:

Console.WriteLine(new Foo() == new Foo());

অনুবাদ করা হয়েছে:

IL_0013:  call       bool test3.Program/Foo::op_Equality(valuetype test3.Program/Foo,
                                                               valuetype test3.Program/Foo)

যেখানে:

Console.WriteLine(new Foo() == null);

মিথ্যা অনুবাদ করা হয়েছে:

IL_001e:  ldc.i4.0
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.