আমি স্থিতিশীল বৈশিষ্ট্যের সেট সহ একটি শ্রেণি তৈরির উপায় খুঁজছি। রান সময়ে, আমি ডাটাবেস থেকে এই বস্তুটিতে অন্যান্য গতিশীল বৈশিষ্ট্য যুক্ত করতে সক্ষম হতে চাই। আমি এই বিষয়গুলিতে বাছাই এবং ফিল্টারিং ক্ষমতা যুক্ত করতে চাই।
আমি সি # তে এটি কীভাবে করব?
আমি স্থিতিশীল বৈশিষ্ট্যের সেট সহ একটি শ্রেণি তৈরির উপায় খুঁজছি। রান সময়ে, আমি ডাটাবেস থেকে এই বস্তুটিতে অন্যান্য গতিশীল বৈশিষ্ট্য যুক্ত করতে সক্ষম হতে চাই। আমি এই বিষয়গুলিতে বাছাই এবং ফিল্টারিং ক্ষমতা যুক্ত করতে চাই।
আমি সি # তে এটি কীভাবে করব?
উত্তর:
আপনি একটি অভিধান ব্যবহার করতে পারেন, বলুন
Dictionary<string,object> properties;
আমি মনে করি বেশিরভাগ ক্ষেত্রে যেখানে অনুরূপ কিছু করা হয়, এটি এইভাবে করা হয়।
যাই হোক না কেন, আপনি সেট সহ "আসল" সম্পত্তি তৈরি এবং অ্যাক্সেসর পেতে কোনও কিছুই অর্জন করতে পারবেন না, কারণ এটি কেবল রান-টাইমে তৈরি করা হবে এবং আপনি এটি আপনার কোডটিতে ব্যবহার করবেন না ...
এখানে একটি উদাহরণ রয়েছে, ফিল্টারিং এবং বাছাইয়ের সম্ভাব্য প্রয়োগ দেখানো হচ্ছে (কোনও ত্রুটি যাচাই করা হয়নি):
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApplication1 {
class ObjectWithProperties {
Dictionary<string, object> properties = new Dictionary<string,object>();
public object this[string name] {
get {
if (properties.ContainsKey(name)){
return properties[name];
}
return null;
}
set {
properties[name] = value;
}
}
}
class Comparer<T> : IComparer<ObjectWithProperties> where T : IComparable {
string m_attributeName;
public Comparer(string attributeName){
m_attributeName = attributeName;
}
public int Compare(ObjectWithProperties x, ObjectWithProperties y) {
return ((T)x[m_attributeName]).CompareTo((T)y[m_attributeName]);
}
}
class Program {
static void Main(string[] args) {
// create some objects and fill a list
var obj1 = new ObjectWithProperties();
obj1["test"] = 100;
var obj2 = new ObjectWithProperties();
obj2["test"] = 200;
var obj3 = new ObjectWithProperties();
obj3["test"] = 150;
var objects = new List<ObjectWithProperties>(new ObjectWithProperties[]{ obj1, obj2, obj3 });
// filtering:
Console.WriteLine("Filtering:");
var filtered = from obj in objects
where (int)obj["test"] >= 150
select obj;
foreach (var obj in filtered){
Console.WriteLine(obj["test"]);
}
// sorting:
Console.WriteLine("Sorting:");
Comparer<int> c = new Comparer<int>("test");
objects.Sort(c);
foreach (var obj in objects) {
Console.WriteLine(obj["test"]);
}
}
}
}
আপনি ডাটা-বাঁধাই উদ্দেশ্যে এই প্রয়োজন হয়, আপনি একটি কাস্টম বর্ণনাকারী মডেল সঙ্গে এই কাজ করতে পারেন ... প্রয়োগ করে ICustomTypeDescriptor, TypeDescriptionProviderএবং / অথবা TypeCoverter, আপনি আপনার নিজের তৈরি করতে পারেন PropertyDescriptorরানটাইম এ দৃষ্টান্ত। এটি নিয়ন্ত্রণ করে পছন্দ কি DataGridView, PropertyGridপ্রদর্শন বৈশিষ্ট্য ইত্যাদি ব্যবহার।
তালিকাগুলিতে আবদ্ধ হওয়ার জন্য, আপনার প্রয়োজন হবে ITypedListএবং IList; মৌলিক সাজানোর জন্য: IBindingList; ফিল্টারিং এবং উন্নত সাজানোর জন্য: IBindingListView; সম্পূর্ণ "নতুন সারি" সমর্থনের জন্য ( DataGridView): ICancelAddNew(ভাও!)।
যদিও এটি অনেক কাজ। DataTable(যদিও আমি এটি ঘৃণা করি) একই জিনিসটি করার সস্তা উপায়। আপনার যদি ডেটা বাইন্ডিংয়ের প্রয়োজন না হয় তবে কেবল একটি হ্যাশটেবল ;-p ব্যবহার করুন
এখানে একটি সাধারণ উদাহরণ - তবে আপনি আরও অনেক কিছু করতে পারেন ...
এমভিসি 3 তে ভিউব্যাগের মতো ExpandoObject ব্যবহার করুন ।
"প্রোপার্টি" নামে একটি হ্যাশটেবল তৈরি করুন এবং এতে আপনার সম্পত্তি যুক্ত করুন।
আমি নিশ্চিত নই যে আপনি যা বলতে চান তা আপনি সত্যিই করতে চান তবে আমার পক্ষে যুক্তি দেওয়া কারণ নয়!
কোনও শ্রেণিতে এটি জেআইটিড হওয়ার পরে আপনি কোনও বৈশিষ্ট্য যুক্ত করতে পারবেন না।
আপনি যে নিকটস্থতে পেলেন তা হ'ল গতিশীলভাবে প্রতিবিম্বের সাথে একটি সাব টাইপ তৈরি করা। বিদ্যমান ক্ষেত্রগুলি অনুলিপি করুন এবং অনুলিপি করুন তবে আপনাকে অবজেক্টের সমস্ত রেফারেন্স নিজেই আপডেট করতে হবে।
আপনি সংকলন সময়ে এই বৈশিষ্ট্য অ্যাক্সেস করতে সক্ষম হবে না।
কিছুটা এইরকম:
public class Dynamic
{
public Dynamic Add<T>(string key, T value)
{
AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("DynamicAssembly"), AssemblyBuilderAccess.Run);
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("Dynamic.dll");
TypeBuilder typeBuilder = moduleBuilder.DefineType(Guid.NewGuid().ToString());
typeBuilder.SetParent(this.GetType());
PropertyBuilder propertyBuilder = typeBuilder.DefineProperty(key, PropertyAttributes.None, typeof(T), Type.EmptyTypes);
MethodBuilder getMethodBuilder = typeBuilder.DefineMethod("get_" + key, MethodAttributes.Public, CallingConventions.HasThis, typeof(T), Type.EmptyTypes);
ILGenerator getter = getMethodBuilder.GetILGenerator();
getter.Emit(OpCodes.Ldarg_0);
getter.Emit(OpCodes.Ldstr, key);
getter.Emit(OpCodes.Callvirt, typeof(Dynamic).GetMethod("Get", BindingFlags.Instance | BindingFlags.NonPublic).MakeGenericMethod(typeof(T)));
getter.Emit(OpCodes.Ret);
propertyBuilder.SetGetMethod(getMethodBuilder);
Type type = typeBuilder.CreateType();
Dynamic child = (Dynamic)Activator.CreateInstance(type);
child.dictionary = this.dictionary;
dictionary.Add(key, value);
return child;
}
protected T Get<T>(string key)
{
return (T)dictionary[key];
}
private Dictionary<string, object> dictionary = new Dictionary<string,object>();
}
আমার কাছে এই মেশিনে ভিএস ইনস্টল করা নেই তাই কোনও বিশাল বাগ রয়েছে কিনা তা আমাকে জানান (ভাল ... বিশাল পারফরম্যান্স সমস্যা ছাড়াও, তবে আমি স্পেসিফিকেশনটি লিখিনি!)
এখন আপনি এটি ব্যবহার করতে পারেন:
Dynamic d = new Dynamic();
d = d.Add("MyProperty", 42);
Console.WriteLine(d.GetType().GetProperty("MyProperty").GetValue(d, null));
দেরীতে বাইন্ডিং সমর্থন করে এমন ভাষায় আপনি এটি একটি সাধারণ সম্পত্তির মতো ব্যবহার করতে পারেন (উদাহরণস্বরূপ, VB.NET)
আমি একটি আইসুস্টমটাইপডেস্ক্রিপ্টর ইন্টারফেস এবং একটি অভিধান দিয়ে ঠিক এটি করেছি।
গতিশীল বৈশিষ্ট্যগুলির জন্য আইকুস্টমটাইপডেস্কিটার কার্যকর করা:
আমার সম্প্রতি একটি রেকর্ড অবজেক্টে গ্রিড ভিউ বাঁধাই করার প্রয়োজন ছিল যা রানটাইমে যোগ এবং সরানো যায় এমন অনেক সংখ্যক বৈশিষ্ট্য থাকতে পারে। এটি ব্যবহারকারীর অতিরিক্ত তথ্যের সেট সেট করার জন্য ফলাফলকে নতুন কলাম যুক্ত করার অনুমতি দেয়।
প্রতিটি ডাটা 'সারি' অভিধান হিসাবে কী হিসাবে সম্পত্তির নাম এবং মান একটি স্ট্রিং বা শ্রেণি যা নির্দিষ্ট সারির জন্য সম্পত্তির মান সঞ্চয় করতে পারে তা দিয়ে এটি অর্জন করা যেতে পারে। অবশ্যই অভিধানের সামগ্রীর তালিকা থাকা কোনও গ্রিডের সাথে আবদ্ধ হতে পারবে না। এখানেই আইসুস্টম টাইপডেস্কিটার আসে।
অভিধানের জন্য একটি মোড়কের ক্লাস তৈরি করে এবং এটি আইসাস্টমটাইপডেস্ক্রিপ্টর ইন্টারফেসের সাথে মেনে চলার মাধ্যমে কোনও সামগ্রীর জন্য বৈশিষ্ট্যগুলি ফিরিয়ে দেওয়ার আচরণকে ওভাররাইড করা যেতে পারে।
নীচে ডেটা 'সারি' শ্রেণীর বাস্তবায়নটি দেখুন:
/// <summary>
/// Class to manage test result row data functions
/// </summary>
public class TestResultRowWrapper : Dictionary<string, TestResultValue>, ICustomTypeDescriptor
{
//- METHODS -----------------------------------------------------------------------------------------------------------------
#region Methods
/// <summary>
/// Gets the Attributes for the object
/// </summary>
AttributeCollection ICustomTypeDescriptor.GetAttributes()
{
return new AttributeCollection(null);
}
/// <summary>
/// Gets the Class name
/// </summary>
string ICustomTypeDescriptor.GetClassName()
{
return null;
}
/// <summary>
/// Gets the component Name
/// </summary>
string ICustomTypeDescriptor.GetComponentName()
{
return null;
}
/// <summary>
/// Gets the Type Converter
/// </summary>
TypeConverter ICustomTypeDescriptor.GetConverter()
{
return null;
}
/// <summary>
/// Gets the Default Event
/// </summary>
/// <returns></returns>
EventDescriptor ICustomTypeDescriptor.GetDefaultEvent()
{
return null;
}
/// <summary>
/// Gets the Default Property
/// </summary>
PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty()
{
return null;
}
/// <summary>
/// Gets the Editor
/// </summary>
object ICustomTypeDescriptor.GetEditor(Type editorBaseType)
{
return null;
}
/// <summary>
/// Gets the Events
/// </summary>
EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes)
{
return new EventDescriptorCollection(null);
}
/// <summary>
/// Gets the events
/// </summary>
EventDescriptorCollection ICustomTypeDescriptor.GetEvents()
{
return new EventDescriptorCollection(null);
}
/// <summary>
/// Gets the properties
/// </summary>
PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes)
{
List<propertydescriptor> properties = new List<propertydescriptor>();
//Add property descriptors for each entry in the dictionary
foreach (string key in this.Keys)
{
properties.Add(new TestResultPropertyDescriptor(key));
}
//Get properties also belonging to this class also
PropertyDescriptorCollection pdc = TypeDescriptor.GetProperties(this.GetType(), attributes);
foreach (PropertyDescriptor oPropertyDescriptor in pdc)
{
properties.Add(oPropertyDescriptor);
}
return new PropertyDescriptorCollection(properties.ToArray());
}
/// <summary>
/// gets the Properties
/// </summary>
PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties()
{
return ((ICustomTypeDescriptor)this).GetProperties(null);
}
/// <summary>
/// Gets the property owner
/// </summary>
object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd)
{
return this;
}
#endregion Methods
//---------------------------------------------------------------------------------------------------------------------------
}
দ্রষ্টব্য: getProperties পদ্ধতিতে আমি একবার সম্পত্তি সম্পাদনাকারীদের ক্যাশে করতে পারলাম পারফরম্যান্সের জন্য তবে আমি রানটাইমের সময় কলামগুলি যুক্ত করছি এবং মুছে ফেলছি আমি সর্বদা সেগুলি পুনর্নির্মাণ করতে চাই
আপনি getProperties পদ্ধতিতে লক্ষ্য করবেন যে অভিধান এন্ট্রিগুলির জন্য সংখ্যার সম্পত্তি বর্ণনাকারীরা টেস্টারেলসাল্টপ্রোপার্টিডেস্কিটার টাইপ করে। এটি একটি কাস্টম সম্পত্তি বর্ণনাকারী শ্রেণি যা সম্পত্তি কীভাবে সেট এবং পুনরুদ্ধার করা হয় তা পরিচালনা করে। নীচের বাস্তবায়নটি একবার দেখুন:
/// <summary>
/// Property Descriptor for Test Result Row Wrapper
/// </summary>
public class TestResultPropertyDescriptor : PropertyDescriptor
{
//- PROPERTIES --------------------------------------------------------------------------------------------------------------
#region Properties
/// <summary>
/// Component Type
/// </summary>
public override Type ComponentType
{
get { return typeof(Dictionary<string, TestResultValue>); }
}
/// <summary>
/// Gets whether its read only
/// </summary>
public override bool IsReadOnly
{
get { return false; }
}
/// <summary>
/// Gets the Property Type
/// </summary>
public override Type PropertyType
{
get { return typeof(string); }
}
#endregion Properties
//- CONSTRUCTOR -------------------------------------------------------------------------------------------------------------
#region Constructor
/// <summary>
/// Constructor
/// </summary>
public TestResultPropertyDescriptor(string key)
: base(key, null)
{
}
#endregion Constructor
//- METHODS -----------------------------------------------------------------------------------------------------------------
#region Methods
/// <summary>
/// Can Reset Value
/// </summary>
public override bool CanResetValue(object component)
{
return true;
}
/// <summary>
/// Gets the Value
/// </summary>
public override object GetValue(object component)
{
return ((Dictionary<string, TestResultValue>)component)[base.Name].Value;
}
/// <summary>
/// Resets the Value
/// </summary>
public override void ResetValue(object component)
{
((Dictionary<string, TestResultValue>)component)[base.Name].Value = string.Empty;
}
/// <summary>
/// Sets the value
/// </summary>
public override void SetValue(object component, object value)
{
((Dictionary<string, TestResultValue>)component)[base.Name].Value = value.ToString();
}
/// <summary>
/// Gets whether the value should be serialized
/// </summary>
public override bool ShouldSerializeValue(object component)
{
return false;
}
#endregion Methods
//---------------------------------------------------------------------------------------------------------------------------
}
এই শ্রেণিতে দেখার জন্য প্রধান বৈশিষ্ট্যগুলি হ'ল getValue এবং সেটভ্যালু। এখানে আপনি উপাদান হিসাবে একটি অভিধান হিসাবে কাস্ট করা হচ্ছে এবং এর ভিতরে থাকা কীটির মান সেট বা পুনরুদ্ধার করতে পারবেন। এটি গুরুত্বপূর্ণ যে এই শ্রেণীর অভিধানটি সারি র্যাপার ক্লাসে একই ধরণের হয় অন্যথায় castালাই ব্যর্থ হবে। যখন বর্ণনাকারীটি তৈরি করা হয় তখন কী (সম্পত্তির নাম )টি পাস করা হয় এবং সঠিক মান পেতে অভিধানে কোয়েরি করতে ব্যবহৃত হয়।
আমার ব্লগ থেকে এখানে নেওয়া:
গতিশীল বৈশিষ্ট্যগুলির জন্য আইসিস্টমটাইপডিজিপেক্টর বাস্তবায়ন
ডাব্লুপিএফ দ্বারা ব্যবহৃত ডিপেন্ডেন্সিঅবজেক্টগুলিতে আপনাকে নজর দেওয়া উচিত এগুলি অনুরূপ প্যাটার্ন অনুসরণ করে যেখানে রানটাইমটিতে সম্পত্তি নির্ধারিত হতে পারে। উপরে উল্লিখিত হিসাবে এটি শেষ পর্যন্ত একটি হ্যাশ টেবিল ব্যবহার দিকে নির্দেশ করে।
আর একটি দরকারী জিনিস সন্ধান করার জন্য হ'ল CSLA.Net । কোডটি অবাধে উপলভ্য এবং কিছু নীতি-নিদর্শনগুলি ব্যবহার করে যা এটি পরে দেখা যায়।
এছাড়াও আপনি যদি বাছাই এবং ফিল্টারিংয়ের দিকে তাকিয়ে থাকেন তবে আমি অনুমান করছি আপনি কোনও একরকম গ্রিড ব্যবহার করবেন। বাস্তবায়নের জন্য একটি দরকারী ইন্টারফেস হ'ল আইকাস্টমটাইপডিজিপেক্টর, এটি আপনাকে কার্যকরভাবে কীভাবে ওভাররাইড করতে দেয় যখন আপনার বস্তুর প্রতিফলিত হয়ে যায় তাই আপনি আপনার বস্তুর নিজস্ব অভ্যন্তরীণ হ্যাশ টেবিলের প্রতিফলককে নির্দেশ করতে পারেন।
ওরসোগুফো-র কোডগুলির কিছু পরিবর্তনের জন্য, কারণ আমি সম্প্রতি এই একই সমস্যার জন্য একটি অভিধান নিয়ে এসেছি, এখানে আমার [] অপারেটর:
public string this[string key]
{
get { return properties.ContainsKey(key) ? properties[key] : null; }
set
{
if (properties.ContainsKey(key))
{
properties[key] = value;
}
else
{
properties.Add(key, value);
}
}
}
এই প্রয়োগের সাথে সাথে, সেটার যখন নতুন শব্দ-মান যুক্ত যুক্ত করে আপনি যখন ব্যবহার করেন []=যদি অভিধানে ইতিমধ্যে তা বিদ্যমান না থাকে।
এছাড়াও, আমার জন্য propertiesএটি একটি IDictionaryএবং কন্সট্রাক্টর আমি এটিতে আরম্ভ করি new SortedDictionary<string, string>()।
record[name_column] = DBConvert.To<string>(r[name_column]);কোথায় recordরয়েছে সে হিসাবে আমি সেবার পাশে একটি মান নির্ধারণ করছি । আমি ক্লায়েন্ট পক্ষ থেকে এই মান পেতে পারি?
আপনার কারণগুলি কী তা আমি নিশ্চিত নই এবং আপনি যদি প্রতিচ্ছবি ইমিট দিয়ে কোনওভাবে এটিকে সরিয়ে ফেলতে পারেন (তবে আমি নিশ্চিত নই যে আপনি এটি করতে পারেন) তবে এটি কোনও ভাল ধারণা বলে মনে হয় না। সম্ভবত কিছু ভাল ধারণা হ'ল একধরনের ডিকশনারি রাখা এবং আপনি আপনার ক্লাসের পদ্ধতিগুলির মাধ্যমে অভিধানটিতে অ্যাক্সেস মোড়ানো করতে পারেন। এই অভিধানে আপনি ডাটাবেস থেকে ডেটা সঞ্চয় করতে পারেন এবং তারপরে এই পদ্ধতিগুলি ব্যবহার করে তাদের পুনরুদ্ধার করতে পারেন।
সূচকের কাছে স্ট্রিংয়ের মান হিসাবে সম্পত্তিটির নামের সাথে কোনও সূচক ব্যবহার করবেন না কেন?