Add properties to class dynamically C# - c#

I want to add properties to a class dynamically and set values to them. Could someone point me in the right direction to some tutorials or articles or even better provide an example.
I have a base class which is called in a foreach loop. Inside this class I need to add up to 30 properties and set values to them.
This is the method that calls the class.
foreach (Class name in this.list)
{
ClassBeingCalled class = new ClassBeingCalled (name);
class.Populate();
this.newlist.Add(class);
}
Now inside the class being called, I need to create the 30 or so properties on the fly, which will be set in the "Populate" method of that class.
Like so...
foreach (PropertyToAssign count2 in listofproperties)
{
string name = "_nameofproperty" + count2.name
base.GetType().GetField(name, BindingFlags.NonPublic |
BindingFlags.Instance).SetValue(this, count2);
}

There are a few ways to approach this.
a) You use reflection to generate a class at runtime with whatever you need. You can always derive this generated class from a base class that contains Populate but I don't see the need.
b) If you're using C# 4.0+, you could use ExpandoObject, which allows you to set whatever properties you want for your needs. Note that these are not added as properties per se, as it uses the DLR which is all runtime-based. Depending on your needs, this may be fine; this is pretty much the same as approach c, but using the DLR.
c) You could use a backing dictionary and use an indexer, like so:
private Dictionary<string, object> _internalData = new Dictionary<string, object>();
public T this[string propName]
{
get {
return _internalData[propName];
}
set {
_internalData[propName] = value;
}
}
By using approach 3, you're actually indexing based on strings which is probably better based on your requirements... As you can do something along the lines of this:
foreach (PropertyToAssign count2 in listofproperties)
{
string name = "_nameofproperty" + count2.name;
this[name] = count2.value;
}
At the end of the day, it's probably best if you explain the problem you're trying to solve, as there may be a better way to approach it entirely.

It is not possible to add dynamic properties to a compiled class on the fly. You can only add dynamic properties to classes while building the class itself on the fly using Reflection.Emit
Your other option could be using a Dictionary or ExpandoObject (which is actually a dictionary). But for this option, you cannot access your dynamic properties using reflection.

Related

Is there a way to construct a deeply nested Dictionary with nice syntax and IntelliSense support?

I am trying to create an object that contains the parsed register values of a robot. I have an ASCII text file that contains representations of the variables and arrays. However, I am struggling to think of an easy way to use the deeply nested values. Ideally, the syntax to use the deeply nested objects would be something like Registers["PositionRegister"]["CurrentPosition"]["X_Coordinate"] and the dictionary would be something like this:
(There was a JSON representation here of what I wanted the dictionary to look like, but people kept suggesting JSON serialization...)
However, since I am parsing the file and constructing the object at the same time, I don't know how deep the nesting will go until the parsing is complete.
I've tried using a simple Register class that can contain a dictionary of sub-Registers:
public class Register
{
public Dictionary<string, Register>? subRegisters;
public string name { get; set; }
public string value { get; set; }
}
However, the usage turns into super unintuitive syntax like motionRegister.subRegisters["Register1"].subRegisters["SubRegister1"].subRegisters["Value1"].Value and I'm duplicating information by using the name as the key.
I've also tried using only nested Dictionaries like:
public Dictionary<string, object> CreateRegisters()
{
Dictionary<string, object> TopLevelRegisters = new();
Dictionary<string, object> SubRegisters = new();
Dictionary<string, object> SubSubRegisters = new();
SubSubRegisters.Add("SubSubElement1", "5678");
SubRegisters.Add("SubElement1", "1234");
SubRegisters.Add("SubElement2", SubSubRegisters);
SubRegisters.Add("SubElement3", "1357");
TopLevelRegisters.Add("Register1", SubRegisters);
return TopLevelRegisters;
}
but they end up being super difficult to use since IntelliSense doesn't know what the object will be until runtime. I would return it as another Dictionary, but I don't know how deep the nesting will have to go.
I'm sure that there's a simple solution, but I can't seem to find it.
The closest thing I could come up with is to
Subclass Dictionary<>, and define the subclass in terms of itself (allows for arbitrary depth, and prevents the need for what you call the "unintuitive syntax" of a sub-dictionary manifesting in the path)
Hide the existing indexer with a new implementation (allows for auto-construction of a new level)
Provide a Value property for storing the value of the leaf node.
Provide a ToString() that returns Value (allows for the elimination of .Value from the syntax in certain cases, such as concatenation of strings, WriteLine, etc.)
NOTE: A Name property is dropped altogether because the name can be determined based on the dictionary key.
This code will look something like this
public class RecursiveDictionary : Dictionary<string, RecursiveDictionary>
{
public string? Value { get; set; }
public override string? ToString() => Value;
public new RecursiveDictionary this[string key]
{
get
{
if (!TryGetValue(key, out var subDictionary))
base[key] = subDictionary = new RecursiveDictionary();
return subDictionary;
}
set => base[key] = value;
}
}
During parsing, you only have to output each path to a terminal Value or if you keep track of where you're at in the parsing, simply set the Value of the current (sub)dictionary. (Side note, it doesn't matter how you build it or whether the source is proprietary (your case), JSON, or some other format).
Here's an example construction:
var rd = new RecursiveDictionary();
rd["x"].Value = "Hi!";
rd["x"]["y"].Value = "VALUE";
rd["a"]["b"]["c"]["d"].Value = "VALUETWO";
Notice, I didn't have to allocate RecursiveDictionary for every level; this is because the get portion of the indexer does that for me.
From the static Intellisense (i.e. while program is not running), you can hover over rd and see it is a RecursiveDictionary,
hover over Value and see that it is a string,
and hover over one of the ] or [ and see that it is an indexer on the dictionary:
Now for the dynamic (runtime under debugger) I'm not going to show all the code for various accesses or the Intellisense for it, but I can emulate both in a watch window. What you see in the watch window below could just as easily been lines of Console.WriteLine(...) with you hovering over the various locations. So imagine these examples:
CAVEAT: The ToString() might give you some unexpected results depending on the situation. Are you concatenating strings, are you viewing in the debugger, are you using in a WriteLine(), are you passing a sub-dictionary to another method, etc. If that becomes problematic, then go for a slightly less terse syntax that requires you to always get the value explicitly via the Value property.

C#, Generics, Type and NHibernate

I'm learning the power of generics in C# in conjunction with NHibernate. I'd like to attempt the following in the pasted code.
In an attempt to do some post processing of N number of NHibernate objects I worked on a utility method leveraging generics to make it applicable to all NHibernate mapping classes we use now, or in the future. It works but I need to hard code each call for each mapping class. This is a pain and will need continuing updating as our schema and mappings change over time.
I do have an ever up-to-date list of all mapping classes by string name through the NHibernate mappings I generate on the fly. If there was a way to use this list of string names to call my generics based method, I'd be super happy.
Can anyone tell me if this is possible? Do I need to find another route?
Thanks so much in advance!!!
public static void ProcessSomeItems()
{
// *************************************************************
// As of now I have to list all classes as such to be processed
// It works but I have to update manually when new mapping classes are created
// *************************************************************
NHibDoSomethingUtil<AspnetMembership>();
NHibDoSomethingUtil<AspnetProfile>();
NHibDoSomethingUtil<AspnetRole>();
NHibDoSomethingUtil<AspnetUser>();
// and so forth...
// I have a up-to-date list of all mappings from "HbmMapping" and can get a list of all in the
// list form as below
List<string> mappingNames = new List<string>();
foreach (string mappingName in mappingNames)
{
Type theType = Type.GetType(mappingName);
// I know I'm getting Types and Generics classes and so forth all jumbled but
// how in the heck would I do something like the below?
NHibDoSomethingUtil<theType>(); // Obviously doesn't compile ;-)
}
}
// Generic method
public static void NHibDoSomethingUtil<T>() where T : class
{
using (ISession session = sourceDBSessionFactory.OpenSession())
{
foreach (dynamic item in new List<T>(session.QueryOver<T>().List()))
{
// Process item;
}
}
}
ecsousa gave great input and I was able to accomplish what I needed with something like the following.
foreach (HbmClass mappingClass in mapping.Items)
{
Console.WriteLine(" -- Discovered Mapping: " + mappingClass.Name);
Type mappingClassType = Type.GetType(mappingClass.Name);
var genericMethod = typeof(Migration).GetMethod("NHibDoSomethingUtil");
var method = genericMethod.MakeGenericMethod(mappingClassType);
method.Invoke(null, null);
}
You will need to use Reflection in order to accomplish this. Instead of directly calling NHibDoSomethingUtil, try this:
var genericMethod = typeof(TheClassName).GetMethod("NHibDoSomethingUtil");
var method = genericMethod.MakeGenericMethod(theType);
method.Invoke(null, null);
Note that you have to replace TheClassName by the class containing both methods.
Keep in mind the this kind of code is slow, and you should use it very carefully.

Looping through class with multiple ObservableCollection<T>

I have a class:
public class ClassA
{
string Field1;
int Field2;
ObservableCollection<ClassB> col1;
ObservableCollection<ClassC> col2;
ObservableCollection<ClassD> col3;
ObservableCollection<ClassE> col4;
ObservableCollection<ClassF> col5;
// ...
}
In my application, when the user hits save I need to loop through this class and perform actions with each of its members.
I can use reflection to go through the normal fields, but not sure how to:
get each of the collections
identify what type it holds
loop its items and cast each collection item to its Type so can work with it.
Background:
I have multiple datagrids on a wpf app, with the class structure above being the viewModel datacontext.
When user hits save I need to do save each item in the viewmodel to its own relevant table in the database via stored procs.
Once I have the a collection I need to test IF "is a class b" or IF "is a class C" and then use the particular method on it, with that method receiving the actual Type.
Would be much cleaner than hardcoding the class.
Reflection can be used to interrogate a type hierarchy at run-time, however this quickly becomes painful if you're trying to do so with generics, more so if you think you can access the type at runtime as you would at compile-time.
The code below demonstrates the principal behind (1) and (2) in your question. (3) is harder to answer without more detail on how you wish to use the generic types contained in each ObservableCollection.
var instance = new ClassA();
var fields = instance.GetType().GetFields(BindingFlags.Instance | BindingFlags.NonPublic);
foreach(var field in fields)
{
Console.WriteLine("Field name: {0}. Type:{1} IsGeneric:{2}", field.Name, field.FieldType.Name, field.FieldType.IsGenericType);
if(field.FieldType.IsGenericType)
{
var genericArgs = field.FieldType.GenericTypeArguments;
foreach(var genericArg in genericArgs)
{
Console.WriteLine("\tGenericArg Type:{0}", genericArg.Name);
}
}
}
Live demo: http://rextester.com/AJVS85556

Add property to a list?

I have a list with a lot of objects List<MyObjects> - Im iterating through this list and reading the objects. Thats all fine. I just relized now, what it would be awesome if I could add 1 more special value to this List - not an Object, just 1 value of something (a string).
I could now create a class like
class Needless
{
public List<MyObjects> MyList { get; set; }
public string MyValue { get; set; }
}
but Im trying to avoid that. I just really need 1 string with an input every List<MyObjects> Any ideas?
Tuple<string, List<MyObject>> is an option. However, if you are going to use this pairing a lot, I would advise creating a custom class for it to be more explicit - either like you have done, or by deriving List<MyObject> and adding the string as a property.
If you are working "in scope" you could always make anonymous types:
var t = new { TheString = "", TheList = new List<MyObject>() };
var list = t.TheList;
var s = t.TheString;
But this only really has benefit in the scope of a method. The compiler can give IntelliSense for this and it is strongly-typed at compile time.
Or if you really want to go all out, use ExpandoObject from System.Dynamic:
var expando = new ExpandoObject();
expando.List = new List<MyObject>();
expando.TheString = "";
This is typed in-line without any IntelliSense support, and will invoke the DLR. ExpandoObject simply uses an IDictionary<string, object> under the hood, so...
var dict = (IDictionary<string, object>)expando;
...is valid.
The last option is a little tongue-in-cheek. It'll work, but the development experience against it isn't ideal compared to other options. That said, we use ExpandoObject in our test code, but I can't remember why. One can only hope the reasoning was sound, but it was likely a developer getting giddy with new toys...
you can inherit the List and simply add your property, it's a bit cleaner than composite the List inside another class
You could extend a List implementation with your Needless class. That way you can still treat your list as a list.

Simple way to transpose data before passing to functions?

This is one of the hardest questions I've ever had to title here on SO. :) Although the title might not make sense, hopefully the question itself will.
Let's say I have a data structure like a Dictionary<string, List<double>>, and that I have functions that then take List<double>s as a parameter:
Dictionary<string, List<double>> candy_positions = new Dictionary<string, List<double>>();
candy_positions.Add( "Godiva", new List<double> { 1.0, 2.0, 4.0 });
EatCandy( candy_positions["Godiva"]);
...
But now I have decided that I don't want to do it this way. I want to replace my Dictionary with a List<CandyPositions>, where CandyPositions looks something like this:
public class CandyPositions
{
public double Sees;
public double Godiva;
public double Lindt;
}
However, I really would like to leave EatCandy() alone. Obviously, the problem is now that my data doesn't lend itself to be passed directly into the method. Instead, I have to do something lame like:
List<CandyPositions> candy_positions = new List<CandyPositions>();
...
var positions = from x in candy_positions select x.Godiva;
EatCandy( positions.ToList());
every time I want to call the method. I'd prefer to be able to do this in a more simple way, like:
EatCandy( candy_positions.GetPositionsFor( "Godiva"));
where the parameter "Godiva" matches the property name in the CandyPositions class.
After writing this question, I've realized that it isn't really about transposing data -- that part of it can be handled by writing an extension method. The part I don't know how to do is to pass in a property name, so that the extension method can take this and associate it with a class's property. I don't want to pass in a string, either, mainly because this will open the door for all sorts of runtime errors. I know how to make this work by passing "Godiva" to my extension method. What I really want to pass in is something akin to CandyPositions.Godiva instead.
This question is probably a little confusing, so in summary, I would accept the best of two types of answers:
Is there a better way to deal with transposing data, than to use an extension method + some way of accessing a property name?
Is there a way to specify the property that I want my extension method to retrieve, other than by a string?
My current extension method looks like this:
public static List<double> GetPositions( this List<CandyPositions> positions, string candy_name)
{
return (from x in positions select x.GetType().GetProperty(candy_name).GetValue(x, null)).Cast<double>().ToList();
}
Well, you could use:
public static List<double> GetPositions(this List<CandyPositions> positions,
Func<CandyPositions, double> projection)
{
return positions.Select(projection).ToList();
}
and call it with:
EatCandy(candyPositions.GetPositions(x => x.Godiva));
On the other hand, if you can change EatCandy to accept an IEnumerable<double> instead, you don't need the extra method - you can just use:
EatCandy(candyPositions.Select(x => x.Godiva));
without writing an extra method at all.
EDIT: If you need to iterate over two sequences at once, there are two options:
If you're using .NET 4, you can use the Zip extension method.
Otherwise, you can basically write your own:
using (var iterator1 = sequence1.GetEnumerator())
using (var iterator2 = sequence2.GetEnumerator())
{
while (iterator1.MoveNext() && iterator2.MoveNext())
{
var value1 = iterator1.Current;
var value2 = iterator2.Current;
// Use the values here
}
}

Categories