`গোটো ভুডু এড়ানো?


47

আমার একটি switchকাঠামো আছে যা পরিচালনা করতে বেশ কয়েকটি কেস রয়েছে। এটি switchপরিচালনা করে enumযা সংযুক্ত মানগুলির মাধ্যমে সদৃশ কোডের বিষয়টি তুলে ধরে :

// All possible combinations of One - Eight.
public enum ExampleEnum {
    One,
    Two, TwoOne,
    Three, ThreeOne, ThreeTwo, ThreeOneTwo,
    Four, FourOne, FourTwo, FourThree, FourOneTwo, FourOneThree,
          FourTwoThree, FourOneTwoThree
    // ETC.
}

বর্তমানে switchকাঠামো প্রতিটি মান পৃথকভাবে পরিচালনা করে:

// All possible combinations of One - Eight.
switch (enumValue) {
    case One: DrawOne; break;
    case Two: DrawTwo; break;
    case TwoOne:
        DrawOne;
        DrawTwo;
        break;
     case Three: DrawThree; break;
     ...
}

আপনি সেখানে ধারণা পাবেন। ifপরিবর্তে একটি একক লাইনের সংমিশ্রণগুলি হ্যান্ডেল করার জন্য আমি বর্তমানে এটি একটি স্ট্যাক করা কাঠামোতে ভেঙে ফেলেছি :

// All possible combinations of One - Eight.
if (One || TwoOne || ThreeOne || ThreeOneTwo)
    DrawOne;
if (Two || TwoOne || ThreeTwo || ThreeOneTwo)
    DrawTwo;
if (Three || ThreeOne || ThreeTwo || ThreeOneTwo)
    DrawThree;

এটি অবিশ্বাস্যরূপে দীর্ঘ যৌক্তিক মূল্যায়নের বিষয়টি তুলে ধরেছে যা পড়তে বিভ্রান্ত করছে এবং বজায় রাখা কঠিন। এটিকে রিফ্যাক্টর করার পরে আমি বিকল্পগুলির বিষয়ে চিন্তা করতে শুরু করি এবং কেসগুলির switchমধ্যে পতনের মধ্য দিয়ে একটি কাঠামোর ধারণা নিয়ে ভাবতে শুরু করি ।

আমাকে gotoসেই ক্ষেত্রে একটি ব্যবহার করতে হবে যেহেতু C#পতনের মাধ্যমে অনুমতি দেয় না। যাইহোক, এটি অবিশ্বাস্যরূপে দীর্ঘ লজিক চেইনগুলি প্রতিরোধ করে যদিও এটি switchকাঠামোর চারপাশে ঝাঁপিয়ে পড়ে , এবং এটি এখনও কোড নকল নিয়ে আসে।

switch (enumVal) {
    case ThreeOneTwo: DrawThree; goto case TwoOne;
    case ThreeTwo: DrawThree; goto case Two;
    case ThreeOne: DrawThree; goto default;
    case TwoOne: DrawTwo; goto default;
    case Two: DrawTwo; break;
    default: DrawOne; break;
}

এটি এখনও একটি পরিষ্কার যথেষ্ট সমাধান নয় এবং মূল শব্দটির সাথে একটি কলঙ্ক যুক্ত gotoযা আমি এড়াতে চাই। আমি নিশ্চিত যে এটি পরিষ্কার করার আরও ভাল উপায় থাকতে হবে।


আমার প্রশ্ন

পাঠযোগ্যতা এবং রক্ষণাবেক্ষণযোগ্যতা প্রভাবিত না করে এই সুনির্দিষ্ট কেসটি পরিচালনা করার জন্য আরও ভাল উপায় কি?


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

5
@ ইভান কেউ গোটো ব্যবহার করে না। লিনাক্স কার্নেল উত্স কোডটি যখন আপনি সর্বশেষে দেখেছেন?
জন ডৌমা

6
gotoআপনার ভাষাতে যখন উচ্চ স্তরের কাঠামো উপস্থিত না থাকে আপনি ব্যবহার করেন। আমি মাঝে মাঝে ইচ্ছা করতাম যে একটি ছিল fallthru; কীওয়ার্ড gotoতবে সেই বিশেষ ব্যবহার থেকে মুক্তি পেতে পারে তবে ওহ ভাল।
যোশুয়া

25
সাধারণ কথায়, যদি আপনি gotoসি # এর মতো উচ্চ-স্তরের ভাষায় কোনও ভাষা ব্যবহারের প্রয়োজন বোধ করেন তবে আপনি সম্ভবত অন্যান্য অনেক (এবং আরও ভাল) নকশা এবং / বা বাস্তবায়নের বিকল্পগুলি উপেক্ষা করেছেন। অত্যন্ত নিরুৎসাহিত।
কোড_ড্রেড

11
সি # তে "গোটো কেস" ব্যবহার করা আরও সাধারণ "গোটো" ব্যবহার করা থেকে আলাদা, কারণ আপনি কীভাবে সুস্পষ্ট পতন সাধন করেন এটি।
হামারাইট

উত্তর:


175

gotoবিবৃতি দিয়ে কোডটি পড়তে আমি কঠিন অনুভব করি । আমি আপনার enumআলাদাভাবে কাঠামোগত সুপারিশ করব । উদাহরণস্বরূপ, যদি আপনার enumএকটি বিটফিল্ড যেখানে প্রতিটি বিট পছন্দগুলির মধ্যে একটির প্রতিনিধিত্ব করে, এটি দেখতে এটির মতো হতে পারে:

[Flags]
public enum ExampleEnum {
    One = 0b0001,
    Two = 0b0010,
    Three = 0b0100
};

ফ্ল্যাগস অ্যাট্রিবিউট কম্পাইলারকে বলে যে আপনি মানগুলি সেট করছেন যা ওভারল্যাপ হয় না। যে কোডটি এই কোডটি কল করে তা যথাযথ বিট সেট করতে পারে। এরপরে যা ঘটছে তা পরিষ্কার করে দেওয়ার জন্য আপনি এরকম কিছু করতে পারেন:

if (myEnum.HasFlag(ExampleEnum.One))
{
    CallOne();
}
if (myEnum.HasFlag(ExampleEnum.Two))
{
    CallTwo();
}
if (myEnum.HasFlag(ExampleEnum.Three))
{
    CallThree();
}

এর জন্য কোড দরকার যা myEnumবিটফিল্ডগুলি সঠিকভাবে সেট করতে সেট করে এবং পতাকা বৈশিষ্ট্যের সাথে চিহ্নিত করে। তবে আপনি উদাহরণস্বরূপ এনামগুলির মানগুলি পরিবর্তন করে এটি করতে পারেন:

[Flags]
public enum ExampleEnum {
    One = 0b0001,
    Two = 0b0010,
    Three = 0b0100,
    OneAndTwo = One | Two,
    OneAndThree = One | Three,
    TwoAndThree = Two | Three
};

আপনি যখন ফর্মটিতে একটি সংখ্যা লিখবেন 0bxxxx, আপনি বাইনারিটিতে এটি নির্দিষ্ট করছেন। সুতরাং আপনি দেখতে পাচ্ছেন যে আমরা বিট 1, 2, বা 3 সেট করেছি (ভাল, প্রযুক্তিগতভাবে 0, 1, বা 2, তবে আপনি ধারণাটি পাবেন)। আপনি বিটওয়াস ব্যবহার করে সংযোজনগুলির নামও দিতে পারেন বা যদি সংমিশ্রণগুলি প্রায়শই একসাথে সেট করা থাকে।


5
এটা তোলে তাই মনে হচ্ছে, ! তবে এটি অবশ্যই সি # 7.0 বা তার পরে হতে হবে, আমার ধারণা।
ব্যবহারকারী 1118321

31
যাই হোক, এক এছাড়াও এটা ভালো কাজ করতে পারে: public enum ExampleEnum { One = 1 << 0, Two = 1 << 1, Three = 1 << 2, OneAndTwo = One | Two, OneAndThree = One | Three, TwoAndThree = Two | Three };। সি # 7 + তে জোর দেওয়ার দরকার নেই।
ডিসেম্বর


13
[Flags]অ্যাট্রিবিউট কম্পাইলার কিছু সংকেত নেই। এজন্য আপনাকে এখনও এনামের মানগুলিকে 2 এর শক্তি হিসাবে স্পষ্টভাবে ঘোষণা করতে হবে
জো সিওল

19
@ ইউকেমনকি আমি দৃhe়ভাবে একমত নই। HasFlagক্রিয়াকলাপটি সম্পাদনের জন্য একটি বর্ণনামূলক এবং স্পষ্ট শব্দ এবং কার্যকারিতা থেকে বাস্তবায়নকে বিমূর্ত করে তোলে। ব্যবহার &করা হয়েছে কারণ এটি অন্য ভাষাতে সাধারণ একটি ব্যবহার বেশী জ্ঞান করে তোলে byteটাইপ পরিবর্তে একটি ঘোষণা enum
বিজে মায়ার্স

136

আইএমও সমস্যাটির মূলটি হচ্ছে এই কোডের এই অংশটি থাকা উচিত নয়।

স্পষ্টতই আপনার কাছে তিনটি স্বাধীন শর্ত রয়েছে এবং যদি এই শর্তগুলি সত্য হয় তবে তিনটি স্বতন্ত্র পদক্ষেপ নিতে হবে। সুতরাং যে সমস্ত কোডের এক টুকরোটিতে বিভক্ত করা হচ্ছে যার জন্য তিনটি বুলিয়ান পতাকা প্রয়োজন তা কী করতে হবে তা বলার জন্য (আপনি তাদের এনামে আবদ্ধ করেন বা না করেন) এবং তারপরে তিনটি স্বতন্ত্র জিনিসের কিছু সংমিশ্রণ ঘটে? একক দায়িত্বের নীতিটি এখানে অফ-ডে হচ্ছে বলে মনে হচ্ছে।

তিনটি ফাংশনগুলিতে কলগুলি রাখুন যেখানে (যেমন আপনি ক্রিয়াগুলি করার প্রয়োজনীয়তাটি আবিষ্কার করেন) এবং এই উদাহরণগুলিতে কোডটি পুনর্ব্যবহারযোগ্য বিনের সাথে সংযুক্ত করুন।

যদি দশটি পতাকা এবং ক্রিয়া তিনটি না হয়ে থাকে, তবে আপনি 1024 টি বিভিন্ন সংমিশ্রণ পরিচালনা করতে এই ধরণের কোডটি প্রসারিত করবেন? আমি আশা করি না! যদি 1024 খুব বেশি হয় তবে 8 একই কারণে অনেক বেশি।


10
প্রকৃতপক্ষে, অনেকগুলি সু-নকশিত এপিআই রয়েছে যাতে সমস্ত ধরণের পতাকা, বিকল্প এবং বিভিন্ন পরামিতি রয়েছে। কারও কারও পাস করা হতে পারে, কারওর সরাসরি প্রভাব রয়েছে, আবার কেউ কেউ এসআরপি না ভেঙে সম্ভাব্য উপেক্ষা করতে পারেন। যাইহোক, ফাংশন এমনকি কিছু বাহ্যিক ইনপুট ডিকোডিং হতে পারে, কে জানে? এছাড়াও, হ্রাস বিজ্ঞাপন অ্যাডসারডাম প্রায়শই অযৌক্তিক ফলাফলের দিকে পরিচালিত করে, বিশেষত যদি প্রারম্ভকালীন পয়েন্টটি এতটা শক্ত না হয়।
Deduplicator

9
এই উত্তর upvated। আপনি যদি GOTO নিয়ে কেবল বিতর্ক করতে চান তবে এটি আপনার জিজ্ঞাসা করা প্রশ্নের চেয়ে আলাদা প্রশ্ন। উপস্থাপিত প্রমাণের ভিত্তিতে, আপনার তিনটি ভিন্নতা প্রয়োজন, যা একত্রিত করা উচিত নয়। এসই দৃষ্টিকোণ থেকে, আমি জমা দিচ্ছি যে অ্যালেফজেরো সঠিক উত্তর।

8
@ ডেডুকিপ্লেটর কিছুতে এই মিশম্যাশের দিকে নজর দিন তবে 1,2 এবং 3 এর সমস্ত সংমিশ্রণ দেখায় না যে এটি একটি "ভাল ডিজাইন করা এপিআই" নয়।
user949300

4
এই এত। অন্যান্য উত্তরগুলি প্রশ্নের মধ্যে যা আছে তাতে সত্যিকারের উন্নতি হয় না। এই কোডটির একটি পুনর্লিখন দরকার। আরও ফাংশন লেখার ক্ষেত্রে কোনও ভুল নেই।
22_9

3
আমি এই উত্তরটি পছন্দ করি, বিশেষত "1024 যদি খুব বেশি হয় তবে 8 টিও অনেক বেশি"। তবে এটি মূলত "পলিমারফিজম ব্যবহার করুন", তাই না? এবং আমার (দুর্বল) উত্তরটি বলার জন্য প্রচুর জঞ্জাল পাচ্ছে। আমি কি আপনার জন ব্যক্তিকে ভাড়া করতে পারি? :-)
user949300

29

কম্পিউটার বিজ্ঞানের অন্যতম "শিশুদের কাছে মিথ্যা" ধারণাগুলির মধ্যে গোটোস ব্যবহার করবেন না । এটি 99% সময়ই সঠিক পরামর্শ এবং এটি যে সময়গুলি হয় তা এত বিরল এবং বিশেষায়িত যে এটি কেবল নতুন কোডারগুলিকে "তাদের ব্যবহার করবেন না" হিসাবে ব্যাখ্যা করা হলে এটি তার চেয়ে অনেক ভাল।

সুতরাং তারা কখন ব্যবহার করা উচিত ? আছে কয়েক পরিস্থিতিতে , কিন্তু মৌলিক আপনি আঘাত হবে বলে মনে হচ্ছে হল: যখন আপনি একটি রাষ্ট্র মেশিন কোডিং করছি । যদি কোনও রাজ্য মেশিনের চেয়ে আপনার অ্যালগরিদমের আরও সুসংগঠিত এবং কাঠামোগত অভিব্যক্তি না থাকে, তবে কোডে তার প্রাকৃতিক অভিব্যক্তিটি অস্ট্রাস্ট্রাক্ট শাখাগুলির সাথে জড়িত, এবং এমন কোনও কিছুই করা যায় না যা তর্কসাপেক্ষভাবে কাঠামোর গঠন করে না রাষ্ট্র মেশিন নিজেই আরও কম অস্পষ্ট।

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

* - আইআইআরসি, টেবিলগুলি বা অন্য কাঠামোগত নিয়ন্ত্রণের বিবৃতিগুলিতে ঝাঁপ না দিয়ে এলএলএল ব্যাকরণগুলি সম্পূর্ণ পুনরাবৃত্ত-বংশোদ্ভূত করা সম্ভব, সুতরাং যদি আপনি সত্যিকার অর্থে বিরোধী হন তবে এটি এক উপায়।


এখন পরের প্রশ্নটি হ'ল "এই উদাহরণটি কি সেই মামলার মধ্যে একটি?"

আমি এটি সন্ধান করতে যা দেখছি তা হ'ল বর্তমান রাষ্ট্রের প্রক্রিয়াকরণের উপর নির্ভর করে আপনার কাছে তিনটি পৃথক সম্ভাব্য পরবর্তী রাজ্য রয়েছে। যেহেতু তাদের মধ্যে একটি ("ডিফল্ট") কোডের একটি লাইন, প্রযুক্তিগতভাবে আপনি কোডগুলি লাইনটি প্রযোজ্য রাষ্ট্রগুলির শেষের দিকে ফাঁকি দিয়ে তা থেকে মুক্তি পেতে পারেন। এটি আপনাকে পরবর্তী 2 টি রাজ্যে নামিয়ে আনবে।

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

switch (exampleValue) {
    case OneAndTwo: i += 3 break;
    case OneAndThree: i += 4 break;
    case Two: i += 2 break;
    case TwoAndThree: i += 5 break;
    case Three: i += 3 break;
    default: i++ break;
}

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


2
@ প্রিপুটুয়ালজে - ভাল, আপনি অবশ্যই কিছু ক্লিনার পেয়েছেন বলে আমি অবশ্যই আনন্দিত। এটি এখনও আকর্ষণীয় হতে পারে, যদি সত্যিই এটি আপনার পরিস্থিতি হয় তবে এটি গোটোসের সাথে চেষ্টা করে দেখুন (কোনও মামলা বা এনাম না। বলা হচ্ছে, "গোটো" বিকল্পটি কেবল বেশি পাঠযোগ্য হতে হবে না, তবে অন্যান্য বিকাশকারীদের তর্ক এবং হাম-হ্যান্ড হ্যান্ড হ্যান্ড হ্যান্ড হ্যান্ড হ্যান্ড-হ্যান্ড হ্যান্ড হ্যান্ড-হ্যান্ড-হ্যান্ড "হ্যান্ড হ্যান্ড" প্রচেষ্টা যথেষ্ট পরিমাণে পাঠযোগ্য so
টেড

4
আমি অস্বীকার করি যে "যদি আরও রক্ষণাবেক্ষণের ফলে রাজ্যগুলিকে যুক্ত বা জটিল করার সম্ভাবনা থাকে তবে আপনি" গোটোস ব্যবহার করা ভাল "। আপনি কি সত্যিই দাবি করছেন যে কাঠামোগত কোডের চেয়ে স্প্যাগেটি কোড বজায় রাখা আরও সহজ? এটি অনুশীলনের 40 ডলারের বিপরীতে যায়।
user949300

5
@ ব্যবহারকারী949300 - রাষ্ট্রীয় মেশিন তৈরির বিরুদ্ধে অনুশীলন করছেন না, তা হয় না। বাস্তব জগতের উদাহরণের জন্য আপনি এই উত্তরটিতে আমার পূর্ববর্তী মন্তব্যটি সহজেই পড়তে পারেন। যদি আপনি সি কেস ফলস-থ্রোসগুলি ব্যবহার করার চেষ্টা করেন যা কোনও রাষ্ট্রীয় মেশিন অ্যালগরিদমের উপর একটি কৃত্রিম কাঠামো (তাদের রৈখিক ক্রম) চাপায় যা সহজাতভাবে এই জাতীয় কোনও বিধিনিষেধ নেই, আপনি প্রতিবার আপনার সমস্ত পুনর্বিন্যাস করতে গিয়ে জ্যামিতিকভাবে ক্রমবর্ধমান জটিলতার সাথে নিজেকে খুঁজে পাবেন একটি নতুন রাষ্ট্রের থাকার জন্য আদেশ। যদি আপনি কেবল অ্যালগরিদমকে কল করার মতো, রাজ্যগুলি এবং ট্রানজিশনগুলি কোড করেন তবে তা ঘটে না। নতুন রাজ্য যুক্ত করতে তুচ্ছ।
টেড

8
@ ব্যবহারকারী949300 - আবার, "40 বছরের অনুশীলন" বিল্ডিং সংকলকগুলি দেখায় যে গোটোস আসলে সেই সমস্যা ডোমেনের অংশগুলির জন্য সর্বোত্তম উপায় which এজন্য আপনি যদি সংকলক উত্স কোডটি দেখেন তবে আপনি প্রায় সর্বদা গোটোস খুঁজে পাবেন।
টেড

3
@ ব্যবহারকারী949300 স্প্যাগেটি কোড নির্দিষ্ট ফাংশন বা কনভেনশন ব্যবহার করার সময় কেবল সহজাতভাবে উপস্থিত হয় না। এটি যে কোনও সময় কোনও ভাষা, ফাংশন বা কনভেনশনে উপস্থিত হতে পারে। কারণটি কোনও অ্যাপ্লিকেশনটিতে বলা ভাষা, ফাংশন বা কনভেনশন ব্যবহার করছে যা এটি উদ্দেশ্য করে নয় এবং এটিকে টানতে পিছনের দিকে বাঁকানো। কাজের জন্য সর্বদা সঠিক সরঞ্জামটি ব্যবহার করুন এবং হ্যাঁ, কখনও কখনও এর অর্থ ব্যবহার করা goto
Abion47

26

সর্বোত্তম উত্তরটি হ'ল পলিমারফিজম ব্যবহার

আর একটি উত্তর, যা, আইএমও, যদি স্টাফকে আরও পরিষ্কার এবং তর্কযোগ্যভাবে ছোট করে তোলে :

if (One || OneAndTwo || OneAndThree)
  CallOne();
if (Two || OneAndTwo || TwoAndThree)
  CallTwo();
if (Three || OneAndThree || TwoAndThree)
  CallThree();

goto সম্ভবত এখানে আমার 58 তম পছন্দ ...


5
পলিমারফিজমের পরামর্শ দেওয়ার জন্য +1, যদিও আদর্শভাবে এটি ক্লায়েন্ট কোডটি কেবল "কল ();" এ নামিয়ে দিতে পারে, বলুন না জিজ্ঞাসা করে - গ্রাহক ক্লায়েন্ট থেকে ক্লাসের পদ্ধতি এবং শ্রেণিবিন্যাসের দিকে সিদ্ধান্তের যুক্তিটিকে দূরে সরিয়ে দেয়।
এরিক tদ

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

বাহ, আমি মনে করি পলিমারফিজমের পরামর্শ দেওয়ার জন্য এটিই প্রথমবারের মতো অগ্রাহ্য হয়েছিল। :-)
user949300

25
কিছু লোক, যখন কোনও সমস্যার মুখোমুখি হন, তখন "আমি কেবল পলিমারফিজম ব্যবহার করব" বলে। এখন তাদের দুটি সমস্যা আছে, এবং পলিমারফিজম।
মনিকার সাথে লাইটনেস রেস

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

10

কেন এটি না:

public enum ExampleEnum {
    One = 0, // Why not?
    OneAndTwo,
    OneAndThree,
    Two,
    TwoAndThree,
    Three
}
int[] COUNTS = { 1, 3, 4, 2, 5, 3 }; // Whatever

int ComputeExampleValue(int i, ExampleEnum exampleValue) {
    return i + COUNTS[(int)exampleValue];
}

ঠিক আছে, আমি সম্মতি জানাই, এটি হ্যাকিশ (আমি সি # বিকাশকারী বিটিডব্লু নই, সুতরাং কোডটির জন্য আমাকে ক্ষমা করুন), তবে দক্ষতার দৃষ্টিকোণ থেকে এটি অবশ্যই করা উচিত? অ্যারে সূচক হিসাবে এনামগুলি ব্যবহার করা বৈধ সি #।


3
হ্যাঁ. ডেটা দিয়ে কোড প্রতিস্থাপনের আরেকটি উদাহরণ (যা সাধারণত গতি, কাঠামো এবং রক্ষণাবেক্ষণের জন্য পছন্দসই)।
পিটার - মনিকা

2
এটি প্রশ্নের সাম্প্রতিকতম সংস্করণের জন্য একটি দুর্দান্ত ধারণা, সন্দেহ নেই। এবং এটি প্রথম এনাম (মানগুলির একটি ঘন পরিসীমা) থেকে কম-বেশি স্বাধীন ক্রিয়াকলাপগুলির পতাকাগুলিতে যেতে ব্যবহার করা যেতে পারে যা সাধারণভাবে করতে হবে।
Deduplicator

আমি সি # কম্পাইলার এক্সেস আছে না, কিন্তু হয়তো কোড কোড এই ধরনের ব্যবহার নিরাপদ তৈরি করা যেতে পারে: int[ExempleEnum.length] COUNTS = { 1, 3, 4, 2, 5, 3 };?
লরেন্ট গ্রোগোয়ার

7

আপনি যদি পতাকা ব্যবহার করতে বা না করতে চান তবে একটি লেজ পুনরাবৃত্ত ফাংশন ব্যবহার করুন। Bit৪ বিট রিলিজ মোডে, সংকলকটি কোড তৈরি করবে যা আপনার gotoবক্তব্যের সাথে খুব মিল । আপনার কেবল এটি মোকাবেলা করার দরকার নেই।

int ComputeExampleValue(int i, ExampleEnum exampleValue) {
    switch (exampleValue) {
        case One: return i + 1;
        case OneAndTwo: return ComputeExampleValue(i + 2, ExampleEnum.One);
        case OneAndThree: return ComputeExampleValue(i + 3, ExampleEnum.One);
        case Two: return i + 2;
        case TwoAndThree: return ComputeExampleValue(i + 2, ExampleEnum.Three);
        case Three: return i + 3;
   }
}

এটি একটি অনন্য সমাধান! +1 আমি মনে করি না এইভাবে আমার এটি করা দরকার তবে ভবিষ্যতের পাঠকদের জন্য দুর্দান্ত!
PerpetualJ

2

গৃহীত সমাধানটি ভাল এবং এটি আপনার সমস্যার একটি দৃ concrete় সমাধান। তবে, আমি একটি বিকল্প, আরও বিমূর্ত সমাধান পোষ্ট করতে চাই।

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

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

আবারও, আমার অবশ্যই বলতে হবে যে যুক্তির প্রবাহ নিয়ন্ত্রণ করতে এনামগুলি ব্যবহার করা প্রায়শই ডিজাইনের সমস্যা is সাধারণ ক্ষেত্রে, এনামগুলি বেশিরভাগ টাইপ-নিরাপদ, গ্রাহক-বান্ধব মান প্রদানের জন্য ব্যবহার করা উচিত যেখানে সম্ভাব্য মানগুলি পরিষ্কারভাবে সংজ্ঞায়িত করা হয়। এগুলি যুক্তি নিয়ন্ত্রণ ব্যবস্থা ব্যবহারের চেয়ে সম্পত্তি হিসাবে (উদাহরণস্বরূপ, কোনও টেবিলের কলাম আইডি হিসাবে) ভাল ব্যবহার করা হয়।

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

যাইহোক, এনাম বিবেচনা করুন:

// All possible combinations of One - Eight.
public enum ExampleEnum {
    One,
    Two,
    TwoOne,
    Three,
    ThreeOne,
    ThreeTwo,
    ThreeOneTwo
}

আমাদের এখানে যা আছে তা হ'ল বিভিন্ন এনাম মান যা বিভিন্ন ব্যবসায়িক ধারণার প্রতিনিধিত্ব করে।

পরিবর্তে আমরা যা ব্যবহার করতে পারি তা হ'ল জিনিসগুলি সরল করার জন্য বিমূর্ততা।

আসুন নীচের ইন্টারফেসটি বিবেচনা করুন:

public interface IExample
{
  void Draw();
}

এরপরে আমরা এটি একটি বিমূর্ত শ্রেণি হিসাবে প্রয়োগ করতে পারি:

public abstract class ExampleClassBase : IExample
{
  public abstract void Draw();
  // other common functionality defined here
}

একটি অঙ্কন ওয়ান, দুই এবং তিনটি উপস্থাপন করার জন্য আমাদের কাছে একটি কংক্রিট শ্রেণি থাকতে পারে (যা তর্কের পক্ষে বিভিন্ন যুক্তিযুক্ত রয়েছে)। এগুলি উপরের সংজ্ঞায়িত বেস ক্লাসটি ব্যবহার করতে পারে তবে আমি ধরে নিচ্ছি যে ড্রইন ধারণা এনাম দ্বারা উপস্থাপিত ধারণা থেকে আলাদা:

public class DrawOne
{
  public void Draw()
  {
    // Drawing logic here
  }
}

public class DrawTwo
{
  public void Draw()
  {
    // Drawing two logic here
  }
}

public class DrawThree
{
  public void Draw()
  {
    // Drawing three logic here
  }
}

এবং এখন আমাদের তিনটি পৃথক ক্লাস রয়েছে যা অন্যান্য শ্রেণীর জন্য যুক্তি সরবরাহ করার জন্য রচনা করা যেতে পারে।

public class One : ExampleClassBase
{
  private DrawOne drawOne;

  public One(DrawOne drawOne)
  {
    this.drawOne = drawOne;
  }

  public void Draw()
  {
    this.drawOne.Draw();
  }
}

public class TwoOne : ExampleClassBase
{
  private DrawOne drawOne;
  private DrawTwo drawTwo;

  public One(DrawOne drawOne, DrawTwo drawTwo)
  {
    this.drawOne = drawOne;
    this.drawTwo = drawTwo;
  }

  public void Draw()
  {
    this.drawOne.Draw();
    this.drawTwo.Draw();
  }
}

// the other six classes here

এই পদ্ধতির অনেক বেশি ভারবস হয়। তবে এর সুবিধাও আছে।

নিম্নলিখিত ক্লাসটি বিবেচনা করুন, এতে একটি বাগ রয়েছে:

public class ThreeTwoOne : ExampleClassBase
{
  private DrawOne drawOne;
  private DrawTwo drawTwo;
  private DrawThree drawThree;

  public One(DrawOne drawOne, DrawTwo drawTwo, DrawThree drawThree)
  {
    this.drawOne = drawOne;
    this.drawTwo = drawTwo;
    this.drawThree = drawThree;
  }

  public void Draw()
  {
    this.drawOne.Draw();
    this.drawTwo.Draw();
  }
}

অনুপস্থিত ড্র থ্রি.ড্রে () কলটি পাওয়া কত সহজ? এবং যদি অর্ডার গুরুত্বপূর্ণ হয় তবে ড্র কলগুলির ক্রমটি দেখতে এবং অনুসরণ করা খুব সহজ।

এই পদ্ধতির অসুবিধা:

  • উপস্থাপিত আটটি বিকল্পের প্রত্যেকটির জন্য একটি পৃথক শ্রেণির প্রয়োজন
  • এটি আরও মেমরি ব্যবহার করবে
  • এটি আপনার কোডকে উচ্চতর আকারে আরও বড় করে তুলবে
  • কখনও কখনও এই পদ্ধতির পক্ষে সম্ভব হয় না, যদিও এটিতে কিছু ভিন্নতা থাকতে পারে

এই পদ্ধতির সুবিধা:

  • এই ক্লাসগুলির প্রতিটি সম্পূর্ণ পরীক্ষামূলক; কারণ
  • ড্র পদ্ধতিগুলির চক্রবৃত্তীয় জটিলতা কম (এবং তাত্ত্বিকভাবে আমি প্রয়োজন হলে ড্রইন, ড্রও বা ড্র থ্রি ক্লাসগুলি উপহাস করতে পারি)
  • অঙ্কনের পদ্ধতিগুলি বোধগম্য - কোনও বিকাশকারীকে পদ্ধতিটি কী কাজ করে তা নট করে তাদের মস্তিষ্ক বেঁধে রাখতে হবে না
  • বাগগুলি স্পট করা সহজ এবং লেখা শক্ত
  • ক্লাসগুলি আরও উচ্চ স্তরের শ্রেণিতে রচনা করে, যার অর্থ একটি তিনত্রে তিনটি শ্রেণীর সংজ্ঞা দেওয়া সহজ

যখনই আপনি কেস স্টেটমেন্টগুলিতে কোনও জটিল লজিক কন্ট্রোল কোড লেখার প্রয়োজন বোধ করেন তখন এই (বা অনুরূপ) পদ্ধতির বিষয়টি বিবেচনা করুন। ভবিষ্যতে আপনি খুশী হবেন


এটি একটি খুব ভাল লিখিত উত্তর এবং আমি পদ্ধতির সাথে সম্পূর্ণ সম্মত agree আমার বিশেষ ক্ষেত্রে এই ভার্বোস প্রতিটিটির পিছনে তুচ্ছ কোড বিবেচনা করে অসীম ডিগ্রিকে ছাড়িয়ে যাবে। এটিকে দৃষ্টিকোণে রাখতে, কল্পনা করুন যে কোডটি কেবল একটি কনসোল করছে performing রাইটলাইন (এন)। এটি কার্যত কোডটি যা আমি কাজ করেছিলাম তার সমতুল্য। অন্যান্য সমস্ত ক্ষেত্রে 90% এর মধ্যে, ওওপি অনুসরণ করার পরে আপনার সমাধানটি অবশ্যই সেরা উত্তর।
পেরেপুটুয়াল

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

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

0

আপনি যদি এখানে একটি স্যুইচ ব্যবহার করতে চান তবে আপনি যদি প্রতিটি কেস পৃথকভাবে পরিচালনা করেন তবে আপনার কোডটি আসলে আরও দ্রুত হবে

switch(exampleValue)
{
    case One:
        i++;
        break;
    case Two:
        i += 2;
        break;
    case OneAndTwo:
    case Three:
        i+=3;
        break;
    case OneAndThree:
        i+=4;
        break;
    case TwoAndThree:
        i+=5;
        break;
}

প্রতিটি ক্ষেত্রে একটিমাত্র গাণিতিক অপারেশন করা হয়

এছাড়াও অন্যরা যেমন বলেছে যে আপনি গোটোস ব্যবহারের কথা বিবেচনা করছেন আপনার সম্ভবত আপনার অ্যালগরিদমটি নিয়ে পুনর্বিবেচনা করা উচিত (যদিও আমি স্বীকার করব যে সি # এর ক্ষেত্রে পতনের অভাব যদিও গোটো ব্যবহারের কারণ হতে পারে)। এডগার ডিজকস্ট্রার বিখ্যাত কাগজ "ক্ষতিকারক হিসাবে বিবেচিত বিবৃতিতে যান" দেখুন


3
আমি বলব যে এটি সহজ বিষয়টির সাথে মোকাবিলা করা কারও পক্ষে একটি দুর্দান্ত ধারণা তাই এটি পোস্ট করার জন্য আপনাকে ধন্যবাদ। আমার ক্ষেত্রে এটি এত সহজ নয়।
পার্পেটিউলে

এছাড়াও, এডগার তাঁর কাগজ লেখার সময় আমাদের যে সমস্যা ছিল তা আজ আমাদের ঠিক ঠিক নেই; আজকাল বেশিরভাগ লোকের কাছে এটিকে বাদ দিয়ে গোটোকে ঘৃণা করার বৈধ কারণও নেই, কোড পড়াই শক্ত করে তোলে। ভাল, সমস্ত সততার সাথে, যদি এটি আপত্তিজনক হয় তবে হ্যাঁ, অন্যথায় এটি ধারণ পদ্ধতিতে আটকা পড়েছে যাতে আপনি সত্যিই স্প্যাগেটি কোড তৈরি করতে পারবেন না। কোনও ভাষার বৈশিষ্ট্যকে ঘিরে কাজ করার জন্য প্রচেষ্টা কেন ব্যয় করবেন? আমি বলব যে গোটো প্রত্নতাত্ত্বিক এবং আপনার ব্যবহারের 99% ক্ষেত্রে অন্যান্য সমাধানের কথা চিন্তা করা উচিত; তবে আপনার যদি এটির প্রয়োজন হয় তবে এটি এখানে।
পার্পেটিউলে

যখন অনেক বুলিয়ান থাকে তখন এটি ভাল স্কেল হবে না।
user949300

0

আপনার নির্দিষ্ট উদাহরণের জন্য, যেহেতু আপনি গণনা থেকে সমস্ত সত্যই চেয়েছিলেন তা প্রতিটি পদক্ষেপের জন্য করণীয় / করণ নির্দেশক ছিল, সুতরাং আপনার তিনটি ifবক্তব্য পুনর্লিখনের সমাধানটি একটির চেয়ে পছন্দনীয় switch, এবং এটি ভাল যে আপনি এটি গ্রহণযোগ্য উত্তর দিয়েছেন ।

কিন্তু যদি আপনি আরো কিছু জটিল লজিক যে হয়নি ফেলা না তাই পরিচ্ছন্নভাবে কাজ, তারপর আমি এখনও এটি gotoমধ্যে গুলি switchবিবৃতি বিভ্রান্তিকর। আমি বরং এরকম কিছু দেখতে চাই:

switch (enumVal) {
    case ThreeOneTwo: DrawThree; DrawTwo; DrawOne; break;
    case ThreeTwo:    DrawThree; DrawTwo; break;
    case ThreeOne:    DrawThree; DrawOne; break;
    case TwoOne:      DrawTwo; DrawOne; break;
    case Two:         DrawTwo; break;
    default:          DrawOne; break;
}

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


0

আমি নিশ্চিত নই যে এই দিনগুলিতে গোটো কীওয়ার্ডটি ঘৃণার সত্যই কারও কারও আছে। এটি অবশ্যই প্রত্নতাত্ত্বিক এবং ব্যবহারের 99% ক্ষেত্রে প্রয়োজন হয় না, তবে এটি একটি কারণের জন্য ভাষার বৈশিষ্ট্য।

gotoকীওয়ার্ডটিকে ঘৃণার কারণ কোডের মতো

if (someCondition) {
    goto label;
}

string message = "Hello World!";

label:
Console.WriteLine(message);

ওহো! এটি পরিষ্কারভাবে কাজ করবে না। messageপরিবর্তনশীল যে কোড পাথ সংজ্ঞায়িত করা হয় না। সুতরাং সি # যে পাস করবে না। তবে এটি অন্তর্নিহিত হতে পারে। বিবেচনা

object.setMessage("Hello World!");

label:
object.display();

এবং ধরে নিন যে displayতারপরে এতে WriteLineবিবৃতি রয়েছে।

এই ধরণের বাগটি খুঁজে পাওয়া কঠিন কারণ gotoকোডের পথটিকে অস্পষ্ট করে।

এটি একটি সরল উদাহরণ। ধরে নিন যে একটি বাস্তব উদাহরণ প্রায় হিসাবে সুস্পষ্ট হবে না। এর মধ্যে label:এবং এর ব্যবহারের মধ্যে পঞ্চাশটি কোড থাকতে পারে message

কীভাবে gotoব্যবহার করা যায় তা সীমাবদ্ধ করে ভাষা কেবল এটি ব্লক থেকে নেমে আসতে সমাধান করতে সহায়তা করে । তবে সি # এর gotoমতো সীমাবদ্ধ নয়। এটি কোডের ওপরে লাফিয়ে উঠতে পারে। আরও, যদি আপনি সীমাবদ্ধ করতে চলেছেন gotoতবে নামটি পরিবর্তন করা ঠিক তেমনি। অন্যান্য ভাষাগুলি breakব্লকের বাইরে নেমে যাওয়ার জন্য ব্যবহার করে , হয় একটি নম্বর (প্রস্থান করার জন্য ব্লকের) বা একটি লেবেল (ব্লকের একটিতে)।

ধারণাটি gotoহ'ল নিম্ন স্তরের মেশিন ভাষার নির্দেশ is তবে আমাদের উচ্চ স্তরের ভাষা থাকার পুরো কারণটি হ'ল আমরা উচ্চ স্তরের বিমূর্ততাগুলিতে সীমাবদ্ধ, যেমন পরিবর্তনশীল সুযোগ।

সব যে বলেন, আপনি যদি C # এর ব্যবহার gotoএকটি ভিতরে switchবিবৃতি ঝাঁপ দাও মামলা থেকে ক্ষেত্রে, এটা যুক্তিসঙ্গতভাবে নিরীহ না। প্রতিটি কেস ইতিমধ্যে একটি এন্ট্রি পয়েন্ট। আমি এখনও মনে করি যে এটিকে কল করা gotoসেই পরিস্থিতিতে নির্বোধ, কারণ এটি এই ক্ষতিকারক ব্যবহারকে gotoআরও বিপজ্জনক রূপের সাথে সংযুক্ত করে। আমি বরং এটি চাই যে তারা এর জন্য কিছু continueব্যবহার করবে। তবে কোনও কারণে তারা ভাষা লেখার আগে আমাকে জিজ্ঞাসা করতে ভুলে গিয়েছিল।


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

0

যখন আপনার কাছে এই অনেক পছন্দ (এবং আরও বেশি, যেমনটি আপনি বলেছেন) থাকে, তবে সম্ভবত এটি কোড নয় ডেটা।

ক্রিয়া হিসাবে প্রকাশিত এনাম মানগুলিকে মেকিংয়ের একটি অভিধান তৈরি করুন, ক্রিয়া হিসাবে বা সরল এনাম প্রকারের প্রতিনিধিত্ব করে। তারপরে আপনার কোডটি একটি সাধারণ অভিধান অনুসন্ধানে সিদ্ধ করা যেতে পারে, তারপরে ফাংশনটির মান বা সরলিকৃত পছন্দগুলিতে একটি স্যুইচ কল করে।


-7

একটি লুপ এবং বিরতি এবং অবিরত মধ্যে পার্থক্য ব্যবহার করুন।

do {
  switch (exampleValue) {
    case OneAndTwo: i += 2; break;
    case OneAndThree: i += 3; break;
    case Two: i += 2; continue;
    case TwoAndThree: i += 2;
    // dropthrough
    case Three: i += 3; continue;
    default: break;
  }
  i++;
} while(0);
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.