শ্রেণীর নাম থেকে আলাদা আলাদা সমাবেশে প্রকারের সমাধান করুন


87

আমার একটি পদ্ধতি রয়েছে যেখানে আমার ক্লাসের ধরণের সমাধান করতে হবে। এই শ্রেণিটি অন্য সমাবেশে নাম স্পেসের অনুরূপ উপস্থিত রয়েছে:

MyProject.Domain.Model

আমি নিম্নলিখিত সম্পাদন করার চেষ্টা করছি:

Type.GetType("MyProject.Domain.Model." + myClassName);

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

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


উত্তর:


171

আপনাকে সমাবেশের নামটি এভাবে যুক্ত করতে হবে:

Type.GetType("MyProject.Domain.Model." + myClassName + ", AssemblyName");

অস্পষ্টতা এড়ানোর জন্য বা যদি সমাবেশটি জিএসি-তে থাকে তবে আপনার যেমন পুরোপুরি যোগ্য সংসদীয় নাম দেওয়া উচিত:

Type.GetType("System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");

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

11
এবং সিরিয়ালাইজেশনে লেনদেনকারীদের
মাইকেল ওয়াইল্ড

4
প্রকারটি যদি একটি তালিকা থাকে <টি>, যেখানে টি একটি কাস্টম শ্রেণি হয়, আপনি কীভাবে 2 টি অ্যাসেমব্লিকে নির্দিষ্ট করবেন? যেমন। সিস্টেম.কলেশনস.জেনারিক.লিস্ট, এবং লাইব্রেরিতে যে টি রয়েছে তার জন্য এমস্কোরলিব সমাবেশ?
সাইমন গ্রিন

@ সিমনগ্রিন: আপনাকে সম্ভবত এটি ব্যবহার করে তৈরি করতে হবে listType.MakeGenericType(itemType)। উভয় প্রকারের ভেরিয়েবলগুলি Type.GetType()আমার উত্তরের মতো ব্যবহার করে তৈরি করা যেতে পারে ।
স্যান্ডর ডিরিউনহুইজন

অবজেক্ট.এএসবুলেশন.টোস্ট্রিং () সম্পূর্ণ সমাবেশ পেতেও ব্যবহার করা যেতে পারে।
zezba9000

7

এই সার্বজনীন সমাধান যারা লোড করতে প্রয়োজন হয় গতিশীল বহিরাগত রেফারেন্স থেকে জেনেরিক ধরনের দ্বারা AssemblyQualifiedNameযা থেকে সমাবেশ জেনেরিক ধরনের সমস্ত অংশ থেকে আসছে জেনে:

    public static Type ReconstructType(string assemblyQualifiedName, bool throwOnError = true, params Assembly[] referencedAssemblies)
    {
        foreach (Assembly asm in referencedAssemblies)
        {
            var fullNameWithoutAssemblyName = assemblyQualifiedName.Replace($", {asm.FullName}", "");
            var type = asm.GetType(fullNameWithoutAssemblyName, throwOnError: false);
            if (type != null) return type;
        }

        if (assemblyQualifiedName.Contains("[["))
        {
            Type type = ConstructGenericType(assemblyQualifiedName, throwOnError);
            if (type != null)
                return type;
        }
        else
        {
            Type type = Type.GetType(assemblyQualifiedName, false);
            if (type != null)
                return type;
        }

        if (throwOnError)
            throw new Exception($"The type \"{assemblyQualifiedName}\" cannot be found in referenced assemblies.");
        else
            return null;
    }

    private static Type ConstructGenericType(string assemblyQualifiedName, bool throwOnError = true)
    {
        Regex regex = new Regex(@"^(?<name>\w+(\.\w+)*)`(?<count>\d)\[(?<subtypes>\[.*\])\](, (?<assembly>\w+(\.\w+)*)[\w\s,=\.]+)$?", RegexOptions.Singleline | RegexOptions.ExplicitCapture);
        Match match = regex.Match(assemblyQualifiedName);
        if (!match.Success)
            if (!throwOnError) return null;
            else throw new Exception($"Unable to parse the type's assembly qualified name: {assemblyQualifiedName}");

        string typeName = match.Groups["name"].Value;
        int n = int.Parse(match.Groups["count"].Value);
        string asmName = match.Groups["assembly"].Value;
        string subtypes = match.Groups["subtypes"].Value;

        typeName = typeName + $"`{n}";
        Type genericType = ReconstructType(typeName, throwOnError);
        if (genericType == null) return null;

        List<string> typeNames = new List<string>();
        int ofs = 0;
        while (ofs < subtypes.Length && subtypes[ofs] == '[')
        {
            int end = ofs, level = 0;
            do
            {
                switch (subtypes[end++])
                {
                    case '[': level++; break;
                    case ']': level--; break;
                }
            } while (level > 0 && end < subtypes.Length);

            if (level == 0)
            {
                typeNames.Add(subtypes.Substring(ofs + 1, end - ofs - 2));
                if (end < subtypes.Length && subtypes[end] == ',')
                    end++;
            }

            ofs = end;
            n--;  // just for checking the count
        }

        if (n != 0)
            // This shouldn't ever happen!
            throw new Exception("Generic type argument count mismatch! Type name: " + assemblyQualifiedName);  

        Type[] types = new Type[typeNames.Count];
        for (int i = 0; i < types.Length; i++)
        {
            try
            {
                types[i] = ReconstructType(typeNames[i], throwOnError);
                if (types[i] == null)  // if throwOnError, should not reach this point if couldn't create the type
                    return null;
            }
            catch (Exception ex)
            {
                throw new Exception($"Unable to reconstruct generic type. Failed on creating the type argument {(i + 1)}: {typeNames[i]}. Error message: {ex.Message}");
            }
        }

        Type resultType = genericType.MakeGenericType(types);
        return resultType;
    }

এবং আপনি এই কোডটি দিয়ে এটি পরীক্ষা করতে পারেন (কনসোল অ্যাপ্লিকেশন):

    static void Main(string[] args)
    {
        Type t1 = typeof(Task<Dictionary<int, Dictionary<string, int?>>>);
        string name = t1.AssemblyQualifiedName;
        Console.WriteLine("Type: " + name);
        // Result: System.Threading.Tasks.Task`1[[System.Collections.Generic.Dictionary`2[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Collections.Generic.Dictionary`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Nullable`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
        Type t2 = ReconstructType(name);
        bool ok = t1 == t2;
        Console.WriteLine("\r\nLocal type test OK: " + ok);

        Assembly asmRef = Assembly.ReflectionOnlyLoad("System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
        // Task<DialogResult> in refTypeTest below:
        string refTypeTest = "System.Threading.Tasks.Task`1[[System.Windows.Forms.DialogResult, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";
        Type t3 = ReconstructType(refTypeTest, true, asmRef);
        Console.WriteLine("External type test OK: " + (t3.AssemblyQualifiedName == refTypeTest));

        // Getting an external non-generic type directly from references:
        Type t4 = ReconstructType("System.Windows.Forms.DialogResult, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", true, asmRef);

        Console.ReadLine();
    }

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

আশা করি এটি যে কাউকে সাহায্য করবে!


2

ও.পি. এর মতোই, আমাকে নাম দ্বারা প্রকারের সীমিত উপসেটটি লোড করা দরকার ছিল (আমার ক্ষেত্রে সমস্ত শ্রেণি একক সমাবেশে ছিল এবং একই ইন্টারফেসটি প্রয়োগ করেছিল)। Type.GetType(string)একটি ভিন্ন সমাবেশের বিরুদ্ধে ব্যবহার করার চেষ্টা করার সময় আমার কাছে প্রচুর অদ্ভুত সমস্যা ছিল (এমনকি অন্যান্য পোস্টগুলিতে উল্লিখিত এসেম্বলি কোয়ালিফাইডনাম যুক্ত করা)। এখানে আমি কীভাবে সমস্যাটি সমাধান করেছি:

ব্যবহার:

var mytype = TypeConverter<ICommand>.FromString("CreateCustomer");

কোড:

    public class TypeConverter<BaseType>
        {
            private static Dictionary<string, Type> _types;
            private static object _lock = new object();

            public static Type FromString(string typeName)
            {
                if (_types == null) CacheTypes();

                if (_types.ContainsKey(typeName))
                {
                    return _types[typeName];
                }
                else
                {
                    return null;
                }
            }

            private static void CacheTypes()
            {
                lock (_lock)
                {
                    if (_types == null)
                    {
                        // Initialize the myTypes list.
                        var baseType = typeof(BaseType);
                        var typeAssembly = baseType.Assembly;
                        var types = typeAssembly.GetTypes().Where(t => 
                            t.IsClass && 
                            !t.IsAbstract && 
                            baseType.IsAssignableFrom(t));

                        _types = types.ToDictionary(t => t.Name);
                    }
                }
            }
        }

স্পষ্টতই আপনি অ্যাপডোমেনের সমস্ত অ্যাসেমব্লিগুলি পরিদর্শন করার জন্য ক্যাশেটাইপস পদ্ধতিটি তাত্পর্যপূর্ণ করতে পারেন বা আপনার যুক্তি-কেস আরও ভাল মানায় এমন অন্যান্য যুক্তি। যদি আপনার ব্যবহারের ক্ষেত্রে একাধিক নেমস্পেসগুলি থেকে প্রকারগুলি লোড হওয়ার অনুমতি দেয় তবে আপনি FullNameপরিবর্তে টাইপটির ব্যবহারের জন্য অভিধান কীটি পরিবর্তন করতে চাইতে পারেন । বা যদি আপনার প্রকারগুলি একটি সাধারণ ইন্টারফেস বা বেস শ্রেণি থেকে উত্তরাধিকার সূত্রে না আসে তবে আপনি এর <BaseType>মতো কিছু ব্যবহার করতে ক্যাশেটাইপস পদ্ধতিটি সরিয়ে এবং পরিবর্তন করতে পারেন.GetTypes().Where(t => t.Namespace.StartsWith("MyProject.Domain.Model.")


1

প্রথমে সমাবেশটি চাপুন এবং তারপরে টাইপ করুন। উদাহরণস্বরূপ: অ্যাসেম্বলি ডিএলএল = এসেম্বলশন.লুডফিল (PATH); ডিএলএল.গেটটাইপ (টাইপনাম);


0

আপনি স্ট্যান্ডার্ড উপায় ব্যবহার করতে পারেন?

typeof( MyClass );

MyClass c = new MyClass();
c.GetType();

যদি তা না হয় তবে আপনাকে প্রকারের তথ্য যোগ করতে হবে the সমাবেশ সম্পর্কে গেটটাইপ।


0

AssemblyQualifiedNameসম্পত্তি ব্যবহার করে স্বল্প এবং গতিশীল পদ্ধতির -

Type.GetType(Type.GetType("MyProject.Domain.Model." + myClassName).AssemblyQualifiedName)

উপভোগ করুন!


10
যদি টাইপ.গেটটাইপ ("মাইপ্রজেক্ট.ডোমেন.মোডেল।" + মাইক্র্লাসনাম) ব্যর্থ হয়, অন্য গেটটাইপ কলটিতে এটি মোড়ানো কীভাবে এটি প্রতিরোধ করতে পারে?
কেইন

4
যাই হোক না কেন, আপনি এটি একটি সিস্টেমের সাহায্যে চেষ্টা ক্যাচ ব্লকে মোড়তে পারেন ull এর মধ্যে আরও ভুল হওয়ার সম্ভাবনা রয়েছে - "মাইপ্রজেক্ট.ডমেন.মোডেল.ক্লাসনাম, ক্লাসনেম, সংস্করণ = 2.0.0.0, সংস্কৃতি = নিরপেক্ষ, পাবলিক্যকিটোকেন = b77a5c561934e089" তারপরে এটি - "মাইপ্রজেক্ট.ডোমেন.মোডেল।" ...
সিমোনবার

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