বিল্ট-ইন টাইপের বৈধতা প্রয়োগ করতে স্ট্রাক্ট ব্যবহার করা


9

সাধারণত ডোমেন অবজেক্টের এমন বৈশিষ্ট্য থাকে যা বিল্ট-ইন টাইপ দ্বারা প্রতিনিধিত্ব করা যেতে পারে তবে যার বৈধ মানগুলি সেই ধরণের দ্বারা প্রতিনিধিত্ব করা হতে পারে এমন মানগুলির একটি উপসেট।

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

এটি সমাধানের একটি উপায় হ'ল মানটিকে একটি কাস্টম হিসাবে সংরক্ষণ করা structযা private readonlyবিল্ট-ইন টাইপের একক ব্যাকিং ক্ষেত্র এবং যার কনস্ট্রাক্টর সরবরাহ করা মানকে বৈধ করে। তারপরে আমরা সর্বদা কেবল এই structধরণের ব্যবহার করে বৈধ মানগুলি ব্যবহারের বিষয়ে নিশ্চিত হতে পারি ।

আমরা অন্তর্নির্মিত অন্তর্নির্মিত টাইপ থেকে এবং এর জন্যও কাস্ট অপারেটর সরবরাহ করতে পারি যাতে মানগুলি নির্বিঘ্নে প্রবেশ করে এবং অন্তর্নিহিত প্রকার হিসাবে প্রস্থান করতে পারে।

উদাহরণ হিসাবে বিবেচনা করুন এমন পরিস্থিতিতে যেখানে আমাদের কোনও ডোমেন অবজেক্টের নাম উপস্থাপন করতে হবে এবং বৈধ মানগুলি এমন কোনও স্ট্রিং যা দৈর্ঘ্য সমেত 1 এবং 255 অক্ষরের মধ্যে থাকে। আমরা নিম্নলিখিত কাঠামো ব্যবহার করে এটি উপস্থাপন করতে পারি:

public struct ValidatedName : IEquatable<ValidatedName>
{
    private readonly string _value;

    private ValidatedName(string name)
    {
        _value = name;
    }

    public static bool IsValid(string name)
    {
        return !String.IsNullOrEmpty(name) && name.Length <= 255;
    }

    public bool Equals(ValidatedName other)
    {
        return _value == other._value;
    }

    public override bool Equals(object obj)
    {
        if (obj is ValidatedName)
        {
            return Equals((ValidatedName)obj);
        }
        return false;
    }

    public static implicit operator string(ValidatedName x)
    {
        return x.ToString();
    }

    public static explicit operator ValidatedName(string x)
    {
        if (IsValid(x))
        {
            return new ValidatedName(x);
        }
        throw new InvalidCastException();
    }

    public static bool operator ==(ValidatedName x, ValidatedName y)
    {
        return x.Equals(y);
    }

    public static bool operator !=(ValidatedName x, ValidatedName y)
    {
        return !x.Equals(y);
    }

    public override int GetHashCode()
    {
        return _value.GetHashCode();
    }

    public override string ToString()
    {
        return _value;
    }
}

উদাহরণস্বরূপ শো পারেন- stringযেমন ঢালাই implicitএই ব্যর্থ না পারে কিন্তু from- stringযেমন ঢালাই explicitএই অবৈধ মানের জন্য নিক্ষেপ করা হবে, কিন্তু অবশ্যই উভয় এই হতে পারেন পারে implicitবা explicit

এও নোট করুন যে একজন কেবলমাত্র এই কাঠামোটি কেবল aালাইয়ের মাধ্যমেই শুরু stringকরতে পারেন তবে IsValid staticপদ্ধতিটি ব্যবহার করে এই জাতীয় অভিনেত্রী আগে থেকে ব্যর্থ হবে কিনা তা পরীক্ষা করতে পারে ।

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

সুতরাং আমার প্রশ্নটি: আপনি এই প্যাটার্নটি ব্যবহার করার সুবিধাগুলি এবং অসুবিধাগুলি হিসাবে কী দেখছেন এবং কেন?

আপনি যদি মনে করেন যে এটি একটি খারাপ প্যাটার্ন, তবে আমি বুঝতে চাই কেন এবং আপনি যা অনুভব করছেন এটি সর্বোত্তম বিকল্প।

এনবি আমি প্রথমে স্ট্যাক ওভারফ্লোতে এই প্রশ্নটি জিজ্ঞাসা করেছি তবে এটি প্রাথমিকভাবে মতামত-ভিত্তিক (নিজের মধ্যে বিদ্রূপাত্মক বিষয়গত) হিসাবে ধরে রাখা হয়েছিল - আশা করি এটি এখানে আরও সাফল্য উপভোগ করতে পারে।

উপরে মূল পাঠ্যটি রয়েছে, আরও কয়েকটা চিন্তাভাবনার নীচে, আংশিকভাবে জবাবগুলি ধরে রাখার আগে সেখানে প্রাপ্ত উত্তরগুলির প্রতিক্রিয়াতে:

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

আপনি একটি টেম্প্লেটেড সংস্করণ তৈরি করতে পারেন যা একটি বুল (টি) লম্বা লাগে
রাচেট ফ্রিক

উত্তর:


4

এটি স্ট্যান্ডার্ড এমএল / ওসিএএমএল / এফ # / হাস্কেলের মতো এমএল স্টাইলের ভাষাগুলিতে মোটামুটি সাধারণ যেখানে র‍্যাপারের প্রকারগুলি তৈরি করা এটি আরও সহজ। এটি আপনাকে দুটি সুবিধা প্রদান করে:

  • এটি কোডের এক টুকরোটি প্রয়োগ করতে অনুমতি দেয় যে কোনও স্ট্রিং সেই বৈধতার নিজেই যত্ন না নিয়েই বৈধতা পেয়েছে।
  • এটি আপনাকে বৈধতা কোডটি এক জায়গায় স্থানীয়করণ করতে দেয়। যদি ValidatedNameকখনও কোনও অবৈধ মান থাকে তবে আপনি জানেন যে IsValidপদ্ধতিটিতে ত্রুটি রয়েছে ।

আপনি যদি IsValidপদ্ধতিটি সঠিকভাবে পান তবে আপনার গ্যারান্টি রয়েছে যে কোনও ফাংশন যা গ্রহণ করবে ValidatedNameতা আসলে একটি বৈধ নাম প্রাপ্তি।

আপনার যদি স্ট্রিং ম্যানিপুলেশনগুলি করতে হয় তবে আপনি একটি সর্বজনীন পদ্ধতি যুক্ত করতে পারেন যা কোনও ফাংশন গ্রহণ করে যা একটি স্ট্রিং (এর মান ValidatedName) গ্রহণ করে এবং একটি স্ট্রিং (নতুন মান) দেয় এবং ফাংশন প্রয়োগের ফলাফলকে বৈধ করে দেয়। এটি অন্তর্নিহিত স্ট্রিংয়ের মান পাওয়ার এবং এটি পুনরায় মোড়ানোর বোয়লারপ্লেটকে সরিয়ে দেয়।

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


1

এই প্যাটার্নটি ব্যবহার করার সুবিধা এবং অসুবিধাগুলি হিসাবে আপনি কী দেখছেন এবং কেন?

ভাল :

  • এটি স্বয়ং নিহিত। অনেকগুলি বৈধতা বিটের বিভিন্ন জায়গায় ট্রেন্ডিলগুলি পৌঁছেছে।
  • এটি স্ব-ডকুমেন্টেশন সহায়তা করে। কোনও পদ্ধতি গ্রহণ দেখে ValidatedStringকলটির শব্দার্থকতা সম্পর্কে এটি আরও পরিষ্কার হয়ে যায়।
  • এটি সর্বজনীন পদ্ধতিতে সদৃশ হওয়ার পরিবর্তে এক স্থানে বৈধতা সীমাবদ্ধ করতে সহায়তা করে।

খারাপ :

  • Ingালাইয়ের কৌশলটি গোপন রয়েছে। এটি আইডেম্যাটিক সি # নয়, সুতরাং কোডটি পড়ার সময় বিভ্রান্তি সৃষ্টি করতে পারে।
  • এটা ছুড়ে ফেলে বৈধতা পূরণ না করে এমন স্ট্রিংগুলি ব্যতিক্রমী দৃশ্য নয়। এরকম IsValidঢালাই একটু আগে unweildy হয়।
  • কোনও কিছু কেন অবৈধ তা এটি আপনাকে বলতে পারে না।
  • ডিফল্টটি ValidatedStringবৈধ / বৈধ নয়।

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


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

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

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

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

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

0

আপনার উপায় বেশ ভারী এবং নিবিড়। আমি সাধারণত ডোমেন সত্তার সংজ্ঞা দিই:

public class Institution
{
    private Institution() { }

    public Institution(int organizationId, string name)
    {
        OrganizationId = organizationId;            
        Name = name;
        ReplicationKey = Guid.NewGuid();

        new InstitutionValidator().ValidateAndThrow(this);
    }

    public int Id { get; private set; }
    public string Name { get; private set; }        
    public virtual ICollection<Department> Departments { get; private set; }

    ... other properties    

    public Department AddDepartment(string name)
    {
        var department = new Department(Id, name);
        if (Departments == null) Departments = new List<Department>();
        Departments.Add(department);            
        return department;
    }

    ... other domain operations
}

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

এই সত্তার বৈধতা একটি পৃথক শ্রেণি:

public class InstitutionValidator : AbstractValidator<Institution>
{
    public InstitutionValidator()
    {
        RuleFor(institution => institution.Name).NotNull().Length(1, 100).WithLocalizedName(() =>   Prim.Mgp.Infrastructure.Resources.GlobalResources.InstitutionName);       
        RuleFor(institution => institution.OrganizationId).GreaterThan(0);
        RuleFor(institution => institution.ReplicationKey).NotNull().NotEqual(Guid.Empty);
    }  
}

এই বৈধকারীদের সহজেই পুনরায় ব্যবহার করা যেতে পারে এবং আপনি কম বয়লারপ্লেট কোড লেখেন। এবং আরেকটি সুবিধা হ'ল এটি পাঠযোগ্য।


আমার উত্তরটি কেন ডাউনটা করা হয়েছিল তা বোঝানোর জন্য ডাউনটাওয়্যাররা কি যত্ন নেবে?
এল-ফোর

মান মানের ধরণের প্রতিবন্ধকতা সম্পর্কে প্রশ্ন ছিল এবং আপনি WHY ব্যাখ্যা না করেই কোনও শ্রেণিতে স্যুইচ করলেন। (ডাউনভোটার নয়, কেবল একটি পরামর্শ দিন।)
ডগএম

আমি ব্যাখ্যা করেছি কেন আমি এটিকে আরও ভাল বিকল্প মনে করি এবং এটি ছিল তাঁর অন্যতম প্রশ্ন। জবাবের জন্য ধন্যবাদ.
এল-ফোর

0

আমি মান ধরণের এই পদ্ধতির পছন্দ করি। ধারণাটি দুর্দান্ত, তবে বাস্তবায়ন সম্পর্কে আমার কাছে কিছু পরামর্শ / অভিযোগ রয়েছে।

কাস্টিং : আমি এই ক্ষেত্রে ingালাইয়ের ব্যবহার পছন্দ করি না। সুস্পষ্ট স্ট্রিং কাস্ট কোনও সমস্যা নয়, তবে (ValidatedName)nameValueনতুন এবং নতুনের মধ্যে খুব বেশি পার্থক্য নেই ValidatedName(nameValue)। সুতরাং এটি একরকম অপ্রয়োজনীয় বলে মনে হচ্ছে। অন্তর্ভুক্ত টু-স্ট্রিং কাস্টটি সবচেয়ে খারাপ সমস্যা। আমি মনে করি প্রকৃত স্ট্রিংয়ের মানটি আরও স্পষ্ট হওয়া উচিত, কারণ এটি ঘটনাক্রমে স্ট্রিংকে নির্ধারিত হতে পারে এবং সংকলক আপনাকে সম্ভাব্য "নির্ভুলতা হ্রাস" সম্পর্কে সতর্ক করবে না won't এই ধরণের নির্ভুল ক্ষতি অবশ্যই স্পষ্ট হওয়া উচিত।

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

সমান এবং গেটহ্যাশকোড : স্ট্রাক্টগুলি ডিফল্টরূপে কাঠামোগত সমতা ব্যবহার করে। সুতরাং আপনার Equalsএবং GetHashCodeএই ডিফল্ট আচরণ নকল করা হয়। আপনি এগুলি সরাতে পারেন এবং এটি বেশ একই জিনিস হবে।


কাস্টিং: শব্দার্থগতভাবে এটি আমার কাছে নতুন ভ্যালিডেটনেম তৈরির পরিবর্তে একটি ভ্যালিডেটনামে স্ট্রিংয়ের পরিবর্তনের মতো আরও বেশি অনুভূত হয়: আমরা একটি বিদ্যমান স্ট্রিংকে একটি বৈধীকৃত নাম হিসাবে চিহ্নিত করছি ying অতএব আমার কাছে কাস্টটি শব্দার্থিকভাবে আরও সঠিক বলে মনে হচ্ছে। (কীবোর্ডের বিভিন্ন ক্ষেত্রে আঙ্গুলের) টাইপ করার ক্ষেত্রে সামান্য পার্থক্য রয়েছে বলে স্বীকার করেছেন। আমি টু-স্ট্রিং কাস্টের সাথে একমত নই:
ValidatedName

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

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

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

হ্যাঁ হ্যাঁ, সমান বিষয়ে ভাল পয়েন্ট। পূর্বনির্ধারিত আচরণের তুলনায় ওভাররাইড আরও ভাল সঞ্চালন করা উচিত যদিও তুলনা করতে প্রতিচ্ছবি ব্যবহার করা উচিত। কাস্টিং: হ্যাঁ সম্ভবত এটি সুস্পষ্ট কাস্ট করার জন্য একটি ভাল যুক্তি।
gmoody1979
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.