সি # 'ডায়নামিক' অন্য সমাবেশে ঘোষিত বেনামি প্রকারের বৈশিষ্ট্যগুলিতে অ্যাক্সেস করতে পারে না


87

নিচের কোডটি যতক্ষণ আমার ক্লাস ClassSameAssemblyহিসাবে একই সমাবেশে ক্লাস রয়েছে ততক্ষণ কাজ করছে Program। কিন্তু যখন আমি ক্লাসটি ClassSameAssemblyএকটি পৃথক সমাবেশে স্থানান্তরিত করি , তখন একটি RuntimeBinderException(নীচে দেখুন) নিক্ষেপ করা হয়। এটি সমাধান করা সম্ভব?

using System;

namespace ConsoleApplication2
{
    public static class ClassSameAssembly
    {
        public static dynamic GetValues()
        {
            return new
            {
                Name = "Michael", Age = 20
            };
        }
    }

    internal class Program
    {
        private static void Main(string[] args)
        {
            var d = ClassSameAssembly.GetValues();
            Console.WriteLine("{0} is {1} years old", d.Name, d.Age);
        }
    }
}

Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: 'অবজেক্ট' এর মধ্যে 'নাম' এর সংজ্ঞা নেই

at CallSite.Target(Closure , CallSite , Object )
at System.Dynamic.UpdateDelegates.UpdateAndExecute1[T0,TRet](CallSite site, T0 arg0)
at ConsoleApplication2.Program.Main(String[] args) in C:\temp\Projects\ConsoleApplication2\ConsoleApplication2\Program.cs:line 23

স্ট্যাকট্রেস: কলসাইট.টারাজেটে (ক্লোজার, কলসাইট, অবজেক্ট) সিস্টেম.ডাইমেনিক.অ্যাপডেটডেলিগেটস.উপডেটএন্ডএেক্সেকিউট 1 [টি 0, ট্রেট] (কলসাইট সাইট, টি0 আর্গ0) কনসোল অ্যাপ্লিকেশন 2.প্রগ্রাম.মেন (স্ট্রিং [] আরগস) তে: Jects প্রজেক্টস \ কনসোল অ্যাপ্লিকেশন 2 \ কনসোল অ্যাপ্লিকেশন 2 .c প্রোগ্রাম কোডস: সিস্টেম 23 এ লাইন 23. সিস্টেমডে অ্যাপডোমেন._ এনএক্সেকিউটসঅ্যাস্পাবলিতে (রানটাইমঅ্যাস্প্যাসবেশন অ্যাসেমব্লিং, স্ট্রিং [] আরোগুলি) স্ট্রিং
অ্যাসেমবিলি ফাইল

মাইক্রোসফ্ট.ভিজুয়ালস্টুডিও.হোস্টিংপ্রসেস.হোস্টপ্রোক.আরুনজারসঅ্যাস্পাবেশন () সিস্টেমে.ট্রেডিং.ট্রেডহেল্পার। ট্র্যাড স্টার্ট_কন্টেক্সট (অবজেক্ট স্টেট) সিস্টেম এ। ট্র্যাডিং। এক্সিকিউশনকন্টেক্সট.রুন (এক্সিকিউশন কনটেক্সট এক্সিকিউশন কনটেক্সট, কনটেক্সট কলব্যাক কলব্যাক, অবজেক্ট স্টেট) সিস্টেম.ট্রেডিং.ট্রেডহেল্পার.ট্রেডস্টার্ট () অভ্যন্তরীণ এক্সেকশন:
মেহনিক

পূর্ণ উত্স কোড সহ কোনও চূড়ান্ত সমাধান?
কিকিনেট

উত্তর:


116

আমি বিশ্বাস করি যে সমস্যাটি হ'ল অজ্ঞাতনামা টাইপটি তৈরি করা হয় internal, সুতরাং বাইন্ডারটি সত্যিকার অর্থে এটি সম্পর্কে "জানেন" না।

পরিবর্তে ExpandoObject ব্যবহার করে দেখুন:

public static dynamic GetValues()
{
    dynamic expando = new ExpandoObject();
    expando.Name = "Michael";
    expando.Age = 20;
    return expando;
}

আমি জানি এটি কিছুটা কুৎসিত, তবে আমি এই মুহুর্তে সবচেয়ে ভাল চিন্তা করতে পারি ... আমি মনে করি না আপনি এটির সাথে একটি অবজেক্ট ইনিশিয়ালাইজারটিও ব্যবহার করতে পারবেন, কারণ এটি ExpandoObjectসংকলক হিসাবে দৃ strongly়ভাবে টাইপ করা অবস্থায় কী করতে হবে তা জানতে পারে না do "নাম" এবং "বয়স" সহ। আপনি এটি করতে সক্ষম হতে পারেন:

 dynamic expando = new ExpandoObject()
 {
     { "Name", "Michael" },
     { "Age", 20 }
 };
 return expando;

তবে এটি এর চেয়ে ভাল নয় ...

প্রতিবিম্বের মাধ্যমে একই বিষয়বস্তু সহ একটি বেনামী প্রকারকে একটি এক্সপেনডোতে রূপান্তর করতে আপনি সম্ভাব্য একটি এক্সটেনশন পদ্ধতি লিখতে পারেন । তাহলে আপনি লিখতে পারেন:

return new { Name = "Michael", Age = 20 }.ToExpando();

যদিও এটি বেশ ভয়ঙ্কর :(


4
ধন্যবাদ জন। আমি কেবল একটি ক্লাস ব্যবহার করে একই সমস্যা ছিল যা সমাবেশের জন্য ব্যক্তিগত বলে মনে হয়েছিল।
ডেভ মার্কল

4
আমি আপনার বীভৎস উদাহরণের মতো শেষ পর্যন্ত পছন্দ করব, যদিও এটি ভয়াবহ নয়। ব্যবহারের জন্য: গতিশীল প্রপস = নতুন {মেটাডেটা = বিশদ মডেলমেটাডেটা। এবং নামযুক্ত প্রসগুলি গতিশীল সদস্য হিসাবে যুক্ত করা দুর্দান্ত হবে!
অধ্যাপক

ওপেন সোর্স ফ্রেমওয়ার্ক ইমোম্প্টু ইন্টারফেসটি ডিএলআর দিয়ে অনেক কিছু করে এটিতে একটি ইনলাইন ইনিশিয়ালাইজেশন সিনট্যাক্স রয়েছে যা কোনও বস্তুর গতিশীল বা স্থির জন্য কাজ করে for return Build<ExpandoObject>.NewObject(Name:"Micheal", Age: 20);
jbtule

4
বেনামে টাইপকে এক্সপেনডোতে রূপান্তর করতে কোনও এক্সটেনশন পদ্ধতির কোনও পূর্ণ উত্স কোড নমুনা?
কিকিনেট

4
@ মোঃআলব্রাহিম: আপনি পারবেন না, মূলত: আপনাকে এটি objectজেনেরিক ধরণের বা জেনেরিক টাইপের (আপনার প্রয়োজন হতে পারে এটি একটি শ্রেণি ...) করতে হবে এবং কার্যকর করার সময় টাইপটি পরীক্ষা করতে হবে।
জন স্কিটি 9

63

আপনি [assembly: InternalsVisibleTo("YourAssemblyName")]আপনার সমাবেশ অভ্যন্তরীণ দৃশ্যমান করতে ব্যবহার করতে পারেন।


4
জনের উত্তরটি আরও সম্পূর্ণ, তবে এটি আসলে আমার পক্ষে যুক্তিসঙ্গত সহজ সমাধান সরবরাহ করে। ধন্যবাদ :)
কেলোটি

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

@ ফয়সালমিকিউ এর কারণ কারণ বেনামে ক্লাস তৈরি করা সংকলক তাদের "অভ্যন্তরীণ" হিসাবে ঘোষণা করে। আসল কারণটি জানেন না।
ইমা

4
হ্যাঁ, আমি এই উত্তরটি গুরুত্বপূর্ণ বলে মনে করি, কারণ আমি কার্য কোডটি পরিবর্তন করতে চাই না, আমাকে কেবল অন্য একটি সমাবেশ থেকে এটি পরীক্ষা করা দরকার
পান্ডাউড

এখানে যোগ করার জন্য একটি নোটটি হ'ল এটির কাজ করার জন্য আপনাকে পরিবর্তনের পরে ভিজ্যুয়াল স্টুডিও পুনরায় চালু করতে হবে।
রেডি

11

আমি একটি অনুরূপ সমস্যার মধ্যে দৌড়েছি এবং জন স্কিটিস উত্তরটিতে যুক্ত করতে চাই যে আরও একটি বিকল্প আছে। আমি যে কারণটি খুঁজে পেয়েছিলাম তা হ'ল আমি বুঝতে পারি যে এসপি এমভিসি 3 তে বহু এক্সটেনশন পদ্ধতি এইচটিএমএল বৈশিষ্ট্যগুলি সরবরাহ করতে ইনপুট হিসাবে বেনাম শ্রেণি ব্যবহার করে (নতুন {Alt = "চিত্র Alt", শৈলী = "প্যাডিং-শীর্ষ: 5px"} =>

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

object o = new {
    name = "theName",
    props = new {
        p1 = "prop1",
        p2 = "prop2"
    }
}
SeparateAssembly.TextFunc(o)

//In SeparateAssembly:
public void TextFunc(Object o) {
  var rvd = new RouteValueDictionary(o);

//Does not work:
Console.WriteLine(o.name);
Console.WriteLine(o.props.p1);

//DOES work!
Console.WriteLine(rvd["name"]);

//Does not work
Console.WriteLine(rvd["props"].p1);
Console.WriteLine(rvd["props"]["p1"]);

তাই ... এখানে আসলে কী চলছে? রুটভ্যালু অভিধানের ভিতরে একটি উঁকি দেওয়া এই কোডটি প্রকাশ করে (উপরের মানের ~ = o):

foreach (PropertyDescriptor descriptor in TypeDescriptor.GetProperties(values))
    object obj2 = descriptor.GetValue(values);
    //"this.Add" would of course need to be adapted
    this.Add(descriptor.Name, obj2);
}

সুতরাং - TypeDescriptor.GetProperties (ও) ব্যবহার করে আমরা বেনামে টাইপ পৃথক সমাবেশে অভ্যন্তরীণ হিসাবে নির্মিত হওয়া সত্ত্বেও আমরা সম্পত্তি এবং মানগুলি পেতে সক্ষম হব! এবং অবশ্যই এটি পুনরাবৃত্তি করতে প্রসারিত করা বেশ সহজ হবে। আপনি চান এবং একটি এক্সটেনশন পদ্ধতি করতে।

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

/ ভিক্টর


এই বিভ্রান্তির জন্য দুঃখিত। প্রোপ 1 => পি 1 থেকে কোড আপডেট করা হয়েছে যেখানে উপযুক্ত। তবুও - পুরো পোস্টটির সাথে ধারণাটি ছিল সমস্যা সমাধানের একটি বিকল্প হিসাবে টাইপডেস্ক্রিপ্টর.গেটপ্রপার্টিগুলি রাখা, যা আশা করি যে কোনওভাবেই পরিষ্কার ছিল ...
ভিক্টর

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

2

টো এক্সপান্ডোঅবজেক্টের জন্য এখানে একটি এক্সটেনশন পদ্ধতির প্রাথমিক সংস্করণটি রয়েছে যে আমার নিশ্চিত যে পোলিশ করার জন্য জায়গা রয়েছে।

    public static ExpandoObject ToExpandoObject(this object value)
    {
        // Throw is a helper in my project, replace with your own check(s)
        Throw<ArgumentNullException>.If(value, Predicates.IsNull, "value");

        var obj = new ExpandoObject() as IDictionary<string, object>;

        foreach (var property in value.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance))
        {
            obj.Add(property.Name, property.GetValue(value, null));
        }

        return obj as ExpandoObject;
    }

    [TestCase(1, "str", 10.75, 9.000989, true)]
    public void ToExpandoObjectTests(int int1, string str1, decimal dec1, double dbl1, bool bl1)
    {
        DateTime now = DateTime.Now;

        dynamic value = new {Int = int1, String = str1, Decimal = dec1, Double = dbl1, Bool = bl1, Now = now}.ToExpandoObject();

        Assert.AreEqual(int1, value.Int);
        Assert.AreEqual(str1, value.String);
        Assert.AreEqual(dec1, value.Decimal);
        Assert.AreEqual(dbl1, value.Double);
        Assert.AreEqual(bl1, value.Bool);
        Assert.AreEqual(now, value.Now);
    }

1

একটি ক্লিনার সমাধানটি হ'ল:

var d = ClassSameAssembly.GetValues().ToDynamic();

যা এখন এক্সপেন্ডোওবজেক্ট।

রেফারেন্স মনে রাখবেন:

Microsoft.CSharp.dll

1

সমাধানের নীচে আমার কনসোল অ্যাপ্লিকেশন প্রকল্পগুলিতে কাজ করেছে

এটিকে [অ্যাসেম্বলি: ইন্টারনালভিজিবলটো ("আপনারআসোপেনসনাম"))] ফাংশন ফিরতি গতিশীল অবজেক্টের সাথে পৃথক প্রকল্পের \ বৈশিষ্ট্য \ এসেম্বলিআইএনফোতে রাখুন।

"ইয়োরএএসব্ল্যাশনেম" কলিং প্রকল্পের সমাবেশ নাম। আপনি এটি অ্যাসেম্বলিয়ের মাধ্যমে পেতে পারেন et


0

টো এক্সপান্ডো এক্সটেনশন পদ্ধতি (জনের উত্তরে উল্লিখিত) সাহসীদের জন্য

public static class ExtensionMethods
{
    public static ExpandoObject ToExpando(this object obj)
    {
        IDictionary<string, object> expando = new ExpandoObject();
        foreach (PropertyDescriptor propertyDescriptor in TypeDescriptor.GetProperties(obj))
        {
            var value = propertyDescriptor.GetValue(obj);
            expando.Add(propertyDescriptor.Name, value == null || new[]
            {
                typeof (Enum),
                typeof (String),
                typeof (Char),
                typeof (Guid),
                typeof (Boolean),
                typeof (Byte),
                typeof (Int16),
                typeof (Int32),
                typeof (Int64),
                typeof (Single),
                typeof (Double),
                typeof (Decimal),
                typeof (SByte),
                typeof (UInt16),
                typeof (UInt32),
                typeof (UInt64),
                typeof (DateTime),
                typeof (DateTimeOffset),
                typeof (TimeSpan),
            }.Any(oo => oo.IsInstanceOfType(value))
                ? value
                : value.ToExpando());
        }

        return (ExpandoObject)expando;
    }
}

0

যদি আপনি ইতিমধ্যে আপনার প্রকল্পে নিউটনসফট.জসন ব্যবহার করছেন (বা আপনি এটির জন্য এটি যুক্ত করতে ইচ্ছুক), আপনি যে ভয়ঙ্কর সম্প্রসারণ পদ্ধতিটি জোন স্কিট তার উত্তরটির সাথে উল্লেখ করছেন তা প্রয়োগ করতে পারেন:

public static class ObjectExtensions
{
    public static ExpandoObject ToExpando(this object obj)
        => JsonConvert.DeserializeObject<ExpandoObject>(JsonConvert.SerializeObject(obj));
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.