টেম্পলেটেড ধরণের সি # জেনেরিক নতুন () এ আর্গুমেন্টগুলি পাস করা


409

তালিকায় যুক্ত করার সময় আমি এর নির্মাণকারীর মাধ্যমে টি টাইপের একটি নতুন অবজেক্ট তৈরি করার চেষ্টা করছি।

আমি একটি সংকলন ত্রুটি পাচ্ছি: ত্রুটি বার্তাটি হ'ল:

'টি': ভেরিয়েবলের উদাহরণ তৈরি করার সময় আর্গুমেন্ট সরবরাহ করতে পারে না

তবে আমার ক্লাসে কনস্ট্রাক্টর যুক্তি আছে! আমি এই কাজটি কীভাবে করব?

public static string GetAllItems<T>(...) where T : new()
{
   ...
   List<T> tabListItems = new List<T>();
   foreach (ListItem listItem in listCollection) 
   {
       tabListItems.Add(new T(listItem)); // error here.
   } 
   ...
}


2
ভাষায় এই কার্যকারিতাটি পাওয়ার প্রস্তাব: github.com/dotnet/roslyn/issues/2206
ইয়ান কেম্প

মাইক্রোসফ্টের ডকুমেন্টেশনে, সংকলক ত্রুটি CS0417 দেখুন
ডেভিডআরআর

1
ভাষায় এই কার্যকারিতাটি পাওয়ার প্রস্তাবটি এতে স্থানান্তরিত হয়েছিল: github.com/dotnet/csharplang/issues/769
ক্রিয়াকলাপ হ্রাস

উত্তর:


410

কোনও ফাংশনে জেনেরিক ধরণের উদাহরণ তৈরি করার জন্য আপনাকে অবশ্যই এটি "নতুন" পতাকা দিয়ে সীমাবদ্ধ করতে হবে।

public static string GetAllItems<T>(...) where T : new()

তবে এটি তখনই কাজ করবে যখন আপনি কোনও কনস্ট্রাক্টরকে কল করতে চান যার কোনও প্যারামিটার নেই। এখানে মামলা হয় না। পরিবর্তে আপনাকে অন্য একটি প্যারামিটার সরবরাহ করতে হবে যা পরামিতিগুলির উপর ভিত্তি করে অবজেক্ট তৈরি করার অনুমতি দেয়। সবচেয়ে সহজ একটি ফাংশন।

public static string GetAllItems<T>(..., Func<ListItem,T> del) {
  ...
  List<T> tabListItems = new List<T>();
  foreach (ListItem listItem in listCollection) 
  {
    tabListItems.Add(del(listItem));
  }
  ...
}

তারপরে আপনি এটির মতো কল করতে পারেন

GetAllItems<Foo>(..., l => new Foo(l));

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

অপর এক প্রশ্নের আমার কোড যোগ stackoverflow.com/questions/1682310/...
ChrisCa

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

1
ধন্যবাদ। আমার ক্ষেত্রে আমি কন্সট্রাক্টরের যুক্তি (গুলি) জানি যখন আমি পদ্ধতিটি কল করি, তখন কেবল টাইপ প্যারামিটারের সীমাবদ্ধতাটি পাওয়া দরকার যে এটি পরামিতিগুলির সাহায্যে তৈরি করা যায় না, তাই আমি একটি থাঙ্ক ব্যবহার করেছি । থাঙ্কটি পদ্ধতির একটি alচ্ছিক পরামিতি, এবং আমি কেবল এটি সরবরাহ করলেই ব্যবহার করি: T result = thunk == null ? new T() : thunk(); আমার পক্ষে এটির সুবিধাটি Tকখনও Tকখনও পদ্ধতির অভ্যন্তরে এবং কখনও কখনও বাইরে তৈরির পরিবর্তে এক জায়গায় সৃষ্টির যুক্তি সংহত করা ।
কার্ল জি

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

331

নেট। 3.5 এবং পরে আপনি অ্যাক্টিভেটর শ্রেণি ব্যবহার করতে পারেন:

(T)Activator.CreateInstance(typeof(T), args)

1
আমরা বস্তুটি তৈরি করতে এক্সপ্রেশন
ট্রিও

4
আরগস কি? একটি বস্তু []?
রডনি পি বারবতি

3
হ্যাঁ, আরোগুলি হ'ল একটি বস্তু [] যেখানে আপনি টি এর নির্মাণকারীর কাছে প্রদত্ত মানগুলি নির্দিষ্ট করেন: "নতুন অবজেক্ট [] {par1, par2}"
টেকনাইকুইস্ট


3
সতর্কতা: যদি আপনার কেবলমাত্র এই একটি কাজের জন্য ডেডিকেটেড কনস্ট্রাক্টর থাকে তবে এটি Activator.CreateInstanceদেখতে আপনার নির্মাণকারীর মতো ব্যবহার করা হয়নি এবং কেউ "ক্লিন আপ" করে মুছে ফেলার চেষ্টা করতে পারে (রানটাইম ত্রুটির কারণ হতে পারে) ভবিষ্যতে কিছু এলোমেলো সময়)। আপনি এই কন্সট্রাক্টরটি ব্যবহার করেন এমন একটি ডামি ফাংশন যুক্ত করার বিষয়ে বিবেচনা করতে পারেন যাতে আপনি মুছে ফেলার চেষ্টা করেন তবে একটি সংকলন ত্রুটি পাবেন।
জুন 12 ই

51

যেহেতু কেউই 'প্রতিবিম্ব' উত্তর পোস্ট করতে বিরক্ত করেনি (যা আমি ব্যক্তিগতভাবে সেরা উত্তর বলে মনে করি), তাই এখানে যায়:

public static string GetAllItems<T>(...) where T : new()
{
   ...
   List<T> tabListItems = new List<T>();
   foreach (ListItem listItem in listCollection) 
   {
       Type classType = typeof(T);
       ConstructorInfo classConstructor = classType.GetConstructor(new Type[] { listItem.GetType() });
       T classInstance = (T)classConstructor.Invoke(new object[] { listItem });

       tabListItems.Add(classInstance);
   } 
   ...
}

সম্পাদনা: এই উত্তরটি .NET 3.5 এর অ্যাক্টিভেটর.ক্রিয়েটআইনস্ট্যান্সের কারণে নষ্ট হয়েছে, তবে এটি এখনও পুরানো .NET সংস্করণগুলিতে কার্যকর।


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

19
আমি মনে করি সংকলন-সময় চেকিংয়ের অভাব উদ্বেগের কারণ।
ডেভ ভ্যান ডেন এয়েন্দে

1
@ জেমস আমি সম্মত, এটিকে "উত্তর" হিসাবে না দেখে আমি অবাক হয়েছি। প্রকৃতপক্ষে, আমি এই প্রশ্নটি অনুসন্ধান করেছিলাম একটি দুর্দান্ত সহজ উদাহরণ (আপনার মতো) খুঁজে পাওয়ার প্রত্যাশায়, যেহেতু আমি প্রতিফলন করেছি দীর্ঘকাল ধরে। যাইহোক, আমার কাছ থেকে +1, তবে অ্যাক্টিভেটরের উত্তরটিতেও +1। অ্যাক্টিভেটর কী করছে তা আমি খতিয়ে দেখলাম এবং দেখা যাচ্ছে যে যা করছে তা খুব ভাল ইঞ্জিনিয়ারড প্রতিচ্ছবি। :)
মাইক 6

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

30

অবজেক্ট ইনিশিয়ালাইজার

যদি প্যারামিটার সহ আপনার কনস্ট্রাক্টর কোনও সম্পত্তি নির্ধারণের পাশাপাশি কিছু না করে থাকেন তবে আপনি এটি সি # 3 এ বা কনস্ট্রাক্টরকে কল করার চেয়ে অবজেক্ট ইনিশিয়ালাইজার ব্যবহার করে আরও ভাল করতে পারেন (যা অসম্ভব, যেমনটি বলা হয়েছে):

public static string GetAllItems<T>(...) where T : new()
{
   ...
   List<T> tabListItems = new List<T>();
   foreach (ListItem listItem in listCollection) 
   {
       tabListItems.Add(new T() { YourPropertyName = listItem } ); // Now using object initializer
   } 
   ...
}

এটি ব্যবহার করে আপনি সর্বদা যে কোনও কনস্ট্রাক্টর লজিক ডিফল্ট (খালি) কনস্ট্রাক্টরে রাখতে পারেন।

Activator.CreateInstance ()

অন্যথা, আপনি বলতে পেরেছিলাম Activator.CreateInstance () যেমন:

public static string GetAllItems<T>(...) where T : new()
{
   ...
   List<T> tabListItems = new List<T>();
   foreach (ListItem listItem in listCollection) 
   {
        object[] args = new object[] { listItem };
        tabListItems.Add((T)Activator.CreateInstance(typeof(T), args)); // Now using Activator.CreateInstance
   } 
   ...
}

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


Tএটি এর আক্রমণকারীদের রক্ষা করতে বাধা দেয় (এটিতে T> 0 নির্ভরতা বা প্রয়োজনীয় মানগুলি রয়েছে তবে আপনি এখন Tএটি একটি অবৈধ / অব্যবহারযোগ্য অবস্থার উদাহরণ তৈরি করতে পারেন Tunless যদি না কোনও ডিটিও ওচ ভিডমোডেলের মতো মৃত সাধারণ কিছু না হয় তবে আমি বলব এটিকে এড়িয়ে চলুন।
সারা

20

খুব পুরানো প্রশ্ন, তবে নতুন উত্তর ;-)

এক্সপ্রেশনট্রি সংস্করণ : (আমি মনে করি দ্রুততম এবং পরিষ্কার সমাধান)

যেমন ওয়েলির তম্বুনান বলেছিলেন, "আমরা বস্তুটি তৈরি করতে অভিব্যক্তি গাছও ব্যবহার করতে পারি"

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

এটা এখানে:

// this delegate is just, so you don't have to pass an object array. _(params)_
public delegate object ConstructorDelegate(params object[] args);

public static ConstructorDelegate CreateConstructor(Type type, params Type[] parameters)
{
    // Get the constructor info for these parameters
    var constructorInfo = type.GetConstructor(parameters);

    // define a object[] parameter
    var paramExpr = Expression.Parameter(typeof(Object[]));

    // To feed the constructor with the right parameters, we need to generate an array 
    // of parameters that will be read from the initialize object array argument.
    var constructorParameters = parameters.Select((paramType, index) =>
        // convert the object[index] to the right constructor parameter type.
        Expression.Convert(
            // read a value from the object[index]
            Expression.ArrayAccess(
                paramExpr,
                Expression.Constant(index)),
            paramType)).ToArray();

    // just call the constructor.
    var body = Expression.New(constructorInfo, constructorParameters);

    var constructor = Expression.Lambda<ConstructorDelegate>(body, paramExpr);
    return constructor.Compile();
}

মাইক্লাস উদাহরণ:

public class MyClass
{
    public int TestInt { get; private set; }
    public string TestString { get; private set; }

    public MyClass(int testInt, string testString)
    {
        TestInt = testInt;
        TestString = testString;
    }
}

ব্যবহার:

// you should cache this 'constructor'
var myConstructor = CreateConstructor(typeof(MyClass), typeof(int), typeof(string));

// Call the `myConstructor` function to create a new instance.
var myObject = myConstructor(10, "test message");

এখানে চিত্র বর্ণনা লিখুন


আর একটি উদাহরণ: অ্যারে হিসাবে প্রকারগুলি পাস করা

var type = typeof(MyClass);
var args = new Type[] { typeof(int), typeof(string) };

// you should cache this 'constructor'
var myConstructor = CreateConstructor(type, args);

// Call the `myConstructor` fucntion to create a new instance.
var myObject = myConstructor(10, "test message");

এক্সপ্রেশন ডিবাগভিউ

.Lambda #Lambda1<TestExpressionConstructor.MainWindow+ConstructorDelegate>(System.Object[] $var1) {
    .New TestExpressionConstructor.MainWindow+MyClass(
        (System.Int32)$var1[0],
        (System.String)$var1[1])
}

এটি উত্পন্ন কোডের সমতুল্য:

public object myConstructor(object[] var1)
{
    return new MyClass(
        (System.Int32)var1[0],
        (System.String)var1[1]);
}

ছোট ডাউনসাইড

সমস্ত ভ্যালুটিটাইপ প্যারামিটারগুলি যখন বস্তু অ্যারের মতো পাস করা হয় তখন বাক্স হয়।


সাধারণ পারফরম্যান্স পরীক্ষা:

private void TestActivator()
{
    Stopwatch sw = Stopwatch.StartNew();
    for (int i = 0; i < 1024 * 1024 * 10; i++)
    {
        var myObject = Activator.CreateInstance(typeof(MyClass), 10, "test message");
    }
    sw.Stop();
    Trace.WriteLine("Activator: " + sw.Elapsed);
}

private void TestReflection()
{
    var constructorInfo = typeof(MyClass).GetConstructor(new[] { typeof(int), typeof(string) });

    Stopwatch sw = Stopwatch.StartNew();
    for (int i = 0; i < 1024 * 1024 * 10; i++)
    {
        var myObject = constructorInfo.Invoke(new object[] { 10, "test message" });
    }

    sw.Stop();
    Trace.WriteLine("Reflection: " + sw.Elapsed);
}

private void TestExpression()
{
    var myConstructor = CreateConstructor(typeof(MyClass), typeof(int), typeof(string));

    Stopwatch sw = Stopwatch.StartNew();

    for (int i = 0; i < 1024 * 1024 * 10; i++)
    {
        var myObject = myConstructor(10, "test message");
    }

    sw.Stop();
    Trace.WriteLine("Expression: " + sw.Elapsed);
}

TestActivator();
TestReflection();
TestExpression();

ফলাফল:

Activator: 00:00:13.8210732
Reflection: 00:00:05.2986945
Expression: 00:00:00.6681696

ব্যবহার Expressionsকরা চালানোর চেয়ে +/- 8 গুণ বেশি ConstructorInfoএবং +/- 20 বারের চেয়ে 20 গুণ বেশি দ্রুতActivator


আপনি যদি কন্সট্রাক্টর পাবলিক মাই ক্লাস (টি ডেটা) দিয়ে মাই ক্লাস <টি> নির্মাণ করতে চান তবে কী করবেন সে সম্পর্কে আপনার কোনও অন্তর্দৃষ্টি আছে। এই ক্ষেত্রে, এক্সপ্রেশন.কনভার্ট একটি ব্যতিক্রম ছোঁড়ে এবং আমি রূপান্তর করতে যদি জেনেরিক সীমাবদ্ধতা বেস শ্রেণিটি ব্যবহার করি তবে এক্সপ্রেশন N নতুন ছোঁড়ে কারণ কনস্ট্রাক্টরের তথ্য জেনেরিক টাইপের জন্য রয়েছে
মেসন

@ ম্যাসন (উত্তর দিতে কিছুটা সময় নিয়েছে ;-)) var myConstructor = CreateConstructor(typeof(MyClass<int>), typeof(int));এটি ভাল কাজ করছে। আমি জানি না।
জেরোইন ভ্যান ল্যাঞ্জেন

19

এটি আপনার পরিস্থিতিতে কাজ করবে না। আপনি কেবল সীমাবদ্ধতাটি নির্দিষ্ট করতে পারেন যে এটিতে একটি খালি নির্মাতা রয়েছে:

public static string GetAllItems<T>(...) where T: new()

আপনি যা করতে পারেন তা হ'ল এই ইন্টারফেসটি সংজ্ঞায়িত করে সম্পত্তি ইনজেকশন ব্যবহার করুন:

public interface ITakesAListItem
{
   ListItem Item { set; }
}

তারপরে আপনি নিজের পদ্ধতিটি এটি হতে পরিবর্তন করতে পারেন:

public static string GetAllItems<T>(...) where T : ITakesAListItem, new()
{
   ...
   List<T> tabListItems = new List<T>();
   foreach (ListItem listItem in listCollection) 
   {
       tabListItems.Add(new T() { Item = listItem });
   } 
   ...
}

অন্য বিকল্পটি Funcজারেডপার দ্বারা বর্ণিত পদ্ধতি।


এটি কনস্ট্রাক্টারে থাকা কোনও যুক্তিকে বাইপাস করবে যা আর্গুমেন্টগুলি গ্রহণ করে, তাই না? আমি
জ্যারেডের

3
ডান, এটি টি () ডিফল্ট কনস্ট্রাক্টরের যুক্তিকে কল করে, তারপরে কেবল সম্পত্তিটিকে "আইটেম" সেট করে। যদি আপনি একটি অ-ডিফল্ট নির্মাণকারীর যুক্তিটি চাওয়ার চেষ্টা করছেন তবে এটি আপনাকে সাহায্য করবে না।
স্কট স্টাফোর্ড

7

সংকলকটি জানতে পারবেন যে টি একটি ডিফল্ট কনস্ট্রাক্টর সরবরাহের গ্যারান্টিযুক্ত, সেখানে আপনাকে টি: নতুন () যুক্ত করতে হবে।

public static string GetAllItems<T>(...) where T: new()

1
আপডেট: সঠিক ত্রুটি বার্তাটি: 'টি': ভেরিয়েবলের উদাহরণ তৈরি করার সময় আর্গুমেন্ট সরবরাহ করতে পারে না
এলবি।

এর কারণ আপনি একটি ফাঁকা নির্মাতা ব্যবহার করছেন না, আপনি এটিতে একটি যুক্তি দিয়ে যাচ্ছেন। জেনেরিক টাইপের একটি নতুন (অবজেক্ট) প্যারামিটার রয়েছে তা উল্লেখ না করে এটি হ্যান্ডেল করার কোনও উপায় নেই।
ন্যূনতম

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

প্রতিবিম্ব ব্যবহার করবেন না! অন্যান্য উত্তরে বর্ণিত অন্যান্য উপায় রয়েছে যা আপনাকে একই প্রভাব দেয়।
গ্যারি শাটলার

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

7

আপনি যদি কেবল কনস্ট্রাক্টর প্যারামিটার দিয়ে কোনও সদস্য ক্ষেত্র বা সম্পত্তি শুরু করতে চান তবে সি #> = 3 এ আপনি এটি খুব সহজ করতে পারেন:

public static string GetAllItems<T>(...) where T : InterfaceOrBaseClass, new() 
{ 
   ... 
   List<T> tabListItems = new List<T>(); 
   foreach (ListItem listItem in listCollection)  
   { 
       tabListItems.Add(new T{ BaseMemberItem = listItem }); // No error, BaseMemberItem owns to InterfaceOrBaseClass. 
   }  
   ... 
} 

গ্যারি শটলার এই একই কথা বলেছেন, তবে আমি একটি অ্যাডিশনাল নোট রাখতে চাই।

অবশ্যই আপনি কেবল ক্ষেত্রের মান নির্ধারণের চেয়ে আরও বেশি জিনিস করার জন্য সম্পত্তি কৌশল ব্যবহার করতে পারেন। একটি সম্পত্তি "সেট ()" তার সম্পর্কিত ক্ষেত্রগুলি সেটআপ করার জন্য প্রয়োজনীয় কোনও প্রসেসিং এবং বস্তুর নিজেই অন্য কোনও প্রয়োজনকে ট্রিগার করতে পারে, এতে একটি চেক সহ পুরো বস্তুটি ব্যবহারের আগে সম্পূর্ণ আরম্ভ হবে কিনা তা সম্পূর্ণ পরীক্ষার অনুকরণ করে ( হ্যাঁ, এটি একটি কুরুচিপূর্ণ কাজ, তবে এটি ম $ 'র নতুন () সীমাবদ্ধতা কাটিয়ে উঠেছে)।

আমি নিশ্চিত হতে পারি না এটি যদি কোনও পরিকল্পিত গর্ত বা দুর্ঘটনাজনিত পার্শ্ব প্রতিক্রিয়া হয় তবে তা কার্যকর হয়।

এমএসের লোকেরা কীভাবে ভাষায় নতুন বৈশিষ্ট্য যুক্ত করে এবং পুরো পার্শ্ব প্রতিক্রিয়া বিশ্লেষণ করে না বলে মনে হয় এটি খুব মজাদার। সম্পূর্ণ জেনেরিক জিনিস এটির একটি ভাল প্রমাণ ...


1
উভয় সীমাবদ্ধতা প্রয়োজন। ইন্টারফেসঅরবেসক্লাস কম্পাইলারটিকে ক্ষেত্র / সম্পত্তি বেসমেম্বার আইটেম সম্পর্কে সচেতন করে তোলে। যদি "নতুন ()" সীমাবদ্ধতা মন্তব্য করা হয়, তবে এটি ত্রুটিটি ট্রিগার করবে: ত্রুটি 6 ত্রুটিযুক্ত টাইপ 'টি' এর উদাহরণ তৈরি করতে পারে না কারণ এতে
fljx

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

5
যখনই কেউ মাইক্রোসফ্টকে "এম $" হিসাবে উল্লেখ করে, আমার আত্মার একটি ক্ষুদ্র অংশ ভোগ করে।
ম্যাথিয়াস লাইককেগার্ড লরেঞ্জেন

6

আমি দেখতে পেয়েছি যে আমি একটি ত্রুটি পেয়েছি "টাইপ প্যারামিটার টির উদাহরণ তৈরি করার সময় আর্গুমেন্ট সরবরাহ করতে পারে না" তাই আমার এটি করা দরকার:

var x = Activator.CreateInstance(typeof(T), args) as T;

5

আপনি যে ক্লাসটি ব্যবহার করতে চলেছেন সেটিতে যদি আপনার অ্যাক্সেস থাকে তবে আপনি যে পদ্ধতিটি ব্যবহার করেছেন তা ব্যবহার করতে পারেন।

একটি ইন্টারফেস তৈরি করুন যাতে বিকল্প স্রষ্টা রয়েছে:

public interface ICreatable1Param
{
    void PopulateInstance(object Param);
}

খালি স্রষ্টার সাথে আপনার ক্লাস তৈরি করুন এবং এই পদ্ধতিটি বাস্তবায়ন করুন:

public class MyClass : ICreatable1Param
{
    public MyClass() { //do something or nothing }
    public void PopulateInstance (object Param)
    {
        //populate the class here
    }
}

এখন আপনার জেনেরিক পদ্ধতিগুলি ব্যবহার করুন:

public void MyMethod<T>(...) where T : ICreatable1Param, new()
{
    //do stuff
    T newT = new T();
    T.PopulateInstance(Param);
}

আপনার যদি অ্যাক্সেস না থাকে তবে লক্ষ্য শ্রেণিটি মোড়ানো:

public class MyClass : ICreatable1Param
{
    public WrappedClass WrappedInstance {get; private set; }
    public MyClass() { //do something or nothing }
    public void PopulateInstance (object Param)
    {
        WrappedInstance = new WrappedClass(Param);
    }
}

0

এটি একধরনের কৌতুকপূর্ণ, এবং যখন আমি একধরনের অশ্লীল কথা বলতে পারি তখন আমি বিদ্রোহ বোঝাতে চাইছি তবে মনে করুন আপনি খালি নির্মাণকারীর সাহায্যে আপনার প্যারামিটারাইজড ধরণটি সরবরাহ করতে পারেন:

public static T GetTInstance<T>() where T: new()
{
    var constructorTypeSignature = new Type[] {typeof (object)};
    var constructorParameters = new object[] {"Create a T"};
    return (T) new T().GetType().GetConstructor(constructorTypeSignature).Invoke(constructorParameters);
}

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


0

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

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

সূচনা করার জন্য একটি সাধারণ অভিধান ব্যবহার করে এমন উদাহরণ:

void Main()
{
    var values = new Dictionary<string, int> { { "BaseValue", 1 }, { "DerivedValue", 2 } };

    Console.WriteLine(CreateObject<Base>(values).ToString());

    Console.WriteLine(CreateObject<Derived>(values).ToString());
}

public T CreateObject<T>(IDictionary<string, int> values)
    where T : Base, new()
{
    var obj = new T();
    obj.Initialize(values);
    return obj;
}

public class Base
{
    public int BaseValue { get; set; }

    public virtual void Initialize(IDictionary<string, int> values)
    {
        BaseValue = values["BaseValue"];
    }

    public override string ToString()
    {
        return "BaseValue = " + BaseValue;
    }
}

public class Derived : Base
{
    public int DerivedValue { get; set; }

    public override void Initialize(IDictionary<string, int> values)
    {
        base.Initialize(values);
        DerivedValue = values["DerivedValue"];
    }

    public override string ToString()
    {       
        return base.ToString() + ", DerivedValue = " + DerivedValue;
    }
}

0

আপনার যদি প্রয়োজন হয় তালিকার আইটেম থেকে আপনার টাইপ টি তে রূপান্তরকরণ আপনি রূপান্তর অপারেটর হিসাবে টি শ্রেণিতে এই রূপান্তরটি প্রয়োগ করতে পারেন।

public class T
{
    public static implicit operator T(ListItem listItem) => /* ... */;
}

public static string GetAllItems(...)
{
    ...
    List<T> tabListItems = new List<T>();
    foreach (ListItem listItem in listCollection) 
    {
        tabListItems.Add(listItem);
    } 
    ...
}

-4

আমি বিশ্বাস করি যে আপনাকে কেবল নতুন নির্মাণকারীর সাহায্যে অবজেক্টগুলিকে মঞ্জুরি দেওয়ার জন্য স্টেটমেন্ট দিয়ে টি সীমাবদ্ধ করতে হবে।

রিজট এখন এটি ছাড়া বস্তুগুলি সহ যে কোনও কিছু গ্রহণ করে।


1
আপনি এই উত্তরটি পরিবর্তন করতে চাইতে পারেন কারণ আপনি উত্তর দেওয়ার পরে এটি প্রশ্নের মধ্যে এডিট হয়ে গেছে যা এই উত্তরটিকে প্রসঙ্গ থেকে বাদ দেয়।
শাটল 8787
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.