Apply hashtable to object properties? - c#

After an extensive search, I ask here: is there a way to "apply" a hashtable to object properties? For example, if I have a class:
public class MyClass
{
public string PropertyOne {get;set;}
public int PropertyTwo {get;set;}
}
Now, if I have a Hashtable of:
var table = new Hashtable {
{ "PropertyOne", "My string"},
{ "PropertyTwo", 4 }
};
Can I plug the table into an instance of the class so that Object.PropertyOne becomes "My string", etc, without having to parse it myself?

What you are referring to is often referred to as a mixture between "auto-conversion" and "de-serialization". In this specific case it is most easily achieved via non-recursive reflection.
MyClass mine = new MyClass();
table.Cast<DictionaryEntry>()
.ToList()
.ForEach((entry) => {
var field = mine.GetType().getProperty((string)entry.Key);
field.SetValue(mine, entry.Value);
});

Related

How can I use a dynamic to find out when a property is used?

I would like to find out which of the properties in a source input object, a method has used. After executing the method I need to store in a database which of the properties was used.
The input could be any class with simple types, like this:
public class MyData : IMyData
{
public string A { get; set; }
public int B { get; set; }
public decimal C { get; set; }
}
I thought it could be done using an interface as input to the method, so I can replace the original object with a more advanced object, which stores usage of properties
public interface IMyData
{
string A { get; }
int B { get; }
decimal C { get; }
}
I can then
Create a dynamic object with the same properties
Use ImpromptuInterface to simulate the dynamic object implements my interface
Call my method with this dynamic interface
private static void Main()
{
var data = new MyData { A = "Test", B = 3, C = new decimal(1.2) };
IDictionary<string, object> replacementObject = new ExpandoObject();
replacementObject.Add("FieldsUsed", new List<string>());
foreach (var property in data.GetType().GetProperties())
replacementObject.Add(property.Name, property.GetValue(data));
var replacementInterface = replacementObject.ActLike<IMyData>();
DoStuff(replacementInterface);
Console.WriteLine($"The method used these fields {string.Join(", ", (List<string>)replacementObject["FieldsUsed"])}");
}
private static void DoStuff(IMyData source)
{
Console.WriteLine($"A is {source.A}");
if (source.B > 5)
Console.WriteLine($"C is {source.C}");
}
In the above example I would like to store that fields A and B have been used.
Only I am stuck at how I should store when a property is used by my DoStuff method.
You can write a wrapper like this:
public class ClassWrapper<T>: DynamicObject where T:class
{
private readonly T _obj;
private readonly List<string> _fieldsUsed=new List<string>();
public ClassWrapper(T obj)
{
_obj = obj;
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
PropertyInfo propertyInfo = _obj.GetType().GetProperty(binder.Name);
_fieldsUsed.Add(binder.Name);
result = propertyInfo.GetValue(_obj);
return true;
}
public List<string> GetFieldsUsed() => _fieldsUsed;
public T GetWrapper()
{
return this.ActLike<T>();
}
}
and use it like
var data = new MyData { A = "Test", B = 3, C = new decimal(1.2) };
var mc=new ClassWrapper<IMyData>(data);
IMyData wrapped = mc.GetWrapper();
DoStuff(wrapped);
Console.WriteLine($"The method used these fields {string.Join(", ", (List<string>)mc.GetFieldsUsed())}");
If you want to know when a property is used, a Interface like INotifyPropertyChanged can do that for you at runtime. The exampel is only about notification for writes (that actually changed a value), but it would be trivial to expand it to reads and writes. It is not a perfect thing of course, as different executions might follow different code paths that use different properties.
If a function takes a specific type as input, you have to asume that all properties may be relevant. This is especially true for abstract types and interfaces - often the interface exists for this function. If it is one of those two, you can also always provide your own implementation of those Interfaces and Abstract class.
I can not shake the feeling that this is a XY problem.

Convert class object to class index

Class Person {
int Id
string Name
string Address
// etc
}
instead of accessing it like Person.Id, Person.Name, Person.Address. I want to access it via index just like Person['Id'], Person['Name']. Is there any codegen or linq conversion for this.
You can use Json.NET's JObject class
Person p = new Person() { Id = 1, Address = "A", Name = "B" };
var obj = JObject.FromObject(p);
Console.WriteLine(obj["Id"]); //1
This is a pure C# implementation:
class Program
{
static void Main(string[] args)
{
Person person = new Person
{
Id = 1,
Name = "test",
Address = "tost"
};
Console.WriteLine(person["Id"]);
person["Id"] = 5;
Console.WriteLine(person["Id"]);
}
}
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public object this[string propertyName]
{
get
{
return this.GetType().GetProperty(propertyName).GetValue(this);
}
set
{
this.GetType().GetProperty(propertyName).SetValue(this, value);
}
}
}
Output:
1
5
Important note:
I would never recommend to use this in a production environment, if you want to use an handly implemented system, atleast you should handle types and properties extractions to avoid consuming more memory than needed and exceeding overheads.
Using reflection and indexers:
public class ExampleClass{
public object this[string name]
{
get
{
var properties = typeof(ExampleClass)
.GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (var property in properties)
{
if (property.Name == name && property.CanRead)
return property.GetValue(this, null);
}
throw new ArgumentException("Can't find property");
}
set {
return;
}
}
}
An indexer won't make data comparison any easier. I suspect the real question is how to handle data in C# the same way Python's DataFrames work. ADO.NET provides the DataTable class since .NET 1.0. It's meant more for database processing than data analysis, altough it does support operations like searching, merging and diffing.
For data anlysis, the new Microsoft.Data.Analysis package provides the DataFrame class.
That said, to read properties by name, you'll have to use Reflection, an expensive operation. One way to make this cheaper is to cache type and property descriptors. Instead of writing the code yourself though, you can use Marc Gravel's FastMember library that does just that. With this, you can create a TypeAccessor or ObjectAccessor type and read properties by name, eg :
var wrapped = ObjectAccessor.Create(obj);
string propName = // something known only at runtime
Console.WriteLine(wrapped[propName]);
If you want to read from multiple objects, you'll need a TypeAccessor :
var accessor = TypeAccessor.Create(type);
string propName = // something known only at runtime
while( /* some loop of data */ )
{
accessor[obj, propName] = rowValue;
}
The library isn't that big. If you aren't allowed to use NuGet packages, you could copy the code into your project.

C# Typesafe dictionary where value depends on Key? IDictionary<Key<TValue>,TValue>?

I don't know the correct name for this data structure (Is it a Homogeneous map?), but basically I'm trying to get something like.
SmartDict dict = new SmartDict();
Key<string> NameKey = new Key<string>("nameID"); // Should this be a generated GUID for serialization that must be registered?
Key<int> HealthKey = new Key<int>("healthID"); //Should this be a generated GUID for serialization that must be registered?
dict[NameKey] = "Ryan";
dict[HealthKey] = 20;
String name = dict[NameKey]; //name is now Ryan
int health = dict[HealthKey];
Say this is defined on a Base class of some instance of a data class that isn't easily customized for each use.
By having a SmartDict attached to the base class, you can then add additional data to the class (and in the future serialize it as a blob) and have it data driven what types and additional data would need to be attached (as long as they too were serialize-able).
class BaseEntity {
public SmartDict dict = new SmartDict();
Key<string> NameKey = new Key<string>("name");
public void Initialize(){
dict[NameKey] = "Ryan";
}
}
class HealthSystem {
Key<int> Health = new Key<Health>();
public void InitHealth(BaseEntity entity){
entity.dict[Health] = 20;
}
public void DamageEntity(BaseEntity entity, int damage){
entity.dict[Health] = entity.dict[Health] - damage];
}
}
So getting the value from the SmartDict revolves around whether you have access to the key object or not. Useful for user authorizations, or making sure people don't mess with the data from contexts where they should be using a facade.
You could use a dictionary of objects, and just rely on remembering what type you put in, but I was trying to make something that would have less potential for mistake, and preferrably serializeable with WCF (But I'm assuming that's a different problem, that's going to required registering compatible types ahead of time etc, and using GUID's in order to match keys after deserializing).
I've been introduced to the ConditionalWeakTable, but that also has Weak references that might not always be wanted considering I want to be able to serialize this.
My first attempt without really understanding what was going wrong with my generics.
class HMap<K> where K : Key<?>
{
ConditionalWeakTable<K, object> data = new ConditionalWeakTable<K, object>();
public T this[Key<T> index]
{
get
{
T ret;
var success = data.TryGetValue(index, out ret);
if (!success) throw new KeyNotFoundException("Key not found: " + index);
return ret;
}
set
{
data.Add(index, value);
}
}
}
It's impossible to achieve what you want with an indexer (as you can't have a generic indexer in .NET), but if you're willing to use generic methods to interact with your SmartDict instead, you can achieve a similar-looking API with minimal effort:
SmartDict dict = new SmartDict();
Key<string> nameKey = new Key<string>("name");
Key<int> idKey = new Key<int>("id");
dict.Set(nameKey, "Ryan");
dict.Set(idKey, 123);
string name = dict.Get(nameKey); // name is now "Ryan".
int id = dict.Get(idKey); // id is now 123.
SmartDict implementation:
internal interface IKey
{
string Name { get; }
}
public sealed class Key<T> : IKey
{
public string Name { get; }
public Key(string name)
{
Name = name;
}
}
public sealed class SmartDict
{
private readonly Dictionary<IKey, object> Values = new Dictionary<IKey, object>();
public T Get<T>(Key<T> key)
{
if (Values.TryGetValue(key, out object value)) {
return (T)value;
}
throw new KeyNotFoundException($"'{key.Name}' not found.");
}
public void Set<T>(Key<T> key, T value)
{
Values[key] = value;
}
}
This is not a very efficient data structure due to the fact that all values are ultimately stored as object, potentially leading to boxing - something you can work around later if performance becomes an issue.
Perhaps you should not depend on the type of object but use a (big) enum to define your types in. Then you can use a Dictionary to store it.
public enum types{
Name,
Health
}
Then you can use:
Dictionary<types, string>
to manage your data

Convert http post variables to an anonymous type

I have a ashx page setup to handle incoming http posts from a service.
And I'd like to know if there's a better way to populate my anonymous type rather than doing it manually. for example.
public class myclass
{
[key]
public int ID { get; set; }
public int field1 { get; set; }
public int field2 { get; set; }
}
then on my ashx page
myclass mc = new myclass();
mc.field1 = context.Request.Form[field1];
mc.field2 = context.Request.Form[field2];
isn't there just a way to cast or convert it to my type?
myclass mc = new myclass();
mc = context.Request.Form;
If by "better" you mean a one liner where performance is not your number one concern, sure you can do this in Reflection by filtering out potential properties based on the keys in your request context.
mc.GetType().GetProperties()
.Where (x => context.Request.Form.AllKeys.Contains(x.Name)).ToList()
.ForEach(x =>
x.SetValue(mc, Convert.ChangeType(context.Request.Form[x.Name], x.PropertyType)));
That said, is this resilient to null checking / type checking? Nope. Is it performant? Not at all. Is it readable? I confused myself three times just writing it. So while it is possible to do something like this, that doesn't mean it's better. Sometimes pulling out each property manually is the best way to do it.
Also, You can use this extension methods. (I didn't implement null checks or type checks)
public static class ObjectExtensions
{
public static void SetValue(this object self, string name, object value)
{
PropertyInfo propertyInfo = self.GetType().GetProperty(name);
propertyInfo.SetValue(self, Convert.ChangeType(value, propertyInfo.PropertyType), null);
}
public static void SetValues(this object self, NameValueCollection nameValues) {
foreach (var item in nameValues.AllKeys)
{
SetValue(self, item, nameValues[item]);
}
}
}
This way:
myclass mc = new myclass();
mc.SetValues(Request.Form);

Return Properties That Are The Same From Typed Collection

I have a an object called FooObject:
public class FooObject
{
public string Test1 {get; set;}
public List<FooSubObject> SubTest1 {get; set;}
}
For later in the example, I also have a DifferenceFooObject:
public class DifferenceFooObject
{
public string SharedTest1 { get; set; }
public List<FooSubObject> SubTest1 {get; set;}
}
For later in the example, I also have a FooSubObject. FooObject has a property SubTest1 that contains a typed collection of this type:
public class FooSubObject
{
public string Test2 { get; set; }
}
I have a method that accepts a typed collection of FooObject. In this method, I need to calculate if any of the properties between the FooObjects within the typed collection parameter, have equal properties.
public DifferenceFooObject RunPropComparison(List<FooObject> foos)
{
DifferenceFooObject difference = new DifferencFooObject();
FooObject forComparison = foos.FirstOrDefault();
IEnumerable<FooObject> intersectCollection = foos.Skip(1);
// maybe do this using the first to compare the rest? No clue
}
I do not know the most efficient way to complete the above method. It is further complicated, at least IMHO, that the calculation has to take into account the properties of objects in collections that are a property of FooObject (looping through the properties of FooSubObject).
Here is the requested in/out:
List<FooObject> foos = new List<FooObject>();
FooObject obj = new FooObject();
obj.Test1= "Test1";
obj.SubTest1 = new List<FooSubObject>();
FooSubObject obj2 = new FooSubObject();
obj2.Test2 = "Test2";
obj.SubTest1.Add(obj2);
FooObject obj3 = new FooObject();
obj3.Test1= "Test1";
obj3.SubTest1 = new List<FooSubObject>();
FooSubObject obj4 = new FooSubObject();
obj4.Test2 = "Test3";
obj3.SubTest1.Add(obj2);
That's what would go in, ideally it would return that Test1 is the same across the board.
Best as I can tell, this is what you're looking for:
public IList<DifferenceFooObject> RunPropComparison(List<FooObject> foos)
{
var differences = new List<DifferenceFooObject>();
foreach (var group in foos.GroupBy(x => x.Test1))
{
var difference = new DifferenceFooObject();
difference.SharedTest1 = group.Key;
difference.SubTest1 = group.SelectMany(x => x.SubTest1).ToList();
differences.Add(difference);
}
return differences;
}
Or if you add the following constructor:
public DifferenceFooObject(string sharedTest1, IEnumerable<FooSubObject> subTest1)
{
this.SharedTest1 = sharedTest1;
this.SubTest1 = subTest1.ToList();
}
Then you can make this code shorter:
public IList<DifferenceFooObject> RunPropComparison(List<FooObject> foos)
{
return foos.GroupBy(x => x.Test1)
.Select(g => new DifferenceFooObject(g.Key, g.SelectMany(x => x.SubTest1)))
.ToList();
}
I don't think there is an especially efficient way of doing this. You will need to rely heavily on Reflection using the getProperties method to get at the values of the object properties...
You could look into using FasterFlect (http://fasterflect.codeplex.com/) which has better performance over standard .Net reflection...
Check out this library. It compares two objects and tells you the different properties http://comparenetobjects.codeplex.com/documentation

Categories

Resources