সি # স্যুইচ স্টেটমেন্টটি আইগনোর কেসটি কীভাবে ব্যবহার করবেন


92

আমার যদি যদি একটি স্যুইচ-কেস স্টেটমেন্ট থাকে যেখানে স্যুইচটিতে থাকা অবজেক্টটি স্ট্রিং করে থাকে, তাহলে কি একটি উপেক্ষাক্যাসের তুলনা করা সম্ভব?

আমি উদাহরণস্বরূপ আছে:

string s = "house";
switch (s)
{
  case "houSe": s = "window";
}

হবে sমান "উইন্ডো" পেতে? আমি কীভাবে স্যুইচ-কেস স্টেটমেন্টকে ওভাররাইড করব তাই এটি উপেক্ষা করে কেস ব্যবহার করে স্ট্রিংগুলির তুলনা করবে?

উত্তর:


64

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

দুর্ভাগ্যক্রমে, switchএকটি সাধারণ তুলনা ছাড়া কিছুই করে না। কিছু ধরণের অ্যাপ্লিকেশনের জন্য অরডিনাল তুলনাটি সূক্ষ্ম, যেমন কঠোরভাবে সংজ্ঞায়িত কোডগুলির সাথে একটি ASCII ফাইলটি পার্স করা হয়, তবে বেশিরভাগ অন্যান্য ব্যবহারের জন্য সাধারণ স্ট্রিং তুলনাটি ভুল।

আমি সঠিক আচরণ পেতে অতীতে যা করেছি তা হ'ল আমার নিজস্ব সুইচ স্টেটমেন্টটি উপহাস করা। এটি করার প্রচুর উপায় রয়েছে। একটি উপায় List<T>হ'ল এক জোড়া কেস স্ট্রিং এবং প্রতিনিধি তৈরি করা। সঠিক স্ট্রিং তুলনা ব্যবহার করে তালিকাটি অনুসন্ধান করা যেতে পারে। ম্যাচটি খুঁজে পাওয়া গেলে তখন সংশ্লিষ্ট প্রতিনিধিদের ডেকে আনা যেতে পারে।

আরেকটি বিকল্প হ'ল ifবিবৃতিগুলির স্পষ্ট চেইন করা । এটি সাধারণত এটি যতটা শোনাচ্ছে ততটা খারাপ হয় নি, কারণ কাঠামোটি খুব নিয়মিত।

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

যদি তুলনা করার মতো অনেকগুলি ক্ষেত্রে থাকে এবং পারফরম্যান্স একটি সমস্যা হয়, তবে List<T>উপরে বর্ণিত বিকল্পটি বাছাই করা অভিধান বা হ্যাশ টেবিলের সাথে প্রতিস্থাপন করা যেতে পারে। তারপরে পারফরম্যান্সটি স্যুইচ স্টেটমেন্ট অপশনটি সম্ভবত মেলা বা অতিক্রম করতে পারে।

প্রতিনিধিদের তালিকার উদাহরণ এখানে:

delegate void CustomSwitchDestination();
List<KeyValuePair<string, CustomSwitchDestination>> customSwitchList;
CustomSwitchDestination defaultSwitchDestination = new CustomSwitchDestination(NoMatchFound);
void CustomSwitch(string value)
{
    foreach (var switchOption in customSwitchList)
        if (switchOption.Key.Equals(value, StringComparison.InvariantCultureIgnoreCase))
        {
            switchOption.Value.Invoke();
            return;
        }
    defaultSwitchDestination.Invoke();
}

অবশ্যই, আপনি সম্ভবত কিছু স্ট্যান্ডার্ড প্যারামিটার এবং কাস্টমসুইচডেস্টিনেশন প্রতিনিধিটিতে একটি রিটার্ন টাইপ যুক্ত করতে চান। এবং আপনি আরও ভাল নাম করতে চাইবেন!

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

    if (s.Equals("house", StringComparison.InvariantCultureIgnoreCase))
    {
        s = "window";
    }
    else if (s.Equals("business", StringComparison.InvariantCultureIgnoreCase))
    {
        s = "really big window";
    }
    else if (s.Equals("school", StringComparison.InvariantCultureIgnoreCase))
    {
        s = "broken window";
    }

6
আমার ভুল না হলে দু'টি নির্দিষ্ট সংস্কৃতিতে (যেমন তুর্কি) আলাদা, এবং সে ক্ষেত্রে সে ব্যবহার করতে পারে না ToUpperInvariant()বা করতে পারে না ToLowerInvariant()? এছাড়াও, তিনি দুটি অজানা স্ট্রিংয়ের তুলনা করছেন না , তিনি একটি অজানা স্ট্রিংকে একটি পরিচিত স্ট্রিংয়ের সাথে তুলনা করছেন। সুতরাং, যতক্ষণ না তিনি উপযুক্ত ওপরের বা লোয়ার কেস উপস্থাপনের জন্য হার্ডকোড করতে জানেন ততক্ষণ স্যুইচ ব্লকের কাজ করা উচিত work
শেঠ পেট্রি-জনসন

8
@ শেঠ পেট্রি-জনসন - সম্ভবত যে অপ্টিমাইজেশান তৈরি করা যেতে পারে, তবে স্ট্রিং তুলনার বিকল্পগুলি কাঠামোর মধ্যে বেক করার কারণ তাই সঠিক, এক্সটেনসিবল সফ্টওয়্যার লেখার জন্য আমাদের সকলকে ভাষাতত্ত্ব বিশেষজ্ঞ হতে হবে না।
জেফ্রি এল হুইলেটজ

59
ঠিক আছে. আমি যেখানে উদাহরণস্বরূপ একটি উদাহরণ দেব। ধরুন "বাড়ি" এর পরিবর্তে আমাদের কাছে (ইংরেজি!) শব্দ "ক্যাফে" রয়েছে। "ক্যাফে 00 u00E9" বা "ক্যাফে 0 u0301" দ্বারা এই মানটি সমানভাবে (এবং সমানভাবে সম্ভবত) প্রতিনিধিত্ব করতে পারে। সাধারণ সাম্যতা (যেমন একটি স্যুইচ স্টেটমেন্ট হিসাবে) হয় ToLower()বা ToLowerInvariant()মিথ্যা ফিরে আসবে। সত্য ফিরে আসবে Equalsসঙ্গে StringComparison.InvariantCultureIgnoreCase। যেহেতু প্রদর্শিত উভয় ক্রম দুটি একইরকম দেখায়, ToLower()সংস্করণটি ট্র্যাক ডাউন করার জন্য একটি বাজে বাগ। এ কারণেই আপনি তুর্কি না হলেও যথাযথ স্ট্রিং তুলনা করা ভাল।
জেফ্রি এল হুইলেটজ

78

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

প্রকৃতপক্ষে, খাঁটি চরম ন্যানোসেকেন্ডের পারফরম্যান্সের অবস্থান থেকে উপরেরটি কিছুটা ভাল তবে দেখতে খুব কম স্বাভাবিক।

যেমন:

string s = "house"; 
switch (s.ToLower()) { 
  case "house": 
    s = "window"; 
    break;
}

4
হ্যাঁ, আমি বুঝতে পেরেছি যে লোয়ারক্যাসিং একটি উপায়, তবে আমি এটি থেকে উপেক্ষা করা উচিত। এমন কোনও উপায় আছে যে আমি স্যুইচ-কেস স্টেটমেন্টকে ওভাররাইড করতে পারি?
তোলসান

6
@Lazarus - এই হয় মাধ্যমে CLR থেকে সি #, তা এখানে পোস্ট করা হয়েছে একটি সময় গোপন বৈশিষ্ট্য থ্রেড ফিরে পাশাপাশি: stackoverflow.com/questions/9033/hidden-features-of-c/... আপনি কয়েক সঙ্গে LinqPad ব্যবহার বাড়িয়ে দিতে পারেন মিলিয়ন পুনরাবৃত্তি, সত্য ধরে।
নিক ক্র্যাভার

4
@ তোলসান - না, দুর্ভাগ্যক্রমে কেবল স্থির প্রকৃতির কারণে নয়। এই একটি উত্তর একটি ভাল ব্যাচ ছিল যখন ফিরে: stackoverflow.com/questions/44905/...
নিক Craver

9
এটি প্রদর্শিত ToUpper(Invariant)হয় কেবল দ্রুতই নয়, তবে আরও নির্ভরযোগ্য: stackoverflow.com/a/2801521/67824
ওহাদ স্নাইডার


48

পুরানো প্রশ্নের এই নতুন পোস্টের জন্য দুঃখিত, তবে সি # 7 (ভিএস 2017) ব্যবহার করে এই সমস্যাটি সমাধান করার জন্য একটি নতুন বিকল্প রয়েছে।

সি # 7 এখন "প্যাটার্ন ম্যাচিং" অফার করে এবং এটি এই সমস্যাটিকে এভাবে সমাধান করার জন্য ব্যবহার করা যেতে পারে:

string houseName = "house";  // value to be tested, ignoring case
string windowName;   // switch block will set value here

switch (true)
{
    case bool b when houseName.Equals("MyHouse", StringComparison.InvariantCultureIgnoreCase): 
        windowName = "MyWindow";
        break;
    case bool b when houseName.Equals("YourHouse", StringComparison.InvariantCultureIgnoreCase): 
        windowName = "YourWindow";
        break;
    case bool b when houseName.Equals("House", StringComparison.InvariantCultureIgnoreCase): 
        windowName = "Window";
        break;
    default:
        windowName = null;
        break;
}

এই সমাধানটি @ জেফ্রি এল হুইটলেজের উত্তরে উল্লিখিত ইস্যুর সাথেও আলোচনা করে যে স্ট্রসের ক্ষেত্রে সংবেদনশীল তুলনা দুটি লোয়ার-কেসড স্ট্রিংয়ের সাথে তুলনা করার মতো নয়।

যাইহোক, ফেব্রুয়ারী 2017 এ ভিজ্যুয়াল স্টুডিও ম্যাগাজিনে একটি আকর্ষণীয় নিবন্ধ ছিল যা প্যাটার্ন মিলের বর্ণনা দেয় এবং কীভাবে এটি ব্লকগুলি ব্যবহার করা যেতে পারে describ দয়া করে একবার দেখুন: সি # 7.0 কেস ব্লকের প্যাটার্ন ম্যাচিং

সম্পাদনা

@ লুইসএম এর উত্তরের আলোকে, এটি উল্লেখ করা গুরুত্বপূর্ণ যে switchবিবৃতিটির কিছু নতুন, আকর্ষণীয় আচরণ রয়েছে। এটি হ'ল যদি আপনার caseবিবৃতিতে একটি ভেরিয়েবল ডিক্লেয়ারেশন থাকে, তবে switchঅংশে নির্দিষ্ট করা মানটি ঘোষিত চলকটিতে অনুলিপি করা হয় case। নিম্নলিখিত উদাহরণে, মানটি trueস্থানীয় ভেরিয়েবলে অনুলিপি করা হয় b। তদ্ব্যতীত, ভেরিয়েবলটি bঅব্যবহৃত এবং কেবলমাত্র উপস্থিত থাকে যাতে বিবৃতিটির whenধারাটি caseবিদ্যমান থাকে:

switch(true)
{
    case bool b when houseName.Equals("X", StringComparison.InvariantCultureIgnoreCase):
        windowName = "X-Window";):
        break;
}

@ লুইজম যেমন উল্লেখ করেছেন, এটি উপকারের জন্য ব্যবহার করা যেতে পারে - যে সুবিধাটি যে তুলনা করা হচ্ছে তা আসলে switchবিবৃতিতে রয়েছে, কারণ এটি বিবৃতিটির শাস্ত্রীয় ব্যবহারের সাথে রয়েছে switch। এছাড়াও, caseবিবৃতিতে ঘোষিত অস্থায়ী মানগুলি মূল মানটিতে অযাচিত বা অজান্তেই পরিবর্তনগুলি রোধ করতে পারে:

switch(houseName)
{
    case string hn when hn.Equals("X", StringComparison.InvariantCultureIgnoreCase):
        windowName = "X-Window";
        break;
}

4
এটি দীর্ঘতর হবে তবে আমি switch (houseName)তারপরে তুলনাটি আপনার পছন্দ মতো করতে চাই, যেমনcase var name when name.Equals("MyHouse", ...
লুইসএম

@ লুইজম - এটি আকর্ষণীয়। আপনি কি এর একটি কাজের উদাহরণ দেখাতে পারেন?
এসটিএলদেভ

@ লুইজম - দুর্দান্ত উত্তর। আমি নিয়োগের বিষয়ে আরও আলোচনা যুক্ত করেছিswitchcase অস্থায়ী ভেরিয়েবলগুলিতে আর্গুমেন্টের মান নির্ধারণের ।
এসটিএলডিভ

আধুনিক সি # তে প্যাটার্ন মিলের জন্য হ্যাঁ
থিয়াগো সিলভা

আপনি "অবজেক্ট প্যাটার্ন ম্যাচিং" ব্যবহার করতে পারেন যাতে case { } whenভেরিয়েবল টাইপ এবং নাম সম্পর্কে আপনাকে চিন্তা করতে হবে না।
বব

32

কিছু ক্ষেত্রে এনাম ব্যবহার করা ভাল ধারণা হতে পারে। সুতরাং প্রথমে এনামকে পার্স করুন (উপেক্ষাক্যাসের পতাকাটি সত্য দিয়ে) এবং এনামটিতে একটি স্যুইচ করুন।

SampleEnum Result;
bool Success = SampleEnum.TryParse(inputText, true, out Result);
if(!Success){
     //value was not in the enum values
}else{
   switch (Result) {
      case SampleEnum.Value1:
      break;
      case SampleEnum.Value2:
      break;
      default:
      //do default behaviour
      break;
   }
}

কেবলমাত্র একটি দ্রষ্টব্য: এনাম ট্রাইপর্স ফ্রেমওয়ার্ক 4.0 এবং এগিয়ে, এফওয়াইআইয়ের সাথে উপলব্ধ বলে মনে হচ্ছে। msdn.microsoft.com/en-us/library/dd991317(v=vs.100).aspx
গ্রানাডা কোডার

4
আমি এই সমাধানটি পছন্দ করি কারণ এটি যাদু স্ট্রিংয়ের ব্যবহারকে নিরুৎসাহিত করে।
ব্যবহারকারী 1069816

23

@ এসটিএল ডেভেলপারএ দ্বারা উত্তরের একটি বর্ধন। একাধিক ছাড়াই বিবৃতি মূল্যায়ন করার একটি নতুন উপায় যদি সি # 7 হিসাবে স্টেটমেন্টগুলি প্যাটার্নের সাথে মিলে যাওয়া সুইচ স্টেটমেন্টটি ব্যবহার করে তবে @ এসটিএল ডেভেলপার যদিও এইভাবে চলকটি স্যুইচ করা হচ্ছে তেমন পরিবর্তন করছে

string houseName = "house";  // value to be tested
string s;
switch (houseName)
{
    case var name when string.Equals(name, "Bungalow", StringComparison.InvariantCultureIgnoreCase): 
        s = "Single glazed";
    break;

    case var name when string.Equals(name, "Church", StringComparison.InvariantCultureIgnoreCase):
        s = "Stained glass";
        break;
        ...
    default:
        s = "No windows (cold or dark)";
        break;
}

ভিজ্যুয়াল স্টুডিও ম্যাগাজিনে প্যাটার্ন ম্যাচিং কেস ব্লকগুলির উপর একটি দুর্দান্ত নিবন্ধ রয়েছে যা দেখতে পারা যায়।


নতুন switchবিবৃতিটির অতিরিক্ত কার্যকারিতা নির্দেশ করার জন্য আপনাকে ধন্যবাদ ।
এসটিএলডিভ

4
+1 - এটি আধুনিক (সি # 7 এর পরে) বিকাশের জন্য স্বীকৃত উত্তর হওয়া উচিত। একটি পরিবর্তন আমি করব যে আমি case var name when "Bungalow".Equals(name, StringComparison.InvariantCultureIgnoreCase):এটির মতো কোড করব: যেহেতু এটি একটি নাল রেফারেন্স ব্যতিক্রম (যেখানে বাড়ির নামটি নাল) বাধা দিতে পারে বা বিকল্পভাবে স্ট্রিংটি প্রথমে নাল হওয়ার জন্য একটি কেস যুক্ত করতে পারে।
জে

21

একটি সম্ভাব্য উপায় হ'ল অ্যাকশন প্রতিনিধি সহ উপেক্ষা করা কেস ডিকশনারিটি ব্যবহার করা।

string s = null;
var dic = new Dictionary<string, Action>(StringComparer.CurrentCultureIgnoreCase)
{
    {"house",  () => s = "window"},
    {"house2", () => s = "window2"}
};

dic["HouSe"]();

// নোট করুন যে কলটি পাঠ্য ফেরত দেয় না, তবে কেবল স্থানীয় ভেরিয়েবলকে পপুলেট করে।
// আপনি, প্রকৃত টেক্সট আসতে প্রতিস্থাপন করতে চান Actionকরতে Func<string>ভালো কিছু করার জন্য অভিধানে ও মূল্যবোধ() => "window2"


4
বরং CurrentCultureIgnoreCase, OrdinalIgnoreCaseপছন্দ করা হয়।
রিচার্ড ইভ

4
@richardEverett পছন্দসই? আপনি যা চান তার উপর নির্ভর করে, আপনি যদি বর্তমান সংস্কৃতি চান তবে এটি অগ্রাহ্য নয় ignore
ম্যাগনাস

যদি কারও আগ্রহী, আমার সমাধান (নীচে) এই ধারণাটি নেয় এবং এটিকে একটি সাধারণ শ্রেণিতে আবদ্ধ করে।
ফ্লাইডগ 5 7

2

এখানে একটি সমাধান যা @ ম্যাগনাসের সমাধানটিকে ক্লাসে গুটিয়ে রাখে:

public class SwitchCaseIndependent : IEnumerable<KeyValuePair<string, Action>>
{
    private readonly Dictionary<string, Action> _cases = new Dictionary<string, Action>(StringComparer.OrdinalIgnoreCase);

    public void Add(string theCase, Action theResult)
    {
        _cases.Add(theCase, theResult);
    }

    public Action this[string whichCase]
    {
        get
        {
            if (!_cases.ContainsKey(whichCase))
            {
                throw new ArgumentException($"Error in SwitchCaseIndependent, \"{whichCase}\" is not a valid option");
            }
            //otherwise
            return _cases[whichCase];
        }
    }

    public IEnumerator<KeyValuePair<string, Action>> GetEnumerator()
    {
        return _cases.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return _cases.GetEnumerator();
    }
}

এটি একটি সাধারণ উইন্ডোজ ফর্ম অ্যাপ্লিকেশনটিতে ব্যবহারের উদাহরণ রয়েছে:

   var mySwitch = new SwitchCaseIndependent
   {
       {"hello", () => MessageBox.Show("hello")},
       {"Goodbye", () => MessageBox.Show("Goodbye")},
       {"SoLong", () => MessageBox.Show("SoLong")},
   };
   mySwitch["HELLO"]();

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

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

এটি সম্ভবত এমন একটি সহজ bool ContainsCase(string aCase)পদ্ধতি যুক্ত করতে অর্থবোধ করবে যা কেবল অভিধানের ContainsKeyপদ্ধতিটিকে কল করে calls


1

আমি আশা করি এটি পুরো স্ট্রিংটিকে বিশেষ ক্ষেত্রে ছোট হাতের বা বড় হাতের ক্ষেত্রে রূপান্তর করতে এবং তুলনার জন্য লোয়ারকেস স্ট্রিংটি ব্যবহার করতে সহায়তা করে:

public string ConvertMeasurements(string unitType, string value)
{
    switch (unitType.ToLower())
    {
        case "mmol/l": return (Double.Parse(value) * 0.0555).ToString();
        case "mg/dl": return (double.Parse(value) * 18.0182).ToString();
    }
}

0

এটি করার জন্য এটি পর্যাপ্ত হওয়া উচিত:

string s = "houSe";
switch (s.ToLowerInvariant())
{
  case "house": s = "window";
  break;
}

স্যুইচ তুলনাটি এর মাধ্যমে সংস্কৃতি অদম্য। আমি যতদূর দেখতে পাচ্ছি এটির জন্য সি # 7 প্যাটার্ন-ম্যাচিং সমাধানগুলির মতো একই ফলাফলটি অর্জন করা উচিত তবে আরও সংক্ষেপে।


-1

10 বছর পরে, সি # প্যাটার্নের মিলের সাথে আপনি এমন কিছু করতে পারেন:

private string NormalisePropertyType(string propertyType) => true switch
{
    true when string.IsNullOrWhiteSpace(propertyType) => propertyType,
    true when "house".Equals(propertyType, StringComparison.OrdinalIgnoreCase) => "house",
    true when "window".Equals(propertyType, StringComparison.OrdinalIgnoreCase) => "window",
    true when "door".Equals(propertyType, StringComparison.OrdinalIgnoreCase) => "door",
    true when "roof".Equals(propertyType, StringComparison.OrdinalIgnoreCase) => "roof",
    true when "chair".Equals(propertyType, StringComparison.OrdinalIgnoreCase) => "chair",
    _ => propertyType
};
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.