রিশার্পার সতর্ক করে: "জেনেরিক ধরণের স্ট্যাটিক ফিল্ড"


261
public class EnumRouteConstraint<T> : IRouteConstraint
    where T : struct
{
    private static readonly Lazy<HashSet<string>> _enumNames; // <--

    static EnumRouteConstraint()
    {
        if (!typeof(T).IsEnum)
        {
            throw new ArgumentException(
                Resources.Error.EnumRouteConstraint.FormatWith(typeof(T).FullName));
        }

        string[] names = Enum.GetNames(typeof(T));
        _enumNames = new Lazy<HashSet<string>>(() => new HashSet<string>
        (
            names.Select(name => name), StringComparer.InvariantCultureIgnoreCase
        ));
    }

    public bool Match(HttpContextBase httpContext, Route route, 
                        string parameterName, RouteValueDictionary values, 
                        RouteDirection routeDirection)
    {
        bool match = _enumNames.Value.Contains(values[parameterName].ToString());
        return match;
    }
}

এটা কি ভুল? আমি ধরে নেব যে এটির static readonlyপ্রতিটি ক্ষেত্রেই EnumRouteConstraint<T>আমি সম্ভবত যে ঘটনাটি ঘটতে পারি তার পক্ষে একটি ক্ষেত্র রয়েছে ।


কখনও কখনও এটির বৈশিষ্ট্য, কখনও কখনও বিরক্তি। আমি চাই সি # এর আলাদা করার জন্য কিছু কীওয়ার্ড রয়েছে
নওফাল

উত্তর:


468

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

এখানে এর একটি উদাহরণ:

using System;

public class Generic<T>
{
    // Of course we wouldn't normally have public fields, but...
    public static int Foo;
}

public class Test
{
    public static void Main()
    {
        Generic<string>.Foo = 20;
        Generic<object>.Foo = 10;
        Console.WriteLine(Generic<string>.Foo); // 20
    }
}

আপনি দেখতে পাচ্ছেন, এর Generic<string>.Fooথেকে আলাদা ক্ষেত্র Generic<object>.Foo- এগুলি পৃথক মান রাখে।


এটি কি সত্য যখন জেনেরিক ক্লাসগুলি অ জেনেরিক শ্রেণীর উত্তরাধিকার সূত্রে ধীরে ধীরে থাকে that উদাহরণস্বরূপ, যদি আমি class BaseFooএকটি স্থিতিশীল সদস্যযুক্ত তৈরি করি , তবে তা থেকে প্রাপ্ত class Foo<T>: BaseFooসমস্ত Foo<T>শ্রেণি কি একই স্ট্যাটিক সদস্যের মান ভাগ করে নেবে?
বাইকম্যান 868

2
এখানে আমার নিজের মন্তব্যের জবাব দিচ্ছি, তবে হ্যাঁ, সমস্ত ফু <T> এর একই স্ট্যাটিক মান থাকবে যদি এটি একটি জেনেরিক বেস শ্রেণিতে থাকে। দেখুন dotnetfiddle.net/Wz75ya
bikeman868

147

থেকে JetBrains উইকি :

বেশিরভাগ ক্ষেত্রে, জেনেরিক ধরণের স্থির ক্ষেত্র থাকা একটি ত্রুটির লক্ষণ। এর কারণ হ'ল জেনেরিক ধরণের একটি স্ট্যাটিক ক্ষেত্রটি বিভিন্ন ঘনিষ্ঠভাবে নির্মিত ধরণের উদাহরণগুলির মধ্যে ভাগ করা হবে না । এর অর্থ হল একটি জেনেরিক শ্রেণির জন্য C<T>যার স্থিতিশীল ক্ষেত্র রয়েছে X, এর মানগুলি C<int>.Xএবং C<string>.X সম্পূর্ণ আলাদা, স্বতন্ত্র মান রয়েছে।

বিরল ক্ষেত্রে যখন আপনি কি প্রয়োজন 'বিশেষ' স্ট্যাটিক ক্ষেত্র সতর্কবাণী দমন বিনা দ্বিধায়।

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


13
জেনেরিক ধরণের নিয়োগের সময়, প্রযুক্তিগতভাবে আপনি হোস্ট করছেন প্রতিটি জেনেরিক ধরণের জন্য একটি স্বতন্ত্র এবং পৃথক শ্রেণীর সাথে সমাপ্ত হয়। দুটি পৃথক, নন-জেনেরিক ক্লাস ঘোষণার সময়, আপনি তাদের মধ্যে স্ট্যাটিক ভেরিয়েবলগুলি ভাগ করে নেওয়ার আশা করবেন না, তবে জেনেরিকগুলি আলাদা হওয়া উচিত কেন? এটি বিরল হিসাবে বিবেচিত হওয়ার একমাত্র উপায় হ'ল জেনেরিক ক্লাস তৈরি করার সময় যদি বেশিরভাগ বিকাশকারী তারা কী করছেন তা না বুঝতে পারে।
সিন্ডোগ

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

তবে আমি যদি কেবল এই স্থির ক্ষেত্রগুলি ধরে রাখতে একটি নন-জেনেরিক বেস শ্রেণি তৈরি করতে না চাই what এই ক্ষেত্রে আমি কি কেবল সতর্কতাগুলি দমন করতে পারি?
টম লিন্ট

@ টমলিন্ট আপনি যদি জানেন যে আপনি কী করছেন তবে সতর্কতাগুলি দমন করা সত্যিই করণীয়।
আকাশম

65

এটি অগত্যা কোনও ত্রুটি নয় - এটি আপনাকে সি # জেনারিকের সম্ভাব্য ভুল বোঝাবুঝির বিষয়ে সতর্ক করে দিচ্ছে।

জেনেরিকগুলি কী করে তা মনে রাখার সহজ উপায়টি হ'ল জেনেরিক্স ক্লাস তৈরির জন্য "ব্লুপ্রিন্ট", ক্লাসগুলির মতো অনেকগুলি অবজেক্ট তৈরির জন্য "ব্লুপ্রিন্ট"। (ভাল, এটি যদিও সরলিকরণ। আপনি পদ্ধতি জেনেরিকগুলিও ব্যবহার করতে পারেন))

এই দৃষ্টিকোণ থেকে MyClassRecipe<T>কোনও শ্রেণি নয় - এটি একটি শ্রেণীর রেসিপি, একটি ব্লুপ্রিন্ট, আপনার শ্রেণীর চেহারা কেমন। একবার আপনি টিয়ের পরিবর্তে কংক্রিটের কোনও কিছুর পরিবর্তে ইনট, স্ট্রিং ইত্যাদি বলুন, আপনি একটি ক্লাস পাবেন। আপনার সদ্য নির্মিত শ্রেণিতে (অন্য কোনও শ্রেণীর মতো) একটি স্থির সদস্য (ক্ষেত্র, সম্পত্তি, পদ্ধতি) ঘোষণা করা এবং এখানে কোনও ত্রুটির চিহ্ন নেই তা সম্পূর্ণ আইনী। এটি প্রথম দর্শনে কিছুটা সন্দেহজনক হবে, যদি আপনি static MyStaticProperty<T> Property { get; set; }নিজের শ্রেণীর নীলনকোষের মধ্যে ঘোষণা করেন তবে এটি আইনীও। আপনার সম্পত্তি পাশাপাশি প্যারামিটারাইজড বা টেম্পলেটড হবে।

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


1
আমি মনে করি সি ++ নামটি এটিকে সব থেকে পরিষ্কার করে তোলে। সি ++ এ তাদের বলা হয় টেমপ্লেট, যা সেগুলি, কংক্রিটের ক্লাসগুলির টেমপ্লেট।
মাইকেল ব্রাউন 21 এ 21

8

ইতিমধ্যে এখানে বেশ কয়েকটি ভাল উত্তর রয়েছে, যা সতর্কতা এবং এর কারণ ব্যাখ্যা করে। এগুলির বেশিরভাগ জেনেরিক ধরণের স্থির ক্ষেত্র থাকার মতো কিছু সাধারণত একটি ভুল

আমি ভেবেছিলাম যে এই বৈশিষ্ট্যটি কীভাবে কার্যকর হতে পারে তার উদাহরণ আমি যুক্ত করব, অর্থাত্ এমন একটি ক্ষেত্রে যেখানে আর-ওয়্যারিংকে দমন করার বিষয়টি বোঝায়।

আপনার কল্পনা করুন যে আপনার সত্তা-শ্রেণীর একটি সেট রয়েছে যা আপনি ক্রমিক করতে চান, এক্সএমএলকে বলুন। আপনি এটি ব্যবহার করে একটি সিরিয়ালাইজার তৈরি করতে পারেন new XmlSerializerFactory().CreateSerializer(typeof(SomeClass))তবে তারপরে আপনাকে প্রতিটি ধরণের জন্য পৃথক সিরিয়ালাইজার তৈরি করতে হবে। জেনেরিক ব্যবহার করে, আপনি নিম্নলিখিতটি দিয়ে প্রতিস্থাপন করতে পারেন, যা সত্তা থেকে প্রাপ্ত জেনেরিক শ্রেণিতে আপনি রাখতে পারেন:

new XmlSerializerFactory().CreateSerializer(typeof(T))

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

public class SerializableEntity<T>
{
    // ReSharper disable once StaticMemberInGenericType
    private static XmlSerializer _typeSpecificSerializer;

    private static XmlSerializer TypeSpecificSerializer
    {
        get
        {
            // Only create an instance the first time. In practice, 
            // that will mean once for each variation of T that is used,
            // as each will cause a new class to be created.
            if ((_typeSpecificSerializer == null))
            {
                _typeSpecificSerializer = 
                    new XmlSerializerFactory().CreateSerializer(typeof(T));
            }

            return _typeSpecificSerializer;
        }
    }

    public virtual string Serialize()
    {
        // .... prepare for serializing...

        // Access _typeSpecificSerializer via the property, 
        // and call the Serialize method, which depends on 
        // the specific type T of "this":
        TypeSpecificSerializer.Serialize(xmlWriter, this);
     }
}

যদি এই শ্রেণিটি জেনেরিক না হয় তবে শ্রেণির প্রতিটি উদাহরণ একই ব্যবহার করবে _typeSpecificSerializer

যেহেতু এটি জেনেরিক, একই ধরণের উদাহরণগুলির একটি সেট Tএকটি একক উদাহরণ ভাগ করবে _typeSpecificSerializer(যা সেই নির্দিষ্ট ধরণের জন্য তৈরি করা হবে), অন্যদিকে বিভিন্ন ধরণের Tউদাহরণগুলি বিভিন্ন উদাহরণ ব্যবহার করবে _typeSpecificSerializer

একটি উদাহরণ

দুটি শ্রেণীর বিস্তৃত প্রসারিত SerializableEntity<T>:

// Note that T is MyFirstEntity
public class MyFirstEntity : SerializableEntity<MyFirstEntity>
{
    public string SomeValue { get; set; }
}

// Note that T is OtherEntity
public class OtherEntity : SerializableEntity<OtherEntity >
{
    public int OtherValue { get; set; }
}

... আসুন সেগুলি ব্যবহার করুন:

var firstInst = new MyFirstEntity{ SomeValue = "Foo" };
var secondInst = new MyFirstEntity{ SomeValue = "Bar" };

var thirdInst = new OtherEntity { OtherValue = 123 };
var fourthInst = new OtherEntity { OtherValue = 456 };

var xmlData1 = firstInst.Serialize();
var xmlData2 = secondInst.Serialize();
var xmlData3 = thirdInst.Serialize();
var xmlData4 = fourthInst.Serialize();

এই ক্ষেত্রে, ফণা অধীনে, firstInstএবং secondInstএকই শ্রেণীর উদাহরণস্বরূপ হবে (যথা SerializableEntity<MyFirstEntity>), এবং যেমন, তারা একটি উদাহরণ ভাগ করবে _typeSpecificSerializer

thirdInstএবং fourthInstএকটি ভিন্ন শ্রেণী (উদাহরণ স্বরূপ ধরে SerializableEntity<OtherEntity>), এবং তাই একটি দৃষ্টান্ত ভাগ হবে _typeSpecificSerializerযে বিভিন্ন অন্য দুটি থেকে।

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


স্ট্যাটিক ইনিশিয়ালাইজের নিয়মগুলির কারণে (ক্লাসটি প্রথমে রেফারেন্স না হওয়া পর্যন্ত স্ট্যাটিক ইনিশিয়ালাইজার বলা হয় না) আপনি গেটরে চেকটি রেখে যেতে পারেন এবং স্থির উদাহরণের ঘোষণায় এটি আরম্ভ করতে পারেন।
মাইকেল ব্রাউন 21 'এ
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.