কোনও প্রকার থেকে কীভাবে একটি নতুন অবজেক্ট উদাহরণ তৈরি করা যায়


747

Typeসংকলন-সময় সময়ে কোনও জিনিস সর্বদা জানতে না পারে তবে এর একটি উদাহরণ তৈরি করার প্রয়োজন হতে পারে Type

আপনি কীভাবে একটি নতুন বস্তুর উদাহরণ পাবেন Type?

উত্তর:


894

Activatorরুট মধ্যে বর্গ Systemনামস্থান চমত্কার শক্তিশালী।

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

http://msdn.microsoft.com/en-us/library/system.activator.createinstance.aspx

বা (নতুন পথ)

https://docs.microsoft.com/en-us/dotnet/api/system.activator.createinstance

এখানে কয়েকটি সহজ উদাহরণ দেওয়া হল:

ObjectType instance = (ObjectType)Activator.CreateInstance(objectType);

ObjectType instance = (ObjectType)Activator.CreateInstance("MyAssembly","MyNamespace.ObjectType");

20
অবশেষে এটির সন্ধান পেয়ে খুব ভাল লাগল, তবে দ্বিতীয় কলটি ঠিক সঠিক নয়, একটি উদ্ধৃতি এবং পার্সগুলি বিপরীত অনুপস্থিত, হওয়া উচিত: অবজেক্টটাইপ উদাহরণ = (অবজেক্টটাইপ) অ্যাক্টিভেটর।
কেভিঙ্ক

9
আপনার পছন্দসই ধরণের অবজেক্টটি পেতে 'আনআরপ ()' কল করতে হবে: কংক্রিট টাইপ উদাহরণ = (কনক্রিটটাইপ) অ্যাক্টিভেটর.ক্রিয়েটইনস্ট্যান্স (অবজেক্ট টাইপ) .উনআর্যাপ ();
Г И І И О

4
ObjectType instanceওপি'র শর্তটি কীভাবে মিশে যায় "সংকলন সময়ে কোনও জিনিসটির ধরণটি সর্বদা জানা থাকতে পারে না"? : পি
মার্টিন স্নাইডার

@ এমএ-মাদদিন ঠিক আছে, তখন object instance = Activator.CreateInstance(...);
BrainSlugs83

1
NET কোর এ কীভাবে করতে হয় যে কেউ জানেন? আন-র্যাপ পদ্ধতিটি অবজেক্টে উপলভ্য নয়।
জাস্টিন

145
ObjectType instance = (ObjectType)Activator.CreateInstance(objectType);

Activatorবর্গ একটি জেনেরিক বৈকল্পিক করে তোলে এই অল্প সহজ আছে:

ObjectType instance = Activator.CreateInstance<ObjectType>();

8
@ কেভিন অবশ্যই এ জাতীয় ক্রিয়াকলাপ কোনও স্ট্যাটিকালি টাইপ করা ভাষায় কাজ করতে পারে না কারণ এটির কোনও অর্থ নেই। আপনি অজানা টাইপের কোনও অবজেক্টে পদ্ধতিগুলি চালিত করতে পারবেন না। ইতিমধ্যে (= এই উত্তরটি লেখার পরে থেকে) সি # এমন dynamicকনস্ট্রাক্ট পেয়েছে যা এই জাতীয় নির্মাণের অনুমতি দেয় তবে বেশিরভাগ উদ্দেশ্যে এখনও এই উত্তরটি এটি কভার করে।
কনরাড রুডল্ফ

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

1
@ অ্যানোরজাকেন আমার মন্তব্য রানটাইমে টাইপ তৈরি করার বিষয়ে কিছুই বলেনি। অবশ্যই আপনি এটি করতে পারেন, তবে আপনি এগুলি একই প্রসঙ্গে স্ট্যাটিকভাবে ব্যবহার করতে পারবেন না (আপনি অবশ্যই একটি সম্পূর্ণ স্ট্যাটিকালি সংকলিত প্রোগ্রাম হোস্ট করতে পারেন)। এটাই আমার মন্তব্য বলছে।
কনরাড রুডল্ফ

@ কনরাড রুডল্ফ আফসোস, এমন ধরণের ইন্সট্যান্টেশন বোঝানোর জন্য যা "রানটাইম" এ কেবল পরিচিত; জেনেরিক টাইপ পরামিতি হিসাবে একটি রানটাইম টাইপ ব্যবহার করার অর্থ পরিবর্তে।
আনোরজাকান

1
@ অ্যানোরজাকেন - প্রযুক্তিগতভাবে আপনি উভয়ই রানটাইমের সময় নতুন প্রকার তৈরি করতে পারেন এবং স্থিতিশীলভাবে নিরাপদ উপায়ে কল পদ্ধতিগুলি করতে পারেন যদি আপনার নতুন প্রকারটি একটি পরিচিত ইন্টারফেস প্রয়োগ করে বা পরিচিত বেস শ্রেণীর উত্তরাধিকার সূত্রে প্রাপ্ত হয়। - এই পদ্ধতির কোনও একটিই আপনাকে আপনার রানটাইম তৈরি করা অবজেক্টের জন্য একটি স্ট্যাটিক চুক্তি দেবে।
BrainSlugs83

132

সংকলিত এক্সপ্রেশন সেরা উপায়! (রানটাইমে বারবার উদাহরণ তৈরি করার জন্য পারফরম্যান্সের জন্য)।

static readonly Func<X> YCreator = Expression.Lambda<Func<X>>(
   Expression.New(typeof(Y).GetConstructor(Type.EmptyTypes))
 ).Compile();

X x = YCreator();

পরিসংখ্যান (2012):

    Iterations: 5000000
    00:00:00.8481762, Activator.CreateInstance(string, string)
    00:00:00.8416930, Activator.CreateInstance(type)
    00:00:06.6236752, ConstructorInfo.Invoke
    00:00:00.1776255, Compiled expression
    00:00:00.0462197, new

পরিসংখ্যান (2015,। নেট 4.5, x64):

    Iterations: 5000000
    00:00:00.2659981, Activator.CreateInstance(string, string)
    00:00:00.2603770, Activator.CreateInstance(type)
    00:00:00.7478936, ConstructorInfo.Invoke
    00:00:00.0700757, Compiled expression
    00:00:00.0286710, new

পরিসংখ্যান (2015,। নেট 4.5, x86):

    Iterations: 5000000
    00:00:00.3541501, Activator.CreateInstance(string, string)
    00:00:00.3686861, Activator.CreateInstance(type)
    00:00:00.9492354, ConstructorInfo.Invoke
    00:00:00.0719072, Compiled expression
    00:00:00.0229387, new

পরিসংখ্যান (2017, লিনকিউপ্যাড 5.22.02 / এক্স 64 /। নেট 4.6):

    Iterations: 5000000
    No args
    00:00:00.3897563, Activator.CreateInstance(string assemblyName, string typeName)
    00:00:00.3500748, Activator.CreateInstance(Type type)
    00:00:01.0100714, ConstructorInfo.Invoke
    00:00:00.1375767, Compiled expression
    00:00:00.1337920, Compiled expression (type)
    00:00:00.0593664, new
    Single arg
    00:00:03.9300630, Activator.CreateInstance(Type type)
    00:00:01.3881770, ConstructorInfo.Invoke
    00:00:00.1425534, Compiled expression
    00:00:00.0717409, new

পরিসংখ্যান (2019, x64 /। নেট 4.8):

Iterations: 5000000
No args
00:00:00.3287835, Activator.CreateInstance(string assemblyName, string typeName)
00:00:00.3122015, Activator.CreateInstance(Type type)
00:00:00.8035712, ConstructorInfo.Invoke
00:00:00.0692854, Compiled expression
00:00:00.0662223, Compiled expression (type)
00:00:00.0337862, new
Single arg
00:00:03.8081959, Activator.CreateInstance(Type type)
00:00:01.2507642, ConstructorInfo.Invoke
00:00:00.0671756, Compiled expression
00:00:00.0301489, new

পরিসংখ্যান (2019, x64 /। নেট কোর 3.0):

Iterations: 5000000
No args
00:00:00.3226895, Activator.CreateInstance(string assemblyName, string typeName)
00:00:00.2786803, Activator.CreateInstance(Type type)
00:00:00.6183554, ConstructorInfo.Invoke
00:00:00.0483217, Compiled expression
00:00:00.0485119, Compiled expression (type)
00:00:00.0434534, new
Single arg
00:00:03.4389401, Activator.CreateInstance(Type type)
00:00:01.0803609, ConstructorInfo.Invoke
00:00:00.0554756, Compiled expression
00:00:00.0462232, new

সম্পূর্ণ কোড:

static X CreateY_New()
{
    return new Y();
}

static X CreateY_New_Arg(int z)
{
    return new Y(z);
}

static X CreateY_CreateInstance()
{
    return (X)Activator.CreateInstance(typeof(Y));
}

static X CreateY_CreateInstance_String()
{
    return (X)Activator.CreateInstance("Program", "Y").Unwrap();
}

static X CreateY_CreateInstance_Arg(int z)
{
    return (X)Activator.CreateInstance(typeof(Y), new object[] { z, });
}

private static readonly System.Reflection.ConstructorInfo YConstructor =
    typeof(Y).GetConstructor(Type.EmptyTypes);
private static readonly object[] Empty = new object[] { };
static X CreateY_Invoke()
{
    return (X)YConstructor.Invoke(Empty);
}

private static readonly System.Reflection.ConstructorInfo YConstructor_Arg =
    typeof(Y).GetConstructor(new[] { typeof(int), });
static X CreateY_Invoke_Arg(int z)
{
    return (X)YConstructor_Arg.Invoke(new object[] { z, });
}

private static readonly Func<X> YCreator = Expression.Lambda<Func<X>>(
   Expression.New(typeof(Y).GetConstructor(Type.EmptyTypes))
).Compile();
static X CreateY_CompiledExpression()
{
    return YCreator();
}

private static readonly Func<X> YCreator_Type = Expression.Lambda<Func<X>>(
   Expression.New(typeof(Y))
).Compile();
static X CreateY_CompiledExpression_Type()
{
    return YCreator_Type();
}

private static readonly ParameterExpression YCreator_Arg_Param = Expression.Parameter(typeof(int), "z");
private static readonly Func<int, X> YCreator_Arg = Expression.Lambda<Func<int, X>>(
   Expression.New(typeof(Y).GetConstructor(new[] { typeof(int), }), new[] { YCreator_Arg_Param, }),
   YCreator_Arg_Param
).Compile();
static X CreateY_CompiledExpression_Arg(int z)
{
    return YCreator_Arg(z);
}

static void Main(string[] args)
{
    const int iterations = 5000000;

    Console.WriteLine("Iterations: {0}", iterations);

    Console.WriteLine("No args");
    foreach (var creatorInfo in new[]
    {
        new {Name = "Activator.CreateInstance(string assemblyName, string typeName)", Creator = (Func<X>)CreateY_CreateInstance},
        new {Name = "Activator.CreateInstance(Type type)", Creator = (Func<X>)CreateY_CreateInstance},
        new {Name = "ConstructorInfo.Invoke", Creator = (Func<X>)CreateY_Invoke},
        new {Name = "Compiled expression", Creator = (Func<X>)CreateY_CompiledExpression},
        new {Name = "Compiled expression (type)", Creator = (Func<X>)CreateY_CompiledExpression_Type},
        new {Name = "new", Creator = (Func<X>)CreateY_New},
    })
    {
        var creator = creatorInfo.Creator;

        var sum = 0;
        for (var i = 0; i < 1000; i++)
            sum += creator().Z;

        var stopwatch = new Stopwatch();
        stopwatch.Start();
        for (var i = 0; i < iterations; ++i)
        {
            var x = creator();
            sum += x.Z;
        }
        stopwatch.Stop();
        Console.WriteLine("{0}, {1}", stopwatch.Elapsed, creatorInfo.Name);
    }

    Console.WriteLine("Single arg");
    foreach (var creatorInfo in new[]
    {
        new {Name = "Activator.CreateInstance(Type type)", Creator = (Func<int, X>)CreateY_CreateInstance_Arg},
        new {Name = "ConstructorInfo.Invoke", Creator = (Func<int, X>)CreateY_Invoke_Arg},
        new {Name = "Compiled expression", Creator = (Func<int, X>)CreateY_CompiledExpression_Arg},
        new {Name = "new", Creator = (Func<int, X>)CreateY_New_Arg},
    })
    {
        var creator = creatorInfo.Creator;

        var sum = 0;
        for (var i = 0; i < 1000; i++)
            sum += creator(i).Z;

        var stopwatch = new Stopwatch();
        stopwatch.Start();
        for (var i = 0; i < iterations; ++i)
        {
            var x = creator(i);
            sum += x.Z;
        }
        stopwatch.Stop();
        Console.WriteLine("{0}, {1}", stopwatch.Elapsed, creatorInfo.Name);
    }
}

public class X
{
  public X() { }
  public X(int z) { this.Z = z; }
  public int Z;
}

public class Y : X
{
    public Y() {}
    public Y(int z) : base(z) {}
}

18
সব পরিসংখ্যানের জন্য +1! এই মুহূর্তে আমার এই ধরণের পারফরম্যান্সের দরকার নেই, তবে এখনও খুব আকর্ষণীয়। :)
আনোরজাকেন

1
এছাড়াও TypeDescriptor.CreateInstance (দেখতে stackoverflow.com/a/17797389/1242 ) যা দ্রুততর যদি TypeDescriptor.AddProvider সাথে ব্যবহার করা যাবে
লার্স Truijens

2
Xরানটাইমের সময় কী ধরণের তা আপনি জানেন না যখন এটি এখনও কার্যকর ?
আজিহ

1
@ আজেহ হ্যাঁ টাইপফোন (টি) কে টাইপ করুন.গেটটাইপ (..) করুন।
সেরজ-টিএম

3
@ সার্জ-টিএম নং, টাইপ এক্স রানটাইম হলে এটি কাজ করবে না Type
নেটমেজ

47

এই সমস্যার একটি বাস্তবায়ন হ'ল ধরণের প্যারামিটার-কম কনস্ট্রাক্টরকে কল করার চেষ্টা করা:

public static object GetNewObject(Type t)
{
    try
    {
        return t.GetConstructor(new Type[] { }).Invoke(new object[] { });
    }
    catch
    {
        return null;
    }
}

এখানে একটি সাধারণ পদ্ধতি রয়েছে যা জেনেরিক পদ্ধতিতে রয়েছে:

public static T GetNewObject<T>()
{
    try
    {
        return (T)typeof(T).GetConstructor(new Type[] { }).Invoke(new object[] { });
    }
    catch
    {
        return default(T);
    }
}

15
ব্যতিক্রম চালিত প্রোগ্রামিং? এটি খুব খারাপ বাস্তবায়নের মতো মনে হয় যখন আপনি কেবল নির্মাতারা নির্ধারণের জন্য ধরণের প্রতিফলন করতে পারেন।
ফিরোসো

16

এটি বেশ সহজ। ধরে নিন যে আপনার ক্লাসের নামটি Carএবং নাম স্থানটি Vehicles, তারপরে প্যারামিটারটি পাস করুন Vehicles.Carযা টাইপের অবজেক্টটি প্রত্যাবর্তন করে Car। এটির মতো আপনি যে কোনও শ্রেণীর যে কোনও উদাহরণ গতিশীলভাবে তৈরি করতে পারেন।

public object GetInstance(string strNamesapace)
{         
     Type t = Type.GetType(strNamesapace); 
     return  Activator.CreateInstance(t);         
}

যদি আপনার সম্পূর্ণ যোগ্য নাম (যেমন, Vehicles.Carএই ক্ষেত্রে) অন্য কোনও সমাবেশে থাকে, তবে Type.GetTypeতা বাতিল হবে। এই ধরনের ক্ষেত্রে, আপনি সমস্ত অ্যাসেম্বলির মধ্য দিয়ে লুপ পেয়েছেন এবং এটি সন্ধান করুন Type। তার জন্য আপনি নীচের কোডটি ব্যবহার করতে পারেন

public object GetInstance(string strFullyQualifiedName)
{
     Type type = Type.GetType(strFullyQualifiedName);
     if (type != null)
         return Activator.CreateInstance(type);
     foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
     {
         type = asm.GetType(strFullyQualifiedName);
         if (type != null)
             return Activator.CreateInstance(type);
     }
     return null;
 }

এবং উপরের পদ্ধতিটি কল করে আপনি উদাহরণটি পেতে পারেন।

object objClassInstance = GetInstance("Vehicles.Car");

আপনার দ্বিতীয় ক্ষেত্রে (বাহ্যিক সমাবেশ), আপনি নিজের প্রথম পদ্ধতিতে স্রেফ "যানবাহন.কার, অন্যান্যরকম" ব্যবহার করতে পারেন এবং এটি কার্যকর হবে। স্পষ্টতই অন্যান্য অ্যাস্প্যাসব্লেলে এটি যে সমাবেশে বাস করে তার নাম
ড্যানিমাইজার

2
@ এডমিনিজার এর পক্ষে সমাবেশের নামটির কঠোর কোডিং দরকার needs নমনীয়তা বাস্তবায়নের জন্য আমি
নালটি

14

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


11

জেনেরিক T t = new T();কাজ করবে না ?


9
প্রকৃতপক্ষে, এটি জেনেরিক শ্রেণি / পদ্ধতিতে হবে তবে প্রদত্ত "প্রকারের" জন্য নয়।
ব্র্যাডি মরিটজ

ধরে নেওয়া যায় যে টাইপ টিতে 'নতুন ()' সীমাবদ্ধতা রয়েছে।
রব ভন নেসেলরোড

10

আপনি যদি ডিফল্ট কনস্ট্রাক্টর ব্যবহার করতে চান তবে System.Activatorপূর্বে উপস্থাপিত সমাধানটি ব্যবহার করা সম্ভবত সবচেয়ে সুবিধাজনক। যাইহোক, যদি টাইপটিতে একটি ডিফল্ট নির্মাণকারীর অভাব থাকে বা আপনাকে একটি ডিফল্ট ব্যবহার করতে হয়, তারপরে একটি বিকল্প হ'ল প্রতিচ্ছবি ব্যবহার করা বা System.ComponentModel.TypeDescriptor। প্রতিবিম্বের ক্ষেত্রে, কেবলমাত্র প্রকারের নামটি (তার নামের স্থান সহ) জানা যথেষ্ট।

প্রতিবিম্ব ব্যবহার করে উদাহরণ:

ObjectType instance = 
    (ObjectType)System.Reflection.Assembly.GetExecutingAssembly().CreateInstance(
        typeName: objectType.FulName, // string including namespace of the type
        ignoreCase: false,
        bindingAttr: BindingFlags.Default,
        binder: null,  // use default binder
        args: new object[] { args, to, constructor },
        culture: null, // use CultureInfo from current thread
        activationAttributes: null
    );

ব্যবহারের উদাহরণ TypeDescriptor:

ObjectType instance = 
    (ObjectType)System.ComponentModel.TypeDescriptor.CreateInstance(
        provider: null, // use standard type description provider, which uses reflection
        objectType: objectType,
        argTypes: new Type[] { types, of, args },
        args: new object[] { args, to, constructor }
    );

args[]আমি ঠিক এই প্রশ্নের সন্ধান করতে এসেছি, ধন্যবাদ!
চাদ

10

প্রতিবিম্ব ব্যবহার ছাড়া:

private T Create<T>() where T : class, new()
{
    return new T();
}

5
এটা কিভাবে দরকারী? আপনাকে সেই পদ্ধতিটি কল করতে ইতিমধ্যে টাইপটি জানতে হবে এবং আপনি যদি টাইপটি জানেন তবে আপনি কোনও বিশেষ পদ্ধতি ছাড়াই এটি নির্মাণ করতে পারেন।
কাইল

তাই রান রানটাইমে টি আলাদা হতে পারে। যদি আপনি উদ্ভূত প্রকারের সাথে কাজ করেন তবে দরকারী।

একটি নতুন টি (); ব্যর্থ হবে যদি টি প্যারামিটারলেস কনস্ট্রাক্টরের সাথে কোনও রেফারেন্স টাইপ না হয়, টি টি রেফারেন্স টাইপ এবং কনস্ট্রাক্টর রয়েছে তা নিশ্চিত করতে এই পদ্ধতিগুলি প্রতিবন্ধকতা ব্যবহার করে।

3
রান টাইমে টি কীভাবে আলাদা হতে পারে? << কল করুন কল করার জন্য আপনার কি ডিজাইনের সময় টি জানতে হবে না?
কাইল

আপনি যদি কারখানায় জেনেরিক ক্লাস এবং ইন্টারফেসের সাথে কাজ করেন, তবে ইন্টারফেসটি প্রয়োগ করার ধরণগুলি পৃথক হতে পারে।

8

এই সমস্যাটি দেওয়া অবস্থায় অ্যাক্টিভেটর যখন প্যারামিটারলেস কর্টর থাকে তখন কাজ করবে। এটি যদি সীমাবদ্ধ থাকে তবে ব্যবহার বিবেচনা করুন

System.Runtime.Serialization.FormatterServices.GetSafeUninitializedObject()


4

আমি এই প্রশ্নটি পার করতে পারি কারণ আমি স্বেচ্ছাসেবী শ্রেণীর জন্য একটি সাধারণ ক্লোনঅজেক্ট পদ্ধতি প্রয়োগ করতে চেয়েছিলাম (একটি ডিফল্ট নির্মাণকারী সহ)

জেনেরিক পদ্ধতিতে আপনার প্রয়োজন হতে পারে যে টাইপটি নতুন () প্রয়োগ করে।

Public Function CloneObject(Of T As New)(ByVal src As T) As T
    Dim result As T = Nothing
    Dim cloneable = TryCast(src, ICloneable)
    If cloneable IsNot Nothing Then
        result = cloneable.Clone()
    Else
        result = New T
        CopySimpleProperties(src, result, Nothing, "clone")
    End If
    Return result
End Function

জেনারিক হিসাবে ধরে নিলে ধরণের ডিফল্ট নির্মাতা রয়েছে এবং যদি এটি না ঘটে তবে একটি ব্যতিক্রম ধরুন catch

Public Function CloneObject(ByVal src As Object) As Object
    Dim result As Object = Nothing
    Dim cloneable As ICloneable
    Try
        cloneable = TryCast(src, ICloneable)
        If cloneable IsNot Nothing Then
            result = cloneable.Clone()
        Else
            result = Activator.CreateInstance(src.GetType())
            CopySimpleProperties(src, result, Nothing, "clone")
        End If
    Catch ex As Exception
        Trace.WriteLine("!!! CloneObject(): " & ex.Message)
    End Try
    Return result
End Function
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.