সি # 4.0: আমি কি ডিফল্ট মান সহ anচ্ছিক প্যারামিটার হিসাবে টাইমস্প্যান ব্যবহার করতে পারি?


125

এগুলি উভয়ই ত্রুটি উত্পন্ন করে বলেছিল যে তাদের অবশ্যই সংকলন-সময় ধ্রুবক হতে হবে:

void Foo(TimeSpan span = TimeSpan.FromSeconds(2.0))
void Foo(TimeSpan span = new TimeSpan(2000))

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


11
আপনি যা জিজ্ঞাসা করছেন তার সাথে সম্পর্কিত নয়, তবে সচেতন থাকুন যা new TimeSpan(2000)2000 মিলিসেকেন্ডের অর্থ নয়, এর অর্থ 2000 "টিক্স" যা 0.2 মিলিসেকেন্ড, বা দুই সেকেন্ডের 10,000,000 তম।
জেপ্প স্টিগ নীলসেন

উত্তর:


172

আপনি নিজের স্বাক্ষর পরিবর্তন করে খুব সহজেই এটিকে ঘিরে কাজ করতে পারেন।

void Foo(TimeSpan? span = null) {

   if (span == null) { span = TimeSpan.FromSeconds(2); }

   ...

}

আমার বিস্তৃত হওয়া উচিত - কারণগুলির উদাহরণ হিসাবে আপনার উদাহরণগুলিতে এই এক্সপ্রেশনগুলি সংকলন-সময় ধ্রুবকগুলি নয় কারণ সংকলন করার সময়, সংকলক কেবল টাইমস্প্যান.ফর্মসেকেন্ডস (২.০) কার্যকর করতে পারে না এবং ফলাফলের বাইটগুলি আপনার সংকলিত কোডে আটকে রাখতে পারে।

উদাহরণ হিসাবে, আপনি পরিবর্তে ডেটটাইম ব্যবহার করার চেষ্টা করেছেন কিনা তা বিবেচনা করুন ow ডেটটাইম-এর মান.এখন প্রতিটি সময় এটি কার্যকর করা হয় পরিবর্তিত হয়। বা ধরুন যে টাইমস্প্যান.ফর্মসেকেন্ডগুলি গ্র্যাভিটি অ্যাকাউন্টে নিয়েছে। এটি একটি অযৌক্তিক উদাহরণ কিন্তু সংকলন-সময় ধ্রুবকগুলির নিয়মগুলি বিশেষ কেসগুলিকে তৈরি করে না কারণ কেবলমাত্র আমরা জানতে পেরেছি যে টাইমস্প্যান Sফ্রমসেকেন্ডস হ'ল নির্দোষ।


15
এখন এতে ডিফল্ট মানটি নথি করুন <param>, কারণ এটি স্বাক্ষরে দৃশ্যমান নয়।
কর্নেল আতঙ্ক

3
আমি এটি করতে পারি না, আমি অন্য কোনও কিছুর জন্য বিশেষ মান নাল ব্যবহার করছি।
কর্নেল আতঙ্ক

4
@ ম্যাটহিকফোর্ড - তারপরে আপনাকে একটি ওভারলোডেড পদ্ধতি সরবরাহ করতে হবে বা প্যারামিটার হিসাবে মিলিসেকেন্ডগুলি নিতে হবে।
জোশ

19
span = span ?? TimeSpan.FromSeconds(2.0);পদ্ধতি শরীরে, nullable টাইপ সঙ্গে ব্যবহার করতে পারেন । অথবা var realSpan = span ?? TimeSpan.FromSeconds(2.0);একটি স্থানীয় পরিবর্তনশীল পেতে যা অযোগ্য নয়।
জেপ্প স্টিগ নীলসেন

5
আমি এই জিনিসটি পছন্দ করি না তা হ'ল এটি ফাংশনের ব্যবহারকারীর প্রতি বোঝায় যে এই ফাংশনটি নাল স্প্যান দিয়ে "কাজ করে"। তবে তা সত্য নয়! নাল না বিঘত জন্য একটি বৈধ মান যতটা ফাংশন প্রকৃত যুক্তিবিজ্ঞান সংশ্লিষ্ট করা হয়। আমি আশা করি এর চেয়ে ভাল আরও কোনও উপায় ছিল যা কোড গন্ধের মতো মনে হয় নি ...
জো কুল

31

আমার ভিবি 6 heritageতিহ্য "নাল মান" এবং "অনুপস্থিত মান" সমতুল্য হিসাবে বিবেচনা করার ধারণা নিয়ে আমাকে অস্বস্তি করে তোলে। বেশিরভাগ ক্ষেত্রে, এটি সম্ভবত ভাল, তবে আপনার অযৌক্তিক পার্শ্ব প্রতিক্রিয়া হতে পারে, বা আপনি একটি ব্যতিক্রমী শর্তটি গ্রাস করতে পারেন (উদাহরণস্বরূপ, যদি উত্স spanবা সম্পত্তি পরিবর্তনযোগ্য হয় তবে এটি বাতিল হওয়া উচিত নয়)।

আমি অতএব পদ্ধতিটি ওভারলোড করব:

void Foo()
{
    Foo(TimeSpan.FromSeconds(2.0));
}
void Foo(TimeSpan span)
{
    //...
}

1
দুর্দান্ত কৌশলটির জন্য +1। ডিফল্ট পরামিতিগুলি কেবলমাত্র কনস্টের ধরণের সাথে ব্যবহার করা উচিত। অন্যথায়, এটি বিশ্বাসযোগ্য নয়।
লাজলো

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

23

এটি সূক্ষ্মভাবে কাজ করে:

void Foo(TimeSpan span = default(TimeSpan))


4
স্ট্যাক ওভারফ্লোতে আপনাকে স্বাগতম। আপনার উত্তরটি মনে হয় যে আপনি কোনও ডিফল্ট প্যারামিটার মান সরবরাহ করতে পারবেন , যতক্ষণ না এটি সংকলকটির দ্বারা সুনির্দিষ্ট একটি নির্দিষ্ট মান। আমি কি ঠিক বুঝতে পেরেছি? (আপনি নিজের উত্তরটি স্পষ্ট করার জন্য সম্পাদনা করতে পারেন )) এটি যদি আরও ভাল উত্তর হতে পারে যে যদি এটি দেখায় যে সংকলকটি মূলত যা জিজ্ঞাসা করেছিল, কীভাবে স্বেচ্ছাসেবীর অন্যান্য TimeSpan মান থাকতে পারে, কীভাবে পেতে পারে তা কীভাবে গ্রহণ করতে পারে by new TimeSpan(2000)
রব কেনেডি

2
একটি বিকল্প যা কিছু নির্দিষ্ট ডিফল্ট মান ব্যবহার করে তা হ'ল একটি প্রাইভেট স্ট্যাটিক কেবল পঠনযোগ্য টাইমস্প্যান ডিফল্টটাইমস্প্যান = টাইমস্প্যান.ফ্রমসেকেন্ডস (2) ডিফল্ট কনস্ট্রাক্টর এবং কনস্ট্রাক্টরের সাথে মিলিত একটি টাইমস্প্যান গ্রহণ করে। পাবলিক ফু (): এটি (ডিফল্ট টাইমস্প্যান) এবং পাবলিক ফু (
টাইমস্প্যান

15

ডিফল্ট মান হিসাবে ব্যবহার করা যেতে পারে এমন মানগুলির সেটটি কোনও অ্যাট্রিবিউট আর্গুমেন্টের জন্য ব্যবহার করা যেতে পারে। ডিফল্ট মানগুলি এর অভ্যন্তরে মেটাডেটাতে এনকোড করা হওয়ার কারণ DefaultParameterValueAttribute

কেন এটি সংকলনের সময় নির্ধারণ করা যায় না। সংকলনের সময় অনুমোদিত এই জাতীয় মানগুলির উপরে মান এবং এক্সপ্রেশনগুলির সেটটি অফিসিয়াল সি # ল্যাঙ্গুয়েজ স্পেসে তালিকাভুক্ত করা হয়েছে :

সি # 6.0 - প্যারামিটারের বৈশিষ্ট্যগুলি :

কোনও অ্যাট্রিবিউট শ্রেণীর অবস্থানগত এবং নামযুক্ত পরামিতিগুলির প্রকারগুলি অ্যাট্রিবিউট প্যারামিটার ধরণের মধ্যে সীমাবদ্ধ , যা হ'ল:

  • নিম্নলিখিত প্রকারের একটি: bool, byte, char, double, float, int, long, sbyte, short, string, uint, ulong, ushort
  • প্রকার object
  • প্রকার System.Type
  • একটি এনাম টাইপ।
    (প্রদত্ত যাতে এটিতে জনসাধারণের অ্যাক্সেসযোগ্যতা রয়েছে এবং যে ধরণের নেস্ট করা হয়েছে (যদি থাকে তবে) জনসাধারণের অ্যাক্সেসযোগ্যতাও রয়েছে)
  • উপরের ধরণের একক মাত্রিক অ্যারে।

প্রকারটি TimeSpanএই তালিকার কোনও তালিকার সাথে খাপ খায় না এবং তাই ধ্রুবক হিসাবে ব্যবহার করা যায় না।


2
সামান্য নিট-পিক: স্ট্যাটিক পদ্ধতিতে কল করা তালিকার কোনওটিতেই খাপ খায় না। TimeSpanএই তালিকার শেষের সাথে মানিয়ে নিতে পারেন default(TimeSpan)বৈধ।
কোডসইনচাউস

12
void Foo(TimeSpan span = default(TimeSpan))
{
    if (span == default(TimeSpan)) 
        span = TimeSpan.FromSeconds(2); 
}

প্রদত্ত default(TimeSpan)ফাংশনটির জন্য কোনও বৈধ মান নয়।

অথবা

//this works only for value types which TimeSpan is
void Foo(TimeSpan span = new TimeSpan())
{
    if (span == new TimeSpan()) 
        span = TimeSpan.FromSeconds(2); 
}

প্রদত্ত new TimeSpan()কোনও বৈধ মান নয়।

অথবা

void Foo(TimeSpan? span = null)
{
    if (span == null) 
        span = TimeSpan.FromSeconds(2); 
}

nullফাংশনটির জন্য একটি বৈধ মান হওয়ার সম্ভাবনা খুব কম বিবেচনা করে এটি আরও ভাল হওয়া উচিত ।


4

TimeSpanএটির জন্য একটি বিশেষ কেস DefaultValueAttributeএবং TimeSpan.Parseপদ্ধতিটির মাধ্যমে পার্স করা যায় এমন কোনও স্ট্রিং ব্যবহার করে নির্দিষ্ট করা হয় ।

[DefaultValue("0:10:0")]
public TimeSpan Duration { get; set; }

3

আমার পরামর্শ:

void A( long spanInMs = 2000 )
{
    var ts = TimeSpan.FromMilliseconds(spanInMs);

    //...
}

বিটিডাব্লু TimeSpan.FromSeconds(2.0)সমান হয় না new TimeSpan(2000)- কনস্ট্রাক্টর টিকগুলি নেয়।


2

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

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

public class FooSettings
{
    public TimeSpan Span { get; set; } = TimeSpan.FromSeconds(2);

    // I imagine that if you had a heavyweight default
    // thing you’d want to avoid instantiating it right away
    // because the caller might override that parameter. So, be
    // lazy! (Or just directly store a factory lambda with Func<IThing>).
    Lazy<IThing> thing = new Lazy<IThing>(() => new FatThing());
    public IThing Thing
    {
        get { return thing.Value; }
        set { thing = new Lazy<IThing>(() => value); }
    }

    // Another cool thing about this pattern is that you can
    // add additional optional parameters in the future without
    // even breaking ABI.
    //bool FutureThing { get; set; } = true;

    // You can even run very complicated code to populate properties
    // if you cannot use a property initialization expression.
    //public FooSettings() { }
}

public class Bar
{
    public void Foo(FooSettings settings = null)
    {
        // Allow the caller to use *all* the defaults easily.
        settings = settings ?? new FooSettings();

        Console.WriteLine(settings.Span);
    }
}

কল করার জন্য, সমস্ত একই অভিব্যক্তিতে বৈশিষ্ট্যগুলি ইনস্ট্যান্ট করতে এবং নির্ধারণের জন্য একটি অদ্ভুত বাক্য গঠন ব্যবহার করুন:

bar.Foo(); // 00:00:02
bar.Foo(new FooSettings { Span = TimeSpan.FromDays(1), }); // 1.00:00:00
bar.Foo(new FooSettings { Thing = new MyCustomThing(), }); // 00:00:02

downsides

এই সমস্যাটি সমাধান করার জন্য এটি সত্যই একটি ভারী ওজনের উপায়। আপনি একটি দ্রুত এবং ময়লা অভ্যন্তরীণ ইন্টারফেস লেখা এবং হয় উপার্জন TimeSpanআপনার পছন্দসই ডিফল্ট মান মত nullable এবং চিকিত্সা নাল উত্তম কাজ করবে, যে পরিবর্তে না।

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

উপকারিতা

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

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

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