C#প্রতিফলন ব্যবহার করে স্ট্রিং থেকে সম্পত্তি মান পান।




reflection (17)

Jheddings দ্বারা মহান উত্তর। আমি এগ্রিগেটেড অ্যারে বা বস্তুর সংগ্রহগুলির রেফারেন্সিং করার জন্য এটি উন্নত করতে চাই, যাতে সম্পত্তি নামটি property1.property2 [X] .property3 হতে পারে:

    public static object GetPropertyValue(object srcobj, string propertyName)
    {
        if (srcobj == null)
            return null;

        object obj = srcobj;

        // Split property name to parts (propertyName could be hierarchical, like obj.subobj.subobj.property
        string[] propertyNameParts = propertyName.Split('.');

        foreach (string propertyNamePart in propertyNameParts)
        {
            if (obj == null)    return null;

            // propertyNamePart could contain reference to specific 
            // element (by index) inside a collection
            if (!propertyNamePart.Contains("["))
            {
                PropertyInfo pi = obj.GetType().GetProperty(propertyNamePart);
                if (pi == null) return null;
                obj = pi.GetValue(obj, null);
            }
            else
            {   // propertyNamePart is areference to specific element 
                // (by index) inside a collection
                // like AggregatedCollection[123]
                //   get collection name and element index
                int indexStart = propertyNamePart.IndexOf("[")+1;
                string collectionPropertyName = propertyNamePart.Substring(0, indexStart-1);
                int collectionElementIndex = Int32.Parse(propertyNamePart.Substring(indexStart, propertyNamePart.Length-indexStart-1));
                //   get collection object
                PropertyInfo pi = obj.GetType().GetProperty(collectionPropertyName);
                if (pi == null) return null;
                object unknownCollection = pi.GetValue(obj, null);
                //   try to process the collection as array
                if (unknownCollection.GetType().IsArray)
                {
                    object[] collectionAsArray = unknownCollection as Array[];
                    obj = collectionAsArray[collectionElementIndex];
                }
                else
                {
                    //   try to process the collection as IList
                    System.Collections.IList collectionAsList = unknownCollection as System.Collections.IList;
                    if (collectionAsList != null)
                    {
                        obj = collectionAsList[collectionElementIndex];
                    }
                    else
                    {
                        // ??? Unsupported collection type
                    }
                }
            }
        }

        return obj;
    }

আমি আমার কোড প্রতিফলন 1 উদাহরণ ব্যবহার করে ডেটা রূপান্তর বাস্তবায়ন করার চেষ্টা করছি।

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

এটা কি সম্ভব?

মূল ব্লগ পোস্টের 1 ওয়েব আর্কাইভ সংস্করণ


কল করার পদ্ধতিটি .NET স্ট্যান্ডার্ড (1.6 হিসাবে) তে পরিবর্তিত হয়েছে। এছাড়াও আমরা C # 6 এর অস্পষ্ট শর্তাধীন অপারেটর ব্যবহার করতে পারি।

using System.Reflection; 
public static object GetPropValue(object src, string propName)
{
    return src.GetType().GetRuntimeProperty(propName)?.GetValue(src);
}

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

using System.Reflection;
public object GetPropValue(string prop)
{
    int splitPoint = prop.LastIndexOf('.');
    Type type = Assembly.GetEntryAssembly().GetType(prop.Substring(0, splitPoint));
    object obj = null;
    return type.GetProperty(prop.Substring(splitPoint + 1)).GetValue(obj, null);
}

উল্লেখ্য যে আমি এমন বস্তুর চিহ্নিত করেছি যা স্থানীয় পরিবর্তনশীল obj সাথে পরিদর্শন করা হচ্ছে। null স্ট্যাটিক মানে, অন্যথায় আপনি চান কি সেট। এছাড়াও " GetEntryAssembly() " GetEntryAssembly() পেতে GetEntryAssembly() কয়েকটি উপলব্ধ পদ্ধতির একটি নোট করুন, যদি আপনি টাইপটি লোড করার সময় হার্ড টাইপ করেন তবে আপনি এটির সাথে প্রায় খেলা করতে চাইতে পারেন।


যদি আমি এড এস থেকে কোড ব্যবহার করি তবে আমি পেতে পারি

'প্রতিফলন এক্সটেনশনস। গেটপ্রোপার্টি (টাইপ, স্ট্রিং)' এর সুরক্ষা স্তরের কারণে প্রবেশযোগ্য নয়

মনে হচ্ছে GetProperty() Xamarin.Forms এ উপলব্ধ নয়। TargetFrameworkProfile ফ্রেমওয়ার্ক প্রোফাইলে আমার পোর্টেবল ক্লাস লাইব্রেরিতে প্রোফাইল 7 (.নেট ফ্রেমওয়ার্ক 4.5, উইন্ডোজ 8, এএসপি.নেট কোর 1.0, জ্যামারিন। অ্যান্ড্রয়েড, জ্যামারিরিন.আইওএস, জ্যামারিন.আইওএস ক্লাসিক)।

এখন আমি একটি কাজ সমাধান খুঁজে পাওয়া যায় নি:

using System.Linq;
using System.Reflection;

public static object GetPropValue(object source, string propertyName)
{
    var property = source.GetType().GetRuntimeProperties().FirstOrDefault(p => string.Equals(p.Name, propertyName, StringComparison.OrdinalIgnoreCase));
    return property?.GetValue(source);
}

Source


কিভাবে ভালো কিছু সম্পর্কে:

public static Object GetPropValue(this Object obj, String name) {
    foreach (String part in name.Split('.')) {
        if (obj == null) { return null; }

        Type type = obj.GetType();
        PropertyInfo info = type.GetProperty(part);
        if (info == null) { return null; }

        obj = info.GetValue(obj, null);
    }
    return obj;
}

public static T GetPropValue<T>(this Object obj, String name) {
    Object retval = GetPropValue(obj, name);
    if (retval == null) { return default(T); }

    // throws InvalidCastException if types are incompatible
    return (T) retval;
}

এটি আপনাকে একটি একক স্ট্রিং ব্যবহার করে বৈশিষ্ট্যগুলিতে নেমে যাওয়ার অনুমতি দেবে, এটির মতো:

DateTime now = DateTime.Now;
int min = GetPropValue<int>(now, "TimeOfDay.Minutes");
int hrs = now.GetPropValue<int>("TimeOfDay.Hours");

আপনি স্ট্যাটিক পদ্ধতি বা এক্সটেনশন হিসাবে এই পদ্ধতিগুলি ব্যবহার করতে পারেন।


নীচের বৈশিষ্ট্যগুলির আলোচনার বিষয়ে, যদি আপনি DataBinder.Eval Method (Object, String) ব্যবহার করেন তবে নীচের প্রতিফলন DataBinder.Eval Method (Object, String) এড়াতে পারেন:

var value = DataBinder.Eval(DateTime.Now, "TimeOfDay.Hours");

অবশ্যই, আপনাকে System.Web সমাবেশে একটি রেফারেন্স যুক্ত করতে হবে, তবে এটি সম্ভবত একটি বড় চুক্তি নয়।


jheddings এবং AlexD উভয়ই সম্পত্তি স্ট্রিংগুলির সমাধান করার জন্য চমৎকার উত্তর লিখেছেন। আমি মিশ্রণে খনন করতে চাই, যেহেতু আমি ঠিক সেই উদ্দেশ্যের জন্য একটি ডেডিকেটেড লাইব্রেরি লিখেছি।

Pather.CSharp এর প্রধান শ্রেণী Pather.CSharp হয়। ডিফল্ট প্রতি এটি বৈশিষ্ট্য, অ্যারে এবং অভিধান এন্ট্রি সমাধান করতে পারেন।

সুতরাং, উদাহরণস্বরূপ, যদি আপনি এই মত একটি বস্তু আছে

var o = new { Property1 = new { Property2 = "value" } };

এবং Property2 পেতে চান, আপনি এটি ভালো করতে পারেন:

IResolver resolver = new Resolver();
var path = "Property1.Property2";
object result = r.Resolve(o, path); 
//=> "value"

এটি সমাধান করতে পারে এমন পাথগুলির সবচেয়ে মৌলিক উদাহরণ। যদি আপনি দেখতে চান যে এটি আর কী করতে পারে, বা আপনি কীভাবে এটি প্রসারিত করতে পারেন, কেবল তার Pather.CSharp


নিচের কোডটি একটি বস্তুর উদাহরণে থাকা সমস্ত সম্পত্তি নাম এবং মানগুলির সম্পূর্ণ শ্রেণীবিন্যাস প্রদর্শন করার জন্য একটি পুনর্মিলনী পদ্ধতি। এই পদ্ধতিটি এই থ্রেডে উপরের Alexes এর GetPropertyValue() উত্তরের একটি সরলীকৃত সংস্করণ ব্যবহার করে। এই আলোচনার থ্রেডের জন্য ধন্যবাদ, আমি কিভাবে এই কাজ করতে পেরেছি!

উদাহরণস্বরূপ, আমি পদ্ধতিটি কল করে WebService প্রতিক্রিয়াতে সমস্ত বৈশিষ্ট্যগুলির বিস্ফোরণ বা ডাম্প দেখানোর জন্য এই পদ্ধতিটি ব্যবহার করি:

PropertyValues_byRecursion("Response", response, false);

public static object GetPropertyValue(object srcObj, string propertyName)
{
  if (srcObj == null) 
  {
    return null; 
  }
  PropertyInfo pi = srcObj.GetType().GetProperty(propertyName.Replace("[]", ""));
  if (pi == null)
  {
    return null;
  }
  return pi.GetValue(srcObj);
}

public static void PropertyValues_byRecursion(string parentPath, object parentObj, bool showNullValues)
{
  /// Processes all of the objects contained in the parent object.
  ///   If an object has a Property Value, then the value is written to the Console
  ///   Else if the object is a container, then this method is called recursively
  ///       using the current path and current object as parameters

  // Note:  If you do not want to see null values, set showNullValues = false

  foreach (PropertyInfo pi in parentObj.GetType().GetTypeInfo().GetProperties())
  {
    // Build the current object property's namespace path.  
    // Recursion extends this to be the property's full namespace path.
    string currentPath = parentPath + "." + pi.Name;

    // Get the selected property's value as an object
    object myPropertyValue = GetPropertyValue(parentObj, pi.Name);
    if (myPropertyValue == null)
    {
      // Instance of Property does not exist
      if (showNullValues)
      {
        Console.WriteLine(currentPath + " = null");
        // Note: If you are replacing these Console.Write... methods callback methods,
        //       consider passing DBNull.Value instead of null in any method object parameters.
      }
    }
    else if (myPropertyValue.GetType().IsArray)
    {
      // myPropertyValue is an object instance of an Array of business objects.
      // Initialize an array index variable so we can show NamespacePath[idx] in the results.
      int idx = 0;
      foreach (object business in (Array)myPropertyValue)
      {
        if (business == null)
        {
          // Instance of Property does not exist
          // Not sure if this is possible in this context.
          if (showNullValues)
          {
            Console.WriteLine(currentPath  + "[" + idx.ToString() + "]" + " = null");
          }
        }
        else if (business.GetType().IsArray)
        {
          // myPropertyValue[idx] is another Array!
          // Let recursion process it.
          PropertyValues_byRecursion(currentPath + "[" + idx.ToString() + "]", business, showNullValues);
        }
        else if (business.GetType().IsSealed)
        {
          // Display the Full Property Path and its Value
          Console.WriteLine(currentPath + "[" + idx.ToString() + "] = " + business.ToString());
        }
        else
        {
          // Unsealed Type Properties can contain child objects.
          // Recurse into my property value object to process its properties and child objects.
          PropertyValues_byRecursion(currentPath + "[" + idx.ToString() + "]", business, showNullValues);
        }
        idx++;
      }
    }
    else if (myPropertyValue.GetType().IsSealed)
    {
      // myPropertyValue is a simple value
      Console.WriteLine(currentPath + " = " + myPropertyValue.ToString());
    }
    else
    {
      // Unsealed Type Properties can contain child objects.
      // Recurse into my property value object to process its properties and child objects.
      PropertyValues_byRecursion(currentPath, myPropertyValue, showNullValues);
    }
  }
}

ছোট উপায় ....

var a = new Test { Id = 1 , Name = "A" , date = DateTime.Now};
var b = new Test { Id = 1 , Name = "AXXX", date = DateTime.Now };

var compare = string.Join("",a.GetType().GetProperties().Select(x => x.GetValue(a)).ToArray())==
              string.Join("",b.GetType().GetProperties().Select(x => x.GetValue(b)).ToArray());

Dim NewHandle As YourType = CType(Microsoft.VisualBasic.CallByName(ObjectThatContainsYourVariable, "YourVariableName", CallType), YourType)

System.fo প্রতিস্থাপন নামস্থান সম্পত্তি Propertyfo ব্যবহার। প্রতিফলন আমরা ঠিক কোনও সম্পত্তিটি অ্যাক্সেস করার চেষ্টা করি ঠিকই কম্পাইল করে। ত্রুটি রান সময় সময় আসবে।

    public static object GetObjProperty(object obj, string property)
    {
        Type t = obj.GetType();
        PropertyInfo p = t.GetProperty("Location");
        Point location = (Point)p.GetValue(obj, null);
        return location;
    }

এটি একটি বস্তুর অবস্থান সম্পত্তি পেতে জরিমানা কাজ করে

Label1.Text = GetObjProperty(button1, "Location").ToString();

আমরা অবস্থানটি পাবেন: {X = 71, Y = 27} আমরা একই স্থানে অবস্থান করতে পারেন। এক্স বা অবস্থান।


Microsoft.VisualBasic CallByName ব্যবহার সম্পর্কে কী। CallByName নামস্থান ( Microsoft.VisualBasic.dll CallByName . CallByName )? এটি বৈশিষ্ট্য, ক্ষেত্র এবং স্বাভাবিক বস্তুর পদ্ধতিগুলি, COM বস্তুগুলি এবং এমনকি গতিশীল বস্তুগুলি পেতে প্রতিফলন ব্যবহার করে।

using Microsoft.VisualBasic;
using Microsoft.VisualBasic.CompilerServices;

এবং তারপর

Versioned.CallByName(this, "method/function/prop name", CallType.Get).ToString();

 public static object GetPropValue(object src, string propName)
 {
     return src.GetType().GetProperty(propName).GetValue(src, null);
 }

অবশ্যই, আপনি বৈধতা এবং whatnot যোগ করতে চান, কিন্তু যে এর মূলতম।


কোন Class :

public class Foo
{
    public object this[string propertyName]
    {
        get { return this.GetType().GetProperty(propertyName).GetValue(this, null); }
        set { this.GetType().GetProperty(propertyName).SetValue(this, value, null); }
    }

    public string Bar { get; set; }
}

তারপর, আপনি এই হিসাবে ব্যবহার করতে পারেন:

Foo f = new Foo();
// Set
f["Bar"] = "asdf";
// Get
string s = (string)f["Bar"];

এখানে আমার সমাধান। এটি COM বস্তুর সাথেও কাজ করে এবং COM বস্তুর থেকে সংগ্রহ / অ্যারে আইটেম অ্যাক্সেস করতে দেয়।

public static object GetPropValue(this object obj, string name)
{
    foreach (string part in name.Split('.'))
    {
        if (obj == null) { return null; }

        Type type = obj.GetType();
        if (type.Name == "__ComObject")
        {
            if (part.Contains('['))
            {
                string partWithoundIndex = part;
                int index = ParseIndexFromPropertyName(ref partWithoundIndex);
                obj = Versioned.CallByName(obj, partWithoundIndex, CallType.Get, index);
            }
            else
            {
                obj = Versioned.CallByName(obj, part, CallType.Get);
            }
        }
        else
        {
            PropertyInfo info = type.GetProperty(part);
            if (info == null) { return null; }
            obj = info.GetValue(obj, null);
        }
    }
    return obj;
}

private static int ParseIndexFromPropertyName(ref string name)
{
    int index = -1;
    int s = name.IndexOf('[') + 1;
    int e = name.IndexOf(']');
    if (e < s)
    {
        throw new ArgumentException();
    }
    string tmp = name.Substring(s, e - s);
    index = Convert.ToInt32(tmp);
    name = name.Substring(0, s - 1);
    return index;
}

public static List<KeyValuePair<string, string>> GetProperties(object item) //where T : class
    {
        var result = new List<KeyValuePair<string, string>>();
        if (item != null)
        {
            var type = item.GetType();
            var properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
            foreach (var pi in properties)
            {
                var selfValue = type.GetProperty(pi.Name).GetValue(item, null);
                if (selfValue != null)
                {
                    result.Add(new KeyValuePair<string, string>(pi.Name, selfValue.ToString()));
                }
                else
                {
                    result.Add(new KeyValuePair<string, string>(pi.Name, null));
                }
            }
        }
        return result;
    }

এটি একটি তালিকা তাদের মান সঙ্গে সব বৈশিষ্ট্য পেতে একটি উপায়।


নিচের পদ্ধতিটি আমার জন্য নিখুঁত কাজ করে:

class MyClass {
    public string prop1 { set; get; }

    public object this[string propertyName]
    {
        get { return this.GetType().GetProperty(propertyName).GetValue(this, null); }
        set { this.GetType().GetProperty(propertyName).SetValue(this, value, null); }
    }
}

সম্পত্তি মান পেতে:

MyClass t1 = new MyClass();
...
string value = t1["prop1].ToString();

সম্পত্তি মান নির্ধারণ করতে:

t1["prop1] = value;




reflection