একটি ইনস্ট্যান্টিয়েটেড সিস্টেম পাস করুন a জেনেরিক ক্লাসের জন্য টাইপ প্যারামিটার হিসাবে টাইপ করুন


181

শিরোনামটি এক ধরণের অস্পষ্ট। আমি যদি জানতে চাই তা হ'ল যদি এটি সম্ভব হয়:

string typeName = <read type name from somwhere>;
Type myType = Type.GetType(typeName);

MyGenericClass<myType> myGenericClass = new MyGenericClass<myType>();

স্পষ্টতই, মাইগেনেরিক ক্লাস বর্ণনা করা হয়েছে:

public class MyGenericClass<T>

এই মুহুর্তে, সংকলকটি অভিযোগ করে যে 'টাইপ বা নেমস্পেস' মাই টাইপ 'সন্ধান করা যায়নি "" এটি করার উপায় আছে।


জেনারিক্স! = টেমপ্লেট। সমস্ত জেনেরিক ধরণের ভেরিয়েবলগুলি সংকলন সময়ে সমাধান করা হয় রানটাইমের সময় নয়। এটি সেই পরিস্থিতিতে একটি যেখানে 'ডায়নামিক' টাইপ ৪.০ কার্যকর হতে পারে।

1
@ উইল - কীভাবে? জেনেরিকের সাথে যখন ব্যবহার করা হয়, বর্তমান সিটিপি এর অধীনে আপনি মূলত <object> সংস্করণগুলি কল করবেন (যতক্ষণ না আমি কোনও কৌশল মিস করছি না ...)
মার্ক গ্র্যাভেল

@ মার্কগ্রাভেল আপনি foo.Method((dynamic)myGenericClass)রান টাইম মেথড বাইন্ডিংয়ের জন্য ব্যবহার করতে পারেন , কার্যকরভাবে কোনও ধরণের পদ্ধতির ওভারলোডের জন্য পরিষেবা লোকেটার প্যাটার্ন।
ক্রিস মেরিসিক

@ ক্রিসমারিসিক হ্যাঁ, কিছু জেনেরিকের জন্য public void Method<T>(T obj)- এমন একটি কৌশল যা আমি এই মন্তব্যটির পরে গত 6 বছরে কয়েকবারের বেশি ব্যবহার করেছি; পি
মার্ক গ্রাভেল

@ মার্কগ্রাভেল কি এমন কোনও উপায় সংশোধন করার উপায় আছে যাতে পদ্ধতিটি এটি তাত্ক্ষণিকভাবে চালিত করে?
বার্লপ

উত্তর:


220

আপনি প্রতিবিম্ব ছাড়া এটি করতে পারবেন না। যাইহোক, আপনি এটি প্রতিচ্ছবি সঙ্গে করতে পারেন । এখানে একটি সম্পূর্ণ উদাহরণ:

using System;
using System.Reflection;

public class Generic<T>
{
    public Generic()
    {
        Console.WriteLine("T={0}", typeof(T));
    }
}

class Test
{
    static void Main()
    {
        string typeName = "System.String";
        Type typeArgument = Type.GetType(typeName);

        Type genericClass = typeof(Generic<>);
        // MakeGenericType is badly named
        Type constructedClass = genericClass.MakeGenericType(typeArgument);

        object created = Activator.CreateInstance(constructedClass);
    }
}

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

Type genericClass = typeof(IReadOnlyDictionary<,>);
Type constructedClass = genericClass.MakeGenericType(typeArgument1, typeArgument2);

1
ঠিক আছে, এটি ভাল, তবে তৈরির পদ্ধতিতে কল করার পদ্ধতি কীভাবে যায়? আরও প্রতিবিম্ব?
রবার্ট সি বার্থ

7
ঠিক আছে, আপনি যদি নিজের জেনেরিক ধরণের একটি নন-জেনেরিক ইন্টারফেস বাস্তবায়নের সাথে দূরে সরে যেতে পারেন তবে আপনি সেই ইন্টারফেসে কাস্ট করতে পারেন। বিকল্পভাবে, আপনি নিজের জেনেরিক পদ্ধতিটি লিখতে পারেন যা জেনেরিকের সাথে আপনি যে কাজটি করতে চান তার সমস্ত কাজ করে এবং প্রতিচ্ছবি সহ এটি কল করতে পারেন
জন স্কিটি

1
হ্যাঁ, আপনি কীভাবে তৈরি টাইপটি ব্যবহার করবেন তা কীভাবে বোঝাবেন না যদি আপনি যে টাইপটি ফেরত পাঠান সে সম্পর্কে তথ্য কেবল টাইপ আর্গুমেন্ট টাইপ ভেরিয়েবলের মধ্যে থাকে? আমার কাছে মনে হচ্ছে আপনাকে সেই পরিবর্তনশীলটিতে কাস্ট করতে হবে, তবে আপনি কী জানেন না এটি এতটা নিশ্চিত যে আপনি প্রতিফলন সহ এটি করতে পারবেন কিনা তা নিশ্চিত Im আরেকটি প্রশ্ন যদি অবজেক্টটি টাইপ ইন্টের উদাহরণস্বরূপ হয় তবে আপনি যদি কোনও বস্তুর ভেরিয়েবল হিসাবে পাস করে থাকেন তবে উদাহরণস্বরূপ একটি তালিকা <int> এই কাজটি করতে চান? তৈরি ভেরিয়েবলটি কি কোন ইন্ট হিসাবে বিবেচিত হবে?
theringostarrs

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

4
@ বালানজা: আপনি মেকগেনেরিকমেথড ব্যবহার করেন।
জন স্কিটি

14

দুর্ভাগ্যক্রমে নেই। জেনেরিক আর্গুমেন্টগুলি সংশোধনযোগ্য সময়ে অবশ্যই 1) একটি বৈধ টাইপ বা 2) অন্য জেনেরিক প্যারামিটার হিসাবে সংশোধনযোগ্য। প্রতিফলন ব্যবহারের বড় হাতুড়ি ছাড়া রানটাইম মানগুলির উপর ভিত্তি করে জেনেরিক উদাহরণ তৈরি করার কোনও উপায় নেই।


2

কিছু অতিরিক্ত কীভাবে কাঁচি কোড দিয়ে চালানো যায়। ধরুন আপনার মতো ক্লাস আছে

public class Encoder() {
public void Markdown(IEnumerable<FooContent> contents) { do magic }
public void Markdown(IEnumerable<BarContent> contents) { do magic2 }
}

ধরুন রানটাইমের সময় আপনার কাছে একটি ফুকন্টেন্ট রয়েছে

যদি আপনি কম্পাইল সময়ে বেঁধে করতে সক্ষম হয়েছি আপনি চাইবেন

var fooContents = new List<FooContent>(fooContent)
new Encoder().Markdown(fooContents)

তবে আপনি রানটাইমে এটি করতে পারবেন না। রানটাইমে এটি করার জন্য আপনি এই লাইনের সাথে কাজটি করবেন:

var listType = typeof(List<>).MakeGenericType(myType);
var dynamicList = Activator.CreateInstance(listType);
((IList)dynamicList).Add(fooContent);

গতিশীলভাবে প্রার্থনা করা Markdown(IEnumerable<FooContent> contents)

new Encoder().Markdown( (dynamic) dynamicList)

dynamicপদ্ধতি কলটিতে ব্যবহারটি নোট করুন । রানটাইমের সময়টি dynamicListহবে List<FooContent>(অতিরিক্ত হিসাবে এটিও IEnumerable<FooContent>) যেহেতু ডায়নামিকের ব্যবহার এখনও দৃ strongly়ভাবে টাইপিত ভাষায় রূট থাকে রান রান টাইম বাইন্ডার উপযুক্তটি নির্বাচন করবেMarkdown পদ্ধতিটি । যদি কোনও সঠিক ধরণের ম্যাচ না থাকে তবে এটি কোনও অবজেক্ট প্যারামিটার পদ্ধতি অনুসন্ধান করবে এবং যদি কোনও রানটাইম বাইন্ডারের সাথে মেলে না তবে সতর্ক করে যে কোনও পদ্ধতি মেলে না।

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


2

আমার প্রয়োজনীয়তা কিছুটা আলাদা ছিল তবে আশা করি কাউকে সহায়তা করবে। আমার একটি কনফিগার থেকে টাইপ পড়ার এবং জেনেরিক টাইপটি গতিশীলভাবে ইনস্ট্যান্ট করা দরকার।

namespace GenericTest
{
    public class Item
    {
    }
}

namespace GenericTest
{
    public class GenericClass<T>
    {
    }
}

শেষ পর্যন্ত, আপনি এটি কল কিভাবে এখানে। ব্যাকটিক দিয়ে প্রকারটি সংজ্ঞায়িত করুন

var t = Type.GetType("GenericTest.GenericClass`1[[GenericTest.Item, GenericTest]], GenericTest");
var a = Activator.CreateInstance(t);

0

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

public class Type1 { }

public class Type2 { }

public class Generic<T> { }

public class Program
{
    public static void Main()
    {
        var typeName = nameof(Type1);

        switch (typeName)
        {
            case nameof(Type1):
                var type1 = new Generic<Type1>();
                // do something
                break;
            case nameof(Type2):
                var type2 = new Generic<Type2>();
                // do something
                break;
        }
    }
}

আপনি 100 টি ক্লাসের সাথে ডিল শুরু করার পরে এটি কুরুচিপূর্ণ হয়ে ওঠে।
মাইকেল জি

0

এই স্নিপেটে আমি কীভাবে একটি গতিশীলভাবে তৈরি তালিকা তৈরি করতে এবং ব্যবহার করব তা দেখাতে চাই। উদাহরণস্বরূপ, আমি এখানে গতিশীল তালিকায় যুক্ত করছি।

void AddValue<T>(object targetList, T valueToAdd)
{
    var addMethod = targetList.GetType().GetMethod("Add");
    addMethod.Invoke(targetList, new[] { valueToAdd } as object[]);
}

var listType = typeof(List<>).MakeGenericType(new[] { dynamicType }); // dynamicType is the type you want
var list = Activator.CreateInstance(listType);

AddValue(list, 5);

একইভাবে আপনি তালিকার অন্য কোনও পদ্ধতিতে আবেদন করতে পারেন।

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