Store generic data in a non-generic class - c#

I have a DataGridView that I want to use to store generic data. I want to keep a typed data list in the DataGridView class so that all of the sorts, etc. can be handled internally. But I don't want to have to set the type on the DataGridView since I won't know the data type until the InitializeData method is called.
public class MyDataGridView : DataGridView {
private List<T> m_data;
public InitializeData<T>(List<T> data) {
m_data = data;
}
... internal events to know when the datagrid wants to sort ...
m_data.Sort<T>(...)
}
Is this possible? If so, how?

If you won't know the type until you call InitializeData, then the type clearly can't be a compile-time part of the object.
Do you know everything you need to know about the sorting when you call InitializeData<T>? If so, how about you do something like:
private IList m_data;
private Action m_sorter;
public InitializeData<T>(List<T> data)
{
m_data = data;
// This captures the data variable. You'll need to
// do something different if that's not good enough
m_sorter = () => data.Sort();
}
Then when you need to sort later, you can just call m_sorter().
If you might sort on different things, you could potentially change it from an Action to Action<string> or whatever you'd need to be able to sort on.

If Jon's answer isn't sufficient, here's a more general (but more involved, and probably somewhat more confusing) approach:
/// <summary>
/// Allows a list of any type to be used to get a result of type TResult
/// </summary>
/// <typeparam name="TResult">The result type after using the list</typeparam>
interface IListUser<TResult>
{
TResult Use<T>(List<T> list);
}
/// <summary>
/// Allows a list of any type to be used (with no return value)
/// </summary>
interface IListUser
{
void Use<T>(List<T> list);
}
/// <summary>
/// Here's a class that can sort lists of any type
/// </summary>
class GenericSorter : IListUser
{
#region IListUser Members
public void Use<T>(List<T> list)
{
// do generic sorting stuff here
}
#endregion
}
/// <summary>
/// Wraps a list of some unknown type. Allows list users (either with or without return values) to use the wrapped list.
/// </summary>
interface IExistsList
{
TResult Apply<TResult>(IListUser<TResult> user);
void Apply(IListUser user);
}
/// <summary>
/// Wraps a list of type T, hiding the type itself.
/// </summary>
/// <typeparam name="T">The type of element contained in the list</typeparam>
class ExistsList<T> : IExistsList
{
List<T> list;
public ExistsList(List<T> list)
{
this.list = list;
}
#region IExistsList Members
public TResult Apply<TResult>(IListUser<TResult> user)
{
return user.Use(list);
}
public void Apply(IListUser user)
{
user.Use(list);
}
#endregion
}
/// <summary>
/// Your logic goes here
/// </summary>
class MyDataGridView
{
private IExistsList list;
public void InitializeData<T>(List<T> list)
{
this.list = new ExistsList<T>(list);
}
public void Sort()
{
list.Apply(new GenericSorter());
}
}

You should define delgates or an interface for any generic operations you need to perform at runtime. As Jon Skeet mentioned, you can't strongly-type your data grid if you don't know the types at compile time.
This is the way the framework does it. For example:
Array.Sort();
Has a few ways it can be used:
Send it an array of objects that implement IComparable or IComparable<T>
Send in a second parameter, which is a class that implements IComparer or IComparer<T>. Used to compare the objects for sorting.
Send in a second parameter, which is a Comparison<T> delegate that can be used to compare objects in the array.
This is an example of how you approach the problem. At its most basic level, your scenario can be solved by a strategy pattern, which is what Array.Sort() does.
If you need to sort by things dynamically at run time, I would create an IComparer class that takes the column you want to sort by as an argument in its constructor. Then in your compare method, use that column as the sort type.
Here is an example of how you would do it using some basic example classes. Once you have these classes set up, then you'd pass both into your data grid and use them where appropriate.
public class Car
{
public string Make { get; set; }
public string Model { get; set; }
public string Year { get; set; }
}
public class CarComparer : IComparer
{
string sortColumn;
public CarComparer(string sortColumn)
{
this.sortColumn = sortColumn;
}
public int Compare(object x, object y)
{
Car carX = x as Car;
Car carY = y as Car;
if (carX == null && carY == null)
return 0;
if (carX != null && carY == null)
return 1;
if (carY != null && carX == null)
return -1;
switch (sortColumn)
{
case "Make":
return carX.Make.CompareTo(carY.Make);
case "Model":
return carX.Model.CompareTo(carY.Model);
case "Year":
default:
return carX.Year.CompareTo(carY.Year);
}
}
}

Related

Cast base class to derive class in .NET Core

I want to create a class to call stored procedures in my SQL Server. I'm using C# with .NET Core 3.1. All stored procedures return the same results but in some cases I have to do more activities and then every function has its own return type base on a base class, in the code below called BaseResponse.
public class BaseResponse
{
public int ErrorCode { get; set; }
public string Message { get; set; }
}
public class InvoiceResponse : BaseResponse
{
public bool IsPaid { get; set; }
}
Then, I have my BaseCall that it is responsible to call a stored procedure and return the BaseResponse.
public async Task<BaseResponse> BaseCall(string procedureName, string[] params)
{
BaseResponse rtn = new BaseResponse();
// call SQL Server stored procedure
return rtn;
}
In another class I want to cast the BaseResponse with the derive class. For that, I thought I can cast the BaseResponse with the derive class but I was wrong.
public async Task<InvoiceResponse> GetInvoice(int id)
{
InvoiceResponse rtn = new InvoiceResponse();
BaseResponse response = BaseCall("myprocedure", null);
rtn = (InvoiceResponse)response;
// do something else
return rtn;
}
I saw other two posts (Convert base class to derived class and this one) and I understood I can't cast in the way I wanted. Then I was my extension from that
/// <summary>
/// Class BaseClassConvert.
/// </summary>
public static class BaseClassConvert
{
/// <summary>
/// Maps to new object.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="sourceobject">The sourceobject.</param>
/// <returns>T.</returns>
/// <remarks>
/// The target object is created on the fly and the target type
/// must have a parameterless constructor (either compiler-generated or explicit)
/// </remarks>
public static T MapToNewObject<T>(this object sourceobject) where T : new()
{
// create an instance of the target class
T targetobject = (T)Activator.CreateInstance(typeof(T));
// map the source properties to the target object
MapToExistingObject(sourceobject, targetobject);
return targetobject;
}
/// <summary>
/// Maps to existing object.
/// </summary>
/// <param name="sourceobject">The sourceobject.</param>
/// <param name="targetobject">The targetobject.</param>
/// <remarks>The target object is created beforehand and passed in</remarks>
public static void MapToExistingObject(this object sourceobject, object targetobject)
{
// get the list of properties available in source class
var sourceproperties = sourceobject.GetType().GetProperties().ToList();
// loop through source object properties
sourceproperties.ForEach(sourceproperty =>
{
var targetProp = targetobject.GetType().GetProperty(sourceproperty.Name);
// check whether that property is present in target class and is writeable
if (targetProp != null && targetProp.CanWrite)
{
// if present get the value and map it
var value = sourceobject.GetType().GetProperty(sourceproperty.Name).GetValue(sourceobject, null);
targetobject.GetType().GetProperty(sourceproperty.Name).SetValue(targetobject, value, null);
}
});
}
}
This code is working and I can use it like:
public async Task<InvoiceResponse> GetInvoice(int id)
{
InvoiceResponse rtn = new InvoiceResponse();
BaseResponse response = BaseCall("myprocedure", null);
response.MapToExistingObject(rtn);
// do something else
return rtn;
}
My questions are:
is there a more efficient way to cast the base class with a derive class in .NET Core?
is this the best practice for casting?
any other guide lines?
this procedure is using Reflection. In performance point of view, is it the right and cheapest way to implement this cast?
You can't cast (without getting error) expression returning/containing base class instance to any inheritor type if this instance not actually inherits it (and to check this there are type-testing operators in C#). Casting as the docs state is an attempt by compiler to perform an explicit conversion in runtime. Also as you mentioned you can't implement custom explicit conversion from or to base class.
What are you looking for (and trying to do) is called mapping and there are a lot of libraries for that, including but not limited to Automapper, Mapster or ExpressMapper for example.

C# Copy inheritance hierarchy into string/enum format

In my game I have merchants. All items have a standard price. Each merchant has an interpretation of this price. I have an item inheritance hierarchy. ConsumableItem and EquipableItem inherits from the base class GameItem, HoldableEquipableItem inherits from EquipableItem and so on. A merchant can add a multiplier to one of these types, so if he has a multiplier of 0.5 on EquipableItem it means EquipableItem and all types inheriting from it will have their price multiplied with 0.5 (halved).
The inheritance hierarchy fits my problem since it doesn't have to be retyped anywhere and the tool Type.IsSubclassOf is built in available.But I'm not too fond of using types for game mechanics mainly because I want to show the type in the Unity inspector and it doesn't support Type, so I would have to use a string to symbolize it and parse the type afterward (maybe also 'ethical' and performance issues?).
Is there a good way I could implement this with a string or enum type instead of Type? A class where you had a method similar to IsSubclassOf just using string/enum instead. The type of the item could either be reflected through a field/property, or just convert GetType in the hierarchy to the string/enum version.
I would go with something like this in your case:
public class GameItem {
public List<string> Type { get; private set; }
GameItem(List<string> type)
{
Type = type;
Type.Add(nameof(GameItem))
}
public IsType(string type)
{
return Type.Contains(type);
}
}
public class SubGameItem : GameItem
{
public SubGameItem(List<string> type)
: base(new List<string>(type){nameof(SubGameItem)})
{
}
}
If this is too hard coded for you, I will have to say I don't understand why, I think this is the least hardcoded way you can do to solve your issue, and it is probably better than using Type class.
If you don't have c#6, you will have to do it hardcoded, but I would use enums instead of string in that case (I would use enums anyway, but if you don't want have to make sure you updated the enum for each change, this is fine).
I forgot to post this. Here is my solution to the problem if anyone needs it.
/// <summary>
/// Mimics the Type inheritance hierarchy for enums
/// </summary>
// Enum is a special class that cannot be used as a constraint, so instead use its parent interface IConvertible
public class InheritanceHierarchy<T> where T : IConvertible
{
private Dictionary<T, InheritanceElement<T>> elements =
new Dictionary<T, InheritanceElement<T>>();
public void Add(T element, T parent)
{
var parentElement = parent.Equals(default(T)) ? null : elements[parent];
elements.Add(element, new InheritanceElement<T>(element, parentElement));
}
/// <summary>
/// Add parent for multiple children
/// </summary>
public void Add(T parent, params T[] elements)
{
foreach (var element in elements)
Add(element, parent);
}
public bool IsSameOrSubclass(T element, T parent)
{
return ParentIndex(element, parent) != -1;
}
/// <summary>
/// Get how many parents the element is from parent. If they don't relate return -1
/// </summary>
public int ParentIndex(T element, T parent)
{
// If the element is same as parent
if (element.Equals(parent))
return 0;
// Loop through the chain of parents checking until it is either null or a match
var actualParent = elements[element].parent;
var parentIndex = 1;
while (actualParent != null)
{
if (parent.Equals(actualParent.element))
return parentIndex;
else
{
actualParent = actualParent.parent;
parentIndex++;
}
}
return -1;
}
}
public class InheritanceElement<T> where T : IConvertible
{
public T element;
public InheritanceElement<T> parent;
public InheritanceElement(T element, InheritanceElement<T> parent)
{
this.element = element;
this.parent = parent;
}
}

Handling Different Sets of Data

Im having design/ architecture issues in how I am putting together my code. For example right now I store data in:
internal interface IProperty<TKey1, TKey2> : IDictionary<TKey1, TKey2> { }
internal class PropertyDictionary<TKey1, TKey2> : IProperty<TKey1, TKey2>
I implement IDictionary in PropertyDictionary. Also with PropertyDictionary i can then have a key and then for the value an immutable object with public properties. I can then reference the data easily by:
foreach (var data in inputData.Values)
{
var propertyValue = data.MyDataProperty;
}
Firstly this way seems a lot of overhead to store data but more importantly now when I need to extend the functionality of PropertyDictionary for example to include RetrievePrice it becomes complicated as I need to add the additional methods in an interface and then create a new class as so:
internal interface IAssetPriceData<in TKey1>
{
double RetrievePrice(TKey1 key);
}
internal class PriceDictionary<TKey1, TKey2> : PropertyDictionary<TKey1, TKey2>, IAssetPriceData<TKey1>
So a solution on how I should structure my code to easily store different types of data which is then easily retrieved so I can manipulate / perform calculation on the properties that are being stored.
For anyone interested, I wrote a class somewhat like the one described here once (below). I was grouping properties of the same type for some WPF binding scenarios, and binding to dictionary elements. I didn't want to use a dictionary because of the key not found exception that would be raise (and eaten) by the framework. This one wraps a dictionary and hardcodes strings as keys, though it could probably be generalized to suit the purpose described here. The main item of note is the behavior of the indexer when key is not found -- it returns the default T instead of throwing exception.
/// This class represents a generic collection of things for binding
/// Hash items is never null, Indexer never throws exceptions, returning defaults on cache miss
public class BindableHash : IEnumerable
{
#region Fields
/// <summary>Current implementation of the hash is a dictionary</summary>
private readonly Dictionary<string, T> _HashItems = new Dictionary<string, T>();
#endregion
#region Properties
/// <summary>How many items are currently in the hash</summary>
public virtual int Count { get { return _HashItems.Count; } }
/// <summary>Indexer provides hashed (by string) lookup</summary>
public virtual T this[string index]
{
get { return index != null && _HashItems.ContainsKey(index) ? _HashItems[index] : default(T); }
}
#endregion
#region Constructors
/// <summary>Default constructor initializes hash with no members</summary>
public BindableHash() : this(null) { }
/// <summary>Injected constructor seeds the list using the tuples passsed in</summary>
public BindableHash(params Tuple<string, T>[] initialTuples)
{
foreach (Tuple<string, T> tuple in initialTuples ?? new Tuple<string, T>[] { })
{
Add(tuple);
}
}
#endregion
#region Methods
/// <summary>Add a key-value pair to the hash</summary>
public virtual void Add(string key, T value)
{
Add(new Tuple<string, T>(key, value));
}
/// <summary>Removes all items from the hash</summary>
public virtual void Clear()
{
_HashItems.Clear();
}
/// <summary>Remove a particular value from the hash</summary>
public bool Remove(string key)
{
return key != null && _HashItems.Remove(key);
}
#endregion
#region Helpers
/// <summary>Abstraction for adding a key value pair</summary>
protected void Add(Tuple<string, T> tuple)
{
if (tuple != null && tuple.Item1 != null)
{
_HashItems[tuple.Item1] = tuple.Item2;
}
}
#endregion
#region IEnumerable<T> Members
/// <summary>Define enumerator retrieval to allow enumeration over values</summary>
public IEnumerator<T> GetEnumerator()
{
foreach (T value in _HashItems.Values)
{
yield return value;
}
}
#endregion
#region IEnumerable Members
/// <summary>Impelementation for clients who cast this as non-generic IEnumerable</summary>
/// <remarks>If you're not familiar with the black magic going on here, IEnmerable generic interface inherits from
/// IEnumerable non-generic (legacy). Both interfaces define GetEnumerator, and one returns a generic IEnumerator and the other
/// a non-generic IEnumerator. This one is the non-generic, and we want to 'hide' it for type safety purposes. When you
/// do an explicit interface implementation, you create some kind of visibility purgatory. This method is not private/protected
/// because the interface is public, but it is also not a public method of this class. The only way you can get to this guy is by casting
/// BindableHash as IEnumerable (non-generic) and invoking the method that way. Since that is possible to do, we have to implement the method,
/// which we do by just invoking our generic one. This is legal because of the fact that IEnumerator generic inherits from non-generic IEnumerator.
/// Clear as mud? You can ask me for a more detailed explanation, if you like --ebd</remarks>
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
#endregion
}

Is there anyway to cache function/method in C#

I got bored with writing same to code again and again to cache the objects in data access layer.
Is there anyway to cache c# function results without much changes to functions.
Is there any framework supports this functionality at the moment?
Can i archive the same by writing custom "c# function attributes"? if so, drop me some points to start implementation?
Possibility 1: Use IL Weaving
Postsharp was mentioned before.
You could also try the MethodCache.Fody package.
Possibility 2: Use an Proxy / Interception Framework
Example (Ninject & Ninject.Interception):
public class CacheAttribute : InterceptAttribute
{
public override IInterceptor CreateInterceptor(IProxyRequest request)
{
return request.Context.Kernel.Get<CachingInterceptor>();
}
}
public class CachingInterceptor : IInterceptor
{
private ICache Cache { get; set; }
public CachingInterceptor(ICache cache)
{
Cache = cache;
}
public void Intercept(IInvocation invocation)
{
string className = invocation.Request.Target.GetType().FullName;
string methodName = invocation.Request.Method.Name;
object[] arguments = invocation.Request.Arguments;
StringBuilder builder = new StringBuilder(100);
builder.Append(className);
builder.Append(".");
builder.Append(methodName);
arguments.ToList().ForEach(x =>
{
builder.Append("_");
builder.Append(x);
});
string cacheKey = builder.ToString();
object retrieve = Cache.Retrieve<object>(cacheKey);
if (retrieve == null)
{
invocation.Proceed();
retrieve = invocation.ReturnValue;
Cache.Store(cacheKey, retrieve);
}
else
{
invocation.ReturnValue = retrieve;
}
}
}
Then you could decorate functions like this:
[Cache]
public virtual Customer GetCustomerByID(int customerID)
{
return CustomerRepository.GetCustomerByID(customerID);
}
Intercepted functions have to be virtual and classes must be created by the Ninject kernel. If you rely on performance, you could proxy classes directly via Castle.DynamicProxy (which is internally used by Ninject.Extensions.Interception.DynamicProxy).
Possibility 3: Use an Expression wrapper
You could pass the function as expression, generate a caching key containing class, method and parameter information and invoke the expression if not found in your Cache. This adds more runtime overhead than AOP / Proxy frameworks, but will be sufficient for simple solutions.
private T CacheAction<T>(Expression<Func<T>> action, [CallerMemberName] string memberName = "") where T : class
{
MethodCallExpression body = (MethodCallExpression)action.Body;
ICollection<object> parameters = new List<object>();
foreach (MemberExpression expression in body.Arguments)
{
parameters.Add(((FieldInfo)expression.Member).GetValue(((ConstantExpression)expression.Expression).Value));
}
StringBuilder builder = new StringBuilder(100);
builder.Append(GetType().FullName);
builder.Append(".");
builder.Append(memberName);
parameters.ToList().ForEach(x =>
{
builder.Append("_");
builder.Append(x);
});
string cacheKey = builder.ToString();
T retrieve = Cache.Retrieve<T>(cacheKey);
if (retrieve == null)
{
retrieve = action.Compile().Invoke();
Cache.Store(cacheKey, retrieve);
}
return retrieve;
}
public Customer GetCustomerByID(int customerID)
{
return CacheAction(() => CustomerRepository.GetCustomerByID(customerID));
}
You can create caching attributes with PostSharp. You can use the Cache attribute.
If I read you question correct, the right term for what you want is memoization. Wikipedia gives more details on this subjects. Unfortunately there is no reference to a C# library supporting it.
Lazy store it's value after first run.
Example: http://msdn.microsoft.com/en-us/vstudio/bb870976
I use this simple implementation of the System.Runetime.Caching namespace:
public class InMemoryCache : ICacheService
{
public T GetOrSet<T>(string cacheKey, Func<T> getItemCallback) where T : class
{
T item = MemoryCache.Default.Get(cacheKey) as T;
if (item == null)
{
item = getItemCallback();
MemoryCache.Default.Add(cacheKey, item, DateTime.Now.AddHours(4));
}
return item;
}
public void Clear(string cacheKey)
{
MemoryCache.Default.Remove(cacheKey);
}
}
interface ICacheService
{
T GetOrSet<T>(string cacheKey, Func<T> getItemCallback) where T : class;
void Clear(string cacheKey);
}
Can be used in the following manner:
var cacheProvider = new InMemoryCache();
var cachedResult = cacheProvider.GetOrSet("YourCacheKey",
() => MethodToCache());
First call to the method will cache the result, the next call will return the cached result.
The Cache Application block is Microsoft's answer to built in library for Caching in .NET.
I suggest Spring.Net AOP.
It basically creates a proxy and the calls can be redirected from/to the cache.
http://www.springframework.net/doc/reference/html/aop-quickstart.html
and then you can have something like that for your advice:
public class CachingAroundAdvice : IMethodInterceptor
{
#region Variable Declarations
private Priority priority = Priority.Normal;
#endregion
public object Invoke(IMethodInvocation invocation)
{
// declare local variables
string cacheKey = string.Empty;
object dataObject = null;
// build cache key with some algorithm
cacheKey = CreateCacheKey(invocation.Method, invocation.Arguments);
// retrieve item from cache
dataObject = CacheManager.Cache.GetData(cacheKey);
// if the dataobject is not in cache proceed to retrieve it
if (null == dataObject)
{
dataObject = invocation.Proceed();
// add item to cache
CacheManager.Cache.Add(cacheKey, dataObject, CachePriority, null, Expiration);
}
// return data object
return dataObject;
}
You could use a Dictionary to cache the function. A dictionary maps keys to values and a function maps arguments to values. So conceptually, a dictionary fits as a cache for a function. Here's a simple class to do that:
/// <summary>
/// The lazy function map caches the results of calls to the backing function. Every time the function is called on an argument u and returns v,
/// the pair (u, v) is stored in the dictionary.
/// </summary>
class LazyFunctionMapImpl<T, U> : ILazyFunctionMap<T, U>
{
private readonly Dictionary<T, U> _backingDictionary;
private readonly Func<T, U> _backingFunction;
public LazyFunctionMapImpl(Func<T, U> backingFunction)
{
_backingDictionary = new Dictionary<T, U>();
_backingFunction = backingFunction;
}
public U this[T index]
{
get
{
if (_backingDictionary.ContainsKey(index))
{
return _backingDictionary[index];
}
U valueAtIndex = _backingFunction(index);
_backingDictionary.Add(index, valueAtIndex);
return valueAtIndex;
}
}
public void Clear()
{
_backingDictionary.Clear();
}
}
And here's a couple of interfaces to go with it:
/// <summary>
/// A function map that should lazily cache param/result pairs until clear is called.
/// </summary>
public interface ILazyFunctionMap<T, U> : IFunctionMap<T, U>
{
/// <summary>
/// Should invalidate any caches forcing the underyling function to be called afresh
/// </summary>
void Clear();
}
public interface IFunctionMap<T, U>
{
/// <summary>
/// Mapped values representing the underlying function.
/// </summary>
U this[T index] { get; }
}

How do I create dynamic properties in C#?

I am looking for a way to create a class with a set of static properties. At run time, I want to be able to add other dynamic properties to this object from the database. I'd also like to add sorting and filtering capabilities to these objects.
How do I do this in C#?
You might use a dictionary, say
Dictionary<string,object> properties;
I think in most cases where something similar is done, it's done like this.
In any case, you would not gain anything from creating a "real" property with set and get accessors, since it would be created only at run-time and you would not be using it in your code...
Here is an example, showing a possible implementation of filtering and sorting (no error checking):
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"]);
}
}
}
}
If you need this for data-binding purposes, you can do this with a custom descriptor model... by implementing ICustomTypeDescriptor, TypeDescriptionProvider and/or TypeCoverter, you can create your own PropertyDescriptor instances at runtime. This is what controls like DataGridView, PropertyGrid etc use to display properties.
To bind to lists, you'd need ITypedList and IList; for basic sorting: IBindingList; for filtering and advanced sorting: IBindingListView; for full "new row" support (DataGridView): ICancelAddNew (phew!).
It is a lot of work though. DataTable (although I hate it) is cheap way of doing the same thing. If you don't need data-binding, just use a hashtable ;-p
Here's a simple example - but you can do a lot more...
Use ExpandoObject like the ViewBag in MVC 3.
Create a Hashtable called "Properties" and add your properties to it.
I'm not sure you really want to do what you say you want to do, but it's not for me to reason why!
You cannot add properties to a class after it has been JITed.
The closest you could get would be to dynamically create a subtype with Reflection.Emit and copy the existing fields over, but you'd have to update all references to the the object yourself.
You also wouldn't be able to access those properties at compile time.
Something like:
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>();
}
I don't have VS installed on this machine so let me know if there are any massive bugs (well... other than the massive performance problems, but I didn't write the specification!)
Now you can use it:
Dynamic d = new Dynamic();
d = d.Add("MyProperty", 42);
Console.WriteLine(d.GetType().GetProperty("MyProperty").GetValue(d, null));
You could also use it like a normal property in a language that supports late binding (for example, VB.NET)
I have done exactly this with an ICustomTypeDescriptor interface and a Dictionary.
Implementing ICustomTypeDescriptor for dynamic properties:
I have recently had a requirement to bind a grid view to a record object that could have any number of properties that can be added and removed at runtime. This was to allow a user to add a new column to a result set to enter an additional set of data.
This can be achieved by having each data 'row' as a dictionary with the key being the property name and the value being a string or a class that can store the value of the property for the specified row. Of course having a List of Dictionary objects will not be able to be bound to a grid. This is where the ICustomTypeDescriptor comes in.
By creating a wrapper class for the Dictionary and making it adhere to the ICustomTypeDescriptor interface the behaviour for returning properties for an object can be overridden.
Take a look at the implementation of the data 'row' class below:
/// <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
//---------------------------------------------------------------------------------------------------------------------------
}
Note: In the GetProperties method I Could Cache the PropertyDescriptors once read for performance but as I'm adding and removing columns at runtime I always want them rebuilt
You will also notice in the GetProperties method that the Property Descriptors added for the dictionary entries are of type TestResultPropertyDescriptor. This is a custom Property Descriptor class that manages how properties are set and retrieved. Take a look at the implementation below:
/// <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
//---------------------------------------------------------------------------------------------------------------------------
}
The main properties to look at on this class are GetValue and SetValue. Here you can see the component being casted as a dictionary and the value of the key inside it being Set or retrieved. Its important that the dictionary in this class is the same type in the Row wrapper class otherwise the cast will fail. When the descriptor is created the key (property name) is passed in and is used to query the dictionary to get the correct value.
Taken from my blog at:
ICustomTypeDescriptor Implementation for dynamic properties
You should look into DependencyObjects as used by WPF these follow a similar pattern whereby properties can be assigned at runtime. As mentioned above this ultimately points towards using a hash table.
One other useful thing to have a look at is CSLA.Net. The code is freely available and uses some of the principles\patterns it appears you are after.
Also if you are looking at sorting and filtering I'm guessing you're going to be using some kind of grid. A useful interface to implement is ICustomTypeDescriptor, this lets you effectively override what happens when your object gets reflected on so you can point the reflector to your object's own internal hash table.
As a replacement for some of orsogufo's code, because I recently went with a dictionary for this same problem myself, here is my [] operator:
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);
}
}
}
With this implementation, the setter will add new key-value pairs when you use []= if they do not already exist in the dictionary.
Also, for me properties is an IDictionary and in constructors I initialize it to new SortedDictionary<string, string>().
I'm not sure what your reasons are, and even if you could pull it off somehow with Reflection Emit (I' not sure that you can), it doesn't sound like a good idea. What is probably a better idea is to have some kind of Dictionary and you can wrap access to the dictionary through methods in your class. That way you can store the data from the database in this dictionary, and then retrieve them using those methods.
Why not use an indexer with the property name as a string value passed to the indexer?
Couldn't you just have your class expose a Dictionary object? Instead of "attaching more properties to the object", you could simply insert your data (with some identifier) into the dictionary at run time.
If it is for binding, then you can reference indexers from XAML
Text="{Binding [FullName]}"
Here it is referencing the class indexer with the key "FullName"

Categories

Resources