সি # তে বেনামে ধরণের সম্পত্তি কীভাবে অ্যাক্সেস করবেন?


125

আমার আছে এটা:

List<object> nodes = new List<object>(); 

nodes.Add(
new {
    Checked     = false,
    depth       = 1,
    id          = "div_" + d.Id
});

... এবং আমি ভাবছি যে আমি যদি তখন বেনামে থাকা অবজেক্টটির "চেক করা" সম্পত্তিটি দখল করতে পারি কিনা। আমি নিশ্চিত না এটি এমনকি সম্ভব কিনা। এটি করার চেষ্টা করা হয়েছে:

if (nodes.Any(n => n["Checked"] == false)) ... কিন্তু কাজ করে না

ধন্যবাদ

উত্তর:


63

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

var nodes = (new[] { new { Checked = false, /* etc */ } }).ToList();

তারপরে আপনি এটির মতো অ্যাক্সেস করতে সক্ষম হবেন:

nodes.Any(n => n.Checked);

সংকলকটি যেভাবে কাজ করে তার কারণে নিম্নলিখিত তালিকাটি একবার তৈরি করার পরেও কাজ করা উচিত, কারণ বেনামে টাইপগুলির একই কাঠামো থাকে তাই তারাও একই ধরণের same যদিও এটি যাচাই করার জন্য আমার কাছে কোনও সংকলক নেই।

nodes.Add(new { Checked = false, /* etc */ });

263

আপনি যদি বস্তুটি টাইপ হিসাবে সংরক্ষণ করেন তবে আপনার objectপ্রতিবিম্বটি ব্যবহার করা দরকার। বেনামে বা অন্যথায় এটি কোনও অবজেক্টের ধরণের ক্ষেত্রে সত্য otherwise কোনও বস্তুর উপর, আপনি এর ধরণটি পেতে পারেন:

Type t = o.GetType();

তারপরে আপনি কোনও সম্পত্তি অনুসন্ধান করুন:

PropertyInfo p = t.GetProperty("Foo");

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

object v = p.GetValue(o, null);

এই উত্তরটি সি # 4 এর আপডেটের জন্য দীর্ঘ সময়সীমা ছাড়িয়ে গেছে:

dynamic d = o;
object v = d.Foo;

এবং এখন সি # 6 এ অন্য একটি বিকল্প:

object v = o?.GetType().GetProperty("Foo")?.GetValue(o, null);

লক্ষ্য করুন ব্যবহার করে ?.আমরা কারণ ফলে vহতে nullতিনটি ভিন্ন পরিস্থিতিতে!

  1. oহয় null, তাই কোনও বস্তু নেই
  2. oঅ- nullতবে এর সম্পত্তি নেইFoo
  3. oএকটি সম্পত্তি আছে Fooতবে এর আসল মান হতে পারে null

সুতরাং এটি পূর্ববর্তী উদাহরণগুলির সমতুল্য নয়, তবে আপনি যদি তিনটি ক্ষেত্রে একইরকম আচরণ করতে চান তবে তা বোধগম্য হতে পারে।


4
আজ অবধি আগে কখনও ডায়নামিক ব্যবহার করা হয়নি, .NET 4.0
এলান

সি # 4 সমাধানে আপনি সম্পত্তিটির অস্তিত্ব না থাকলে রানটাইম ব্যতিক্রম পাবেন ( object v = d.Foo), GetValue(o, null)অস্তিত্ব না থাকলে শূন্য হবে।
ইয়াকভহাটাম

1
না, GetPropertyফিরে আসবে nullএবং GetValueপাস হয়ে গেলে নিক্ষেপ করবে null, সুতরাং সামগ্রিক প্রভাবটি ব্যতিক্রম। সি # 4.0 সংস্করণটি আরও বর্ণনামূলক ব্যতিক্রম দেয়।
ড্যানিয়েল আরউইকার

4
আপনি যদি উত্সের তুলনায় বিভিন্ন সমাবেশে গতিশীল ব্যবহার করেন তবে আপনার [ইন্টারনালভিজিবলিটো] ব্যবহার করতে হবে
সারথ

2
সমাপ্তির জন্য @DanielEarwicker ধন্যবাদ এটি বেনামে প্রকারের ক্ষেত্রেও প্রযোজ্য। বেনামে প্রকারের জন্য উত্পন্ন সমস্ত সম্পত্তি অভ্যন্তরীণ।
সারথ

13

আপনি প্রতিবিম্ব ব্যবহার করে বেনামে প্রকারের বৈশিষ্ট্যগুলি নিয়ে পুনরাবৃত্তি করতে পারেন; "পরীক্ষিত" সম্পত্তি আছে কিনা তা দেখুন এবং তারপরেও এর মানটি পান।

এই ব্লগ পোস্টটি দেখুন: http://blogs.msdn.com/wriju/archive/2007/10/26/c-3-0- বেনামে- টাইপ- এবং- নেট- রিফ্লেশন- হ্যান্ড- ইন-hand.aspx

সুতরাং যেমন কিছু:

foreach(object o in nodes)
{
    Type t = o.GetType();

    PropertyInfo[] pi = t.GetProperties(); 

    foreach (PropertyInfo p in pi)
    {
        if (p.Name=="Checked" && !(bool)p.GetValue(o))
            Console.WriteLine("awesome!");
    }
}

6
আপনার যদি কেবল একটি সম্পত্তি প্রয়োজন হয় এবং আপনি ইতিমধ্যে এর নামটি জানেন তবে সেগুলির মধ্যে দিয়ে যাওয়ার কোনও অর্থ নেই; কেবলমাত্র গেটপ্রপার্টি এবং গেটভ্যালু ব্যবহার করুন। এছাড়াও, System.out.println জাভা, সি # নয় ...
ক্রিস চরবারুক

উফফফ, তাই, ক্রিস! কিছুটা বিব্রতকর ... এখনই ঠিক হয়ে গেছে।
গ্লেনকেন্টওয়েল

6

গৃহীত উত্তর সঠিকভাবে বর্ণনা করে যে তালিকাটি কীভাবে ঘোষণা করা উচিত এবং বেশিরভাগ পরিস্থিতিতে তার জন্য অত্যন্ত প্রস্তাবিত।

তবে আমি একটি ভিন্ন দৃশ্য জুড়ে এসেছি, যা জিজ্ঞাসিত প্রশ্নকেও coversেকে দেয়। আপনি যদি একটি বিদ্যমান বস্তুর তালিকা ব্যবহার করতে চান কি আছে যদি ViewData["htmlAttributes"]MVC ? আপনি কীভাবে এর বৈশিষ্ট্যগুলি অ্যাক্সেস করতে পারেন (সেগুলি সাধারণত মাধ্যমে তৈরি করা হয় new { @style="width: 100px", ... })?

এই সামান্য ভিন্ন দৃশ্যের জন্য আমি যা জানতে পেরেছিলাম তা আপনার সাথে ভাগ করে নিতে চাই। নীচের সমাধানগুলিতে, আমি নিম্নলিখিত ঘোষণাটি ধরে নিচ্ছি nodes:

List<object> nodes = new List<object>();

nodes.Add(
new
{
    Checked = false,
    depth = 1,
    id = "div_1" 
});

1. গতিশীল সঙ্গে সমাধান

ইন সি # 4.0 এবং উচ্চতর সংস্করণ আপনি কেবল গতিশীল এবং লিখতে কাস্ট করতে পারেন:

if (nodes.Any(n => ((dynamic)n).Checked == false))
    Console.WriteLine("found not checked element!");

নোট: এই ব্যবহার করছে প্রয়াত বাঁধাই, যার মানে হচ্ছে এটা শুধুমাত্র রানটাইম এ চিনতে পারবে যদি বস্তুর একটি নেই Checkedসম্পত্তি এবং ছোঁড়ার RuntimeBinderExceptionএই ক্ষেত্রে - তাই যদি আপনি একটি অ-বিদ্যমান ব্যবহারের চেষ্টা Checked2সম্পত্তি আপনি নিম্নলিখিত বার্তা পেতে হবে এ রানটাইম: "'<>f__AnonymousType0<bool,int,string>' does not contain a definition for 'Checked2'"

2. প্রতিবিম্ব সঙ্গে সমাধান

প্রতিচ্ছবি সহ সমাধান পুরানো এবং নতুন সি # সংকলক সংস্করণ উভয়ই কাজ করে । পুরানো সি # সংস্করণের জন্য দয়া করে এই উত্তরটির শেষে ইঙ্গিতটি বিবেচনা করুন।

পটভূমি

একটি আদ্যস্থল হিসাবে, আমি একটি ভাল উত্তর পাওয়া এখানে । ভাবনাটি হ'ল প্রতিবিম্ব ব্যবহার করে বেনামে তথ্য প্রকারকে অভিধানে রূপান্তর করা। অভিধানগুলি বৈশিষ্ট্যগুলি অ্যাক্সেস করা সহজ করে তোলে, যেহেতু তাদের নামগুলি কী হিসাবে সংরক্ষণ করা হয় (আপনি তাদের মতো অ্যাক্সেস করতে পারেন myDict["myProperty"])।

উপরের লিঙ্কটি কোড দ্বারা অনুপ্রাণিত, আমি একটি এক্সটেনশন বর্গ প্রদানের নির্মিত GetProp, UnanonymizePropertiesএবং UnanonymizeListItemsএক্সটেনশন পদ্ধতি, বেনামী বৈশিষ্ট্য যা প্রক্রিয়া সহজ অ্যাক্সেস করার অনুমতি। এই শ্রেণীর সাহায্যে আপনি নিম্নরূপে কোয়েরিটি সহজভাবে করতে পারেন:

if (nodes.UnanonymizeListItems().Any(n => (bool)n["Checked"] == false))
{
    Console.WriteLine("found not checked element!");
}

অথবা আপনি শর্ত nodes.UnanonymizeListItems(x => (bool)x["Checked"] == false).Any()হিসাবে অভিব্যক্তিটি ব্যবহার করতে পারেন if, যা স্পষ্টভাবে ফিল্টার করে এবং তারপরে কোনও উপাদান ফিরে আসে কিনা তা পরীক্ষা করে।

"পরীক্ষিত" বৈশিষ্ট্যযুক্ত প্রথম বস্তুটি পেতে এবং এর সম্পত্তি "গভীরতা" ফিরিয়ে আনতে আপনি ব্যবহার করতে পারেন:

var depth = nodes.UnanonymizeListItems()
             ?.FirstOrDefault(n => n.Contains("Checked")).GetProp("depth");

বা সংক্ষিপ্ত: nodes.UnanonymizeListItems()?.FirstOrDefault(n => n.Contains("Checked"))?["depth"];

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

if (nodes.UnanonymizeListItems(x => { var y = ((bool?)x.GetProp("Checked", true)); 
                                      return y.HasValue && y.Value == false;}).Any())
{
    Console.WriteLine("found not checked element!");
}

এটি প্রতিরোধ করে, KeyNotFoundException"চেক করা" সম্পত্তিটি উপস্থিত না থাকলে এমন একটি ঘটে।


নীচের শ্রেণিতে নিম্নলিখিত এক্সটেনশন পদ্ধতি রয়েছে:

  • UnanonymizeProperties: কোনও বস্তুর মধ্যে থাকা বৈশিষ্ট্যগুলি ডি-বেনামে ব্যবহার করা হয় । এই পদ্ধতিতে প্রতিবিম্ব ব্যবহার করা হয়। এটি বস্তুটিকে বৈশিষ্ট্য এবং এর মান সমেত একটি অভিধানে রূপান্তরিত করে।
  • UnanonymizeListItems: বৈশিষ্ট্যযুক্ত অভিধানের তালিকায় কোনও সামগ্রীর তালিকা রূপান্তর করতে ব্যবহৃত হয়। এটিতে আগে ফিল্টার করার জন্য optionচ্ছিকভাবে ল্যাম্বডা এক্সপ্রেশন থাকতে পারে ।
  • GetProp: প্রদত্ত সম্পত্তি নামের সাথে একক মান ফেরত দিতে ব্যবহৃত হয়। কী-নটফাউন্ডএক্সেপশন (ভুয়া) না হয়ে অস্তিত্বের বৈশিষ্ট্যগুলিকে নাল মান (সত্য) হিসাবে বিবেচনা করার অনুমতি দেয়

উপরের উদাহরণগুলির জন্য, যা প্রয়োজন তা হ'ল আপনি নীচে এক্সটেনশন ক্লাস যুক্ত করুন:

public static class AnonymousTypeExtensions
{
    // makes properties of object accessible 
    public static IDictionary UnanonymizeProperties(this object obj)
    {
        Type type = obj?.GetType();
        var properties = type?.GetProperties()
               ?.Select(n => n.Name)
               ?.ToDictionary(k => k, k => type.GetProperty(k).GetValue(obj, null));
        return properties;
    }

    // converts object list into list of properties that meet the filterCriteria
    public static List<IDictionary> UnanonymizeListItems(this List<object> objectList, 
                    Func<IDictionary<string, object>, bool> filterCriteria=default)
    {
        var accessibleList = new List<IDictionary>();
        foreach (object obj in objectList)
        {
            var props = obj.UnanonymizeProperties();
            if (filterCriteria == default
               || filterCriteria((IDictionary<string, object>)props) == true)
            { accessibleList.Add(props); }
        }
        return accessibleList;
    }

    // returns specific property, i.e. obj.GetProp(propertyName)
    // requires prior usage of AccessListItems and selection of one element, because
    // object needs to be a IDictionary<string, object>
    public static object GetProp(this object obj, string propertyName, 
                                 bool treatNotFoundAsNull = false)
    {
        try 
        {
            return ((System.Collections.Generic.IDictionary<string, object>)obj)
                   ?[propertyName];
        }
        catch (KeyNotFoundException)
        {
            if (treatNotFoundAsNull) return default(object); else throw;
        }
    }
}

ইঙ্গিত: উপরের কোড ব্যবহার করছে নাল-শর্তাধীন অপারেটর, যেহেতু C # এর সংস্করণ 6.0 প্রাপ্তিসাধ্য - আপনি সাথে এসেছেন পরিশ্রমী পুরোনো C # এর কম্পাইলার (যেমন C # এর 3.0), কেবল প্রতিস্থাপন ?.দ্বারা .এবং ?[দ্বারা [, সর্বত্র যেমন

var depth = nodes.UnanonymizeListItems()
            .FirstOrDefault(n => n.Contains("Checked"))["depth"];

যদি আপনাকে কোনও পুরানো সি # সংকলক ব্যবহার করতে বাধ্য করা না হয়, তবে এটি ঠিক রাখুন, কারণ নাল-কন্ডিশনাল ব্যবহার নাল পরিচালনা সহজতর করে তোলে।

দ্রষ্টব্য: ডায়নামিক সহ অন্যান্য সমাধানের মতো, এই সমাধানটিও দেরী বাঁধাই ব্যবহার করছে, তবে এই ক্ষেত্রে আপনি কোনও ব্যতিক্রম পাচ্ছেন না - আপনি যদি অ-বিদ্যমান সম্পত্তি হিসাবে উল্লেখ করছেন তবে এটি উপাদানটি খুঁজে পাবে না long আপনি নাল-শর্তযুক্ত অপারেটরদের রাখা হিসাবে ।

কিছু অ্যাপ্লিকেশনগুলির জন্য দরকারী যেটি হ'ল সম্পত্তিটি সমাধান 2-এ স্ট্রিংয়ের মাধ্যমে উল্লেখ করা হয়, তাই এটি প্যারামিটারাইজ করা যেতে পারে।


1

সম্প্রতি, নেট .৩.৫ এর মধ্যে আমার একই সমস্যা ছিল (কোনও গতিশীল নেই)। এখানে আমি কীভাবে সমাধান করেছি:

// pass anonymous object as argument
var args = new { Title = "Find", Type = typeof(FindCondition) };

using (frmFind f = new frmFind(args)) 
{
...
...
}

স্ট্যাকওভারফ্লোতে কোথাও থেকে অভিযোজিত:

// Use a custom cast extension
public static T CastTo<T>(this Object x, T targetType)
{
   return (T)x;
}

কাস্টের মাধ্যমে এখন অবজেক্টটি ফিরে পান:

public partial class frmFind: Form
{
    public frmFind(object arguments)
    {

        InitializeComponent();

        var args = arguments.CastTo(new { Title = "", Type = typeof(Nullable) });

        this.Text = args.Title;

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