গেটটাইপ () মিথ্যা বলতে পারে?


94

কিছু দিন আগে এসও: গেটটাইপ () এবং পলিমারফিজম এবং এরিক লিপার্টের উত্তর পড়া নীচের প্রশ্নের উপর ভিত্তি করে আমি ভাবতে শুরু করেছিলাম GetType()যে ভার্চুয়াল না হয়ে আসলেই নিশ্চিত করা হয়েছে যে কোনও বস্তু এর সম্পর্কে মিথ্যা বলতে পারে না Type।

বিশেষত, এরিকের উত্তর নিম্নলিখিতটি বলে:

ফ্রেমওয়ার্ক ডিজাইনাররা একটি অবিশ্বাস্যরূপে বিপজ্জনক বৈশিষ্ট্য যুক্ত করতে যাচ্ছেন না যেমন কোনও বস্তুকে কেবল একই ধরণের অন্য তিনটি পদ্ধতির সাথে সামঞ্জস্য করার জন্য এটির ধরণ সম্পর্কে মিথ্যা বলার অনুমতি দেওয়া হয়।

এখন প্রশ্ন হ'ল: আমি কি এমন কোনও বস্তু তৈরি করতে পারি যা তা অবিলম্বে সুস্পষ্ট না হয়েই তার ধরণের সম্পর্কে মিথ্যা বলে? আমি এখানে গভীর ভুল হতে পারি এবং আমি যদি সে ক্ষেত্রে হয় তবে স্পষ্টতা পছন্দ করতে চাই তবে নীচের কোডটি বিবেচনা করুন:

public interface IFoo
{
    Type GetType();
}

এবং বর্ণিত ইন্টারফেসের নিম্নলিখিত দুটি বাস্তবায়ন:

public class BadFoo : IFoo
{
    Type IFoo.GetType()
    {
        return typeof(int);
    }
}

public class NiceFoo : IFoo
{
}

তারপরে আপনি যদি নিম্নলিখিত সাধারণ প্রোগ্রামটি চালান:

static void Main(string[] args)
{
    IFoo badFoo = new BadFoo();
    IFoo niceFoo = new NiceFoo();
    Console.WriteLine("BadFoo says he's a '{0}'", badFoo.GetType().ToString());
    Console.WriteLine("NiceFoo says he's a '{0}'", niceFoo.GetType().ToString());
    Console.ReadLine();
}

অবশ্যই যথেষ্ট পরিমাণে badFooভুল কাজ করেছে Type।

এখন আমি জানি না যে এরিকের এই আচরণটিকে " অবিশ্বাস্যরূপে বিপজ্জনক বৈশিষ্ট্য " হিসাবে বর্ণনা করার উপর ভিত্তি করে এর কোনও গুরুতর প্রভাব রয়েছে কিনা , তবে এই প্যাটার্নটি কি কোনও বিশ্বাসযোগ্য হুমকি হতে পারে?


4
আকর্ষণীয় শিরোনাম এবং বিষয়!
— ডেভিড

43
IFoo.GetTypeএবং object.GetTypeএকই জিনিস নয় তাই দুর্বল শৈলী ব্যতীত এখানে খারাপ কিছুই ঘটছে না। সম্পাদনা: সাধারণত GetTypeএমন কিছু বস্তুর উপরে ডেকে পাঠানো হবে যা সংকলন-সময়ে জানা যায় না, বেশিরভাগ ক্ষেত্রে objectএবং কিছু ডজি ইন্টারফেস নয়। :)
— লিপি

4
আপনার শিরোনাম স্যার, আমার দিন তৈরি।
— সোনার Gön 28l

5
আপনি ঠিক একই স্বাক্ষর সহ নতুন সদস্যদেরও ডেকে পরিচয় করিয়ে GetTypeদিয়েছেন। GetTypeএটি গুরুত্বপূর্ণ যে পদ্ধতির সাথে সম্পর্কিত নয় । আপনি একটি সর্বজনীন উদাহরণ পদ্ধতিও তৈরি করতে পারেন যা সংশোধনকারী কীওয়ার্ডটি GetTypeব্যবহার করে প্রাসঙ্গিক পদ্ধতিটিকে আড়াল করে new। দ্রষ্টব্য, আপনার যদি জেনেরিক পদ্ধতি থাকে static Type Test<T>(T t) { return t.GetType(); }( যেমন কোনও বাধা ছাড়াই T) থাকে তবে Test<IFoo>(new BadFoo())তার মতো স্টাফগুলি এখনও মূল GetTypeপদ্ধতিটিকে কল করবে ।
— জেপ্পে স্টিগ নীলসেন

4
@ জামেইক - প্রশ্ন "এই প্যাটার্নটি কি বিশ্বাসযোগ্য হুমকি সৃষ্টি করতে পারে?" বাজে কথা নয়।
— মার্টিন স্মিথ

উত্তর:


45

সুন্দর প্রশ্ন! আমি এটি যেভাবে দেখছি, আপনি কেবলমাত্র সহকর্মী বিকাশকারীকে বিভ্রান্ত করতে পারেন যদি গেটটাইপ বস্তুটিতে ভার্চুয়াল ছিল, যা এটি নয়।

আপনি যা করেছেন তা গেটটাইপকে ছায়া দেওয়ার মতো, যেমন:

public class BadFoo
{
    public new Type GetType()
    {
        return typeof(int);
    }
}

এই শ্রেণীর সাথে (এবং এমএসডিএন থেকে গেটটাইপ () পদ্ধতির জন্য নমুনা কোডটি ব্যবহার করে ) আপনি অবশ্যই পেতে পারেন:

int n1 = 12;
BadFoo foo = new BadFoo();

Console.WriteLine("n1 and n2 are the same type: {0}",
                  Object.ReferenceEquals(n1.GetType(), foo.GetType())); 
// output: 
// n1 and n2 are the same type: True

তাই, হ্যাঁ, আপনি সফলভাবে মিথ্যা বলেছেন, তাই না? ঠিক আছে, হ্যাঁ এবং না ... বিবেচনা করুন যে এটিকে শোষণ হিসাবে ব্যবহার করার অর্থ আপনার ব্যাডফু উদাহরণটি কোনও কোনও পদ্ধতির যুক্তি হিসাবে ব্যবহার করা হবে, যা প্রত্যাশাগুলির objectশ্রেণিবিন্যাসের জন্য সম্ভবত একটি বা সাধারণ বেস টাইপ করে। এটার মতো কিছু:

public void CheckIfInt(object ob)
{
    if(ob.GetType() == typeof(int))
    {
        Console.WriteLine("got an int! Initiate destruction of Universe!");
    }
    else
    {
        Console.WriteLine("not an int");
    }
}

তবে CheckIfInt(foo)"ইনট নয়" প্রিন্ট করে।

সুতরাং, মূলত (আপনার উদাহরণে ফিরে), আপনি কেবলমাত্র আপনার IFooইন্টারফেসের বিপরীতে কেউ লিখেছেন এমন কোড সহ আপনার "মিথ্যা প্রকার" ব্যবহার করতে পারেন , এটির "কাস্টম" GetType()পদ্ধতি রয়েছে এই বিষয়টি সম্পর্কে খুব স্পষ্ট ।

গেটটাইপ () যদি বস্তুটিতে ভার্চুয়াল হয় তবেই আপনি "মিথ্যা" টাইপের কারুকাজ করতে সক্ষম হবেন যা CheckIfIntঅন্য কারও দ্বারা লিখিত লাইব্রেরিতে বিধ্বস্ত করার জন্য উপরের মতো পদ্ধতিগুলির সাথে ব্যবহার করা যেতে পারে ।


হ্যাঁ, এটি ছায়ার মত ঠিক শেষ অনুচ্ছেদটি যা প্রকৃতপক্ষে এটি স্পষ্ট করে তোলে যে আসলেই কোনও হুমকি নেই। ধন্যবাদ!
— inbetween

32

প্রকার সম্পর্কে নিশ্চিত হওয়ার দুটি উপায় রয়েছে:

  1. typeofযে ধরণের ওভারলোড করা যায় না তা ব্যবহার করুন

    IFoo badFoo = new BadFoo();
    IFoo niceFoo = new NiceFoo();
    
    Console.WriteLine("BadFoo says he's a '{0}'", badFoo.GetType().ToString());
    Console.WriteLine("NiceFoo says he's a '{0}'", niceFoo.GetType().ToString());
    
    Console.WriteLine("BadFoo really is a '{0}'", typeof(BadFoo));
    Console.WriteLine("NiceFoo really is a '{0}'", typeof(NiceFoo));
    Console.ReadLine();
    
  2. উদাহরণটিকে একটিতে কাস্ট করুন objectএবং GetType()পদ্ধতিটি কল করুন

    IFoo badFoo = new BadFoo();
    IFoo niceFoo = new NiceFoo();
    
    Console.WriteLine("BadFoo says he's a '{0}'", badFoo.GetType().ToString());
    Console.WriteLine("NiceFoo says he's a '{0}'", niceFoo.GetType().ToString());
    
    Console.WriteLine("BadFoo really is a '{0}'", ((object)badFoo).GetType());
    Console.WriteLine("NiceFoo really is a '{0}'", ((object)niceFoo).GetType());
    Console.ReadLine();
    

4
আপনি typeofযে পদ্ধতিতে কেবলমাত্র IFoo badFooপ্যারামিটার হিসাবে ব্যবহার করবেন তা কীভাবে ব্যবহার করবেন ?
— হাইস্ট্রিটউ

typeofআমাদের এখানে যা করা দরকার তা বর্গের উদাহরণগুলিতে প্রয়োগ করা যায় না। আপনার একমাত্র বিকল্প GetType()।
— ই

আপনার দুটি নমুনা দুটি পৃথক কাজ করছে। দ্বিতীয় রেখাগুলি প্রয়োজনীয় প্রশ্নের উত্তর দেয় না - তারা স্পষ্টভাবে "টাইপ পান BadFoo" তবে তারা "ভেরিয়েবলের ধরণ পান না" badFoo।
— ড্যান পুজে

হ্যাঁ আমি দুঃখিত। যথারীতি আমি যথেষ্ট মনোযোগ দিয়ে প্রশ্নটি পড়িনি। টাইপ সম্পর্কে নিশ্চিত হওয়ার দুটি ভিন্ন উপায় উল্লেখ করার জন্য আমি আমার উত্তর আপডেট করেছি।
— জোহানেস ওয়ানজাক

4
এই আমি ইঙ্গিত ছিল। তাহলে আপনার মন্তব্যের মূল বক্তব্য কী? :)
— জোহানেস ওয়ানজিক

10

না, আপনি গেটটাইপ মিথ্যা বলতে পারবেন না। আপনি কেবল একটি নতুন পদ্ধতি প্রবর্তন করছেন। এই পদ্ধতি সম্পর্কে সচেতন এমন কোডগুলিই এটি কল করবে।

আপনি উদাহরণস্বরূপ তৃতীয় পক্ষ বা ফ্রেমওয়ার্ক কোডটিকে বাস্তবের পরিবর্তে আপনার নতুন গেটটাইপ পদ্ধতিতে কল করতে পারবেন না, যেহেতু এই কোডটি জানেন না যে আপনার পদ্ধতিটি বিদ্যমান এবং তাই এটি কখনই কল করবে না।

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

আপনি যদি একটি বর্গ একটি ব্যবহার করে এই কাজ করা উচিত জন্য একটি কাস্টম টাইপ বর্ণনা প্রদান করতে চান না যদি কাস্টম প্রকার বর্ণনাকারী সম্ভবত একটি সঙ্গে আপনার বর্গ টিকা দ্বারা, TypeDescriptionProviderAttribute । এটি কিছু পরিস্থিতিতে কার্যকর হতে পারে।


4
আপনার দ্বিতীয় অনুচ্ছেদের জন্য +1 স্পষ্টভাবে নির্দেশ করে যে তৃতীয় পক্ষের কোডটি কোনও কাস্টম গেটটাইপ বাস্তবায়ন সম্পর্কে জানে না। অন্যান্য উত্তরগুলি এই ধারণার প্রতি ইঙ্গিত দিয়েছিল তবে সত্যই বেরিয়ে এসে তা বলে নি (কমপক্ষে পরিষ্কার হিসাবে নয়)।
— ব্রিচিন্স

7

ওয়েল, আসলে সেখানে হয় ইতিমধ্যে একটি টাইপ যা থাকা পারেন GetTypeকোনো nullable টাইপ:।

এই কোড :

int? x = 0; int y = 0;
Console.WriteLine(x.GetType() == y.GetType());

আউটপুট True।


প্রকৃতপক্ষে, int?তিনি যে মিথ্যা কথা বলছেন তা নয় , কেবল বাক্সে objectপরিণত int?হওয়ার জন্য নিখুঁত অভিনেতাকে int। কিন্তু তা সত্ত্বেও আপনি করতে পারবেন না বলুন int?থেকে intসঙ্গে GetType()।


4
যা প্রত্যাশিত (বা কমপক্ষে সুপরিচিত) আচরণ। উত্তর এই প্রশ্ন এই ধারণা চমত্কার পরিষ্কারভাবে, সেইসাথে এটা জন্য কারণ ব্যাখ্যা করে।
— brichins

@ ব্রিচিনস: ঠিক আছে, আমি সম্মত হয়েছি এটি পরিচিত, তবে আমি এটি ভালভাবেই জানাতে পারি না । যাইহোক, এটি এমন একটি ঘটনা যেখানে GetType()কিছুটা বিস্ময়কর ফলাফল আসে। আমি প্রকৃতপক্ষে বেশ কয়েকজন সহকর্মীকে জিজ্ঞাসা করেছি যে কোনও ছায়াবিহীন GetType()এমন কিছু ফিরে আসতে পারে যা প্রকৃত অবজেক্টের রানটাইম টাইপের চেয়ে আলাদা, প্রত্যেকের উত্তর ছিল 'না'।
— ভ্লাদ

5

আমার মনে হয় না, যেহেতু প্রতিটি লাইব্রেরি কোড যা গেটটাইপ কল করে তা ভেরিয়েবলটিকে 'অবজেক্ট' বা জেনেরিক টাইপ 'টি' হিসাবে ঘোষণা করবে

নিম্নলিখিত কোড:

    public static void Main(string[] args)
    {
        IFoo badFoo = new BadFoo();
        IFoo niceFoo = new NiceFoo();
        PrintObjectType("BadFoo", badFoo);
        PrintObjectType("NiceFoo", niceFoo);
        PrintGenericType("BadFoo", badFoo);
        PrintGenericType("NiceFoo", niceFoo);
    }

    public static void PrintObjectType(string actualName, object instance)
    {
        Console.WriteLine("Object {0} says he's a '{1}'", actualName, instance.GetType());
    }

    public static void PrintGenericType<T>(string actualName, T instance)
    {
        Console.WriteLine("Generic Type {0} says he's a '{1}'", actualName, instance.GetType());
    }

মুদ্রণ:

অবজেক্ট ব্যাডফু বলেছেন যে তিনি 'টাইপকনসেপ্ট.ব্যাডফু'

নিসফু অবজেক্টটি বলেছে যে সে 'টাইপকনসেপ্ট.নাইসফু'

জেনেরিক টাইপ ব্যাডফু বলেছেন যে তিনি 'টাইপকনসেপ্ট.ব্যাডফু'

জেনেরিক টাইপ নাইসফু বলেছেন যে তিনি একজন 'টাইপকনসেপ্ট.নাইসফু'

এই জাতীয় কোডটি কেবলমাত্র আপনার নিজের কোডেই খারাপ দৃশ্যের ফলাফল ঘটবে, যেখানে আপনি প্যারামিটারের প্রকারটি আইএফও হিসাবে ঘোষণা করেন

    public static void Main(string[] args)
    {
        IFoo badFoo = new BadFoo();
        IFoo niceFoo = new NiceFoo();
        PrintIFoo("BadFoo", badFoo);
        PrintIFoo("NiceFoo", niceFoo);
    }

    public static void PrintIFoo(string actualName, IFoo instance)
    {
        Console.WriteLine("IFoo {0} says he's a '{1}'", actualName, instance.GetType());
    }

আইএফও ব্যাডফু বলেছেন যে তিনি একজন 'সিস্টেম.আইন্ট 32'

আইফু নিসফু বলেছেন যে তিনি একজন 'টাইপকনসেপ্ট.নাইসফু'


4

যতদূর আমি বলতে পারি সবচেয়ে খারাপ হতে পারে হ'ল নিরপরাধ প্রোগ্রামারদের বিভ্রান্ত করে যারা বিষাক্ত শ্রেণীর ব্যবহার করে, উদাহরণস্বরূপ:

Type type = myInstance.GetType();
string fullName = type.FullName;
string output;
if (fullName.Contains(".Web"))
{
    output = "this is webby";
}
else if (fullName.Contains(".Customer"))
{
    output = "this is customer related class";
}
else
{
    output = "unknown class";
}

আপনি myInstanceযদি কোনও শ্রেণীর উদাহরণ হিসাবে প্রশ্নে বর্ণনা করেন তবে এটি কেবল অজানা ধরণের হিসাবে বিবেচিত হবে।

সুতরাং আমার উত্তর না, এখানে কোনও আসল হুমকি দেখতে পাচ্ছেন না।


4
অবশ্যই একটি সাবধানী প্রোগ্রামার সংকলন সময়ে দেখতে পাবে যে "গেটটাইপ" তিনি কোন পদ্ধতিটি গ্রহণ করেন। Object.GetType()থেকে পৃথক SomeUserdefinedInterfaceClassOrStruct.GetType()। কেবলমাত্র, আপনি যদি dynamicটাইপটি ব্যবহার করেন তবে আপনি কখনই তা জানতে পারবেন না যে বাঁধাইয়ের সময় কী হবে। সুতরাং আপনি dynamic x = expression; ... Type t = ((object)x).GetType();যেমন ক্ষেত্রে ব্যবহার করা উচিত ।
— জেপ্প স্টিগ নীলসন

@ জেপ্পে ফেয়ার পয়েন্ট! আমি মনে করি এটি পৃথক উত্তরকে ন্যায্যতা দেয়, আমার উত্তরটি "নির্দোষ" প্রোগ্রামারকে আরও বেশি কেন্দ্রীভূত করে যারা এতটা যত্নবান হবে না।
— শেডো উইজার্ড আপনার পক্ষে কান

3

আপনি যদি সেই ধরণের হ্যাকের বিরুদ্ধে নিরাপদে খেলতে চান তবে আপনার কাছে কিছু বিকল্প রয়েছে:

প্রথমে আপত্তি জানাতে Cast

আপনি GetType()প্রথমে উদাহরণটি কাস্ট করে মূল পদ্ধতিটি কল করতে পারেন object:

 Console.WriteLine("BadFoo says he's a '{0}'", ((object)badFoo).GetType());

ফলাফল স্বরূপ:

BadFoo says he's a 'ConsoleApplication.BadFoo'

টেমপ্লেট পদ্ধতিটি ব্যবহার করুন

এই টেমপ্লেট পদ্ধতিটি ব্যবহার করে আপনাকে আসল প্রকারটিও দেবে:

static Type GetType<T>(T obj)
{
    return obj.GetType();
}

GetType(badFoo);

2

object.GetTypeএবং মধ্যে পার্থক্য আছে IFoo.GetType। GetTypeসংজ্ঞায়িত অবজেক্টের উপর সংকলন সময়ে বলা হয়, ইন্টারফেসগুলিতে নয়। আপনার উদাহরণে, আউটপুট সহ badFoo.GetTypeএটি বাহাবিউর প্রত্যাশিত, কারণ আপনি পদ্ধতিটি ওভারলোড করেন। কেবলমাত্র এটি হ'ল অন্যান্য প্রোগ্রামাররা এই আচরণ সম্পর্কে বিভ্রান্ত হতে পারে।

তবে আপনি যদি typeof()এটি ব্যবহার করেন তবে ফলাফলটি একই হবে এবং আপনি ওভাররাইট করতে পারবেন না typeof()।

এছাড়াও প্রোগ্রামার সংকলনের সময় দেখতে পাবে যে GetTypeসে কোন পদ্ধতিটি গ্রহণ করে ।

আপনার প্রশ্নের তাই: এই প্যাটার্নটি কোনও বিশ্বাসযোগ্য হুমকি তৈরি করতে পারে না, তবে এটি কোডিংয়ের সর্বোত্তম স্টাইলও নয়।


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