Reputation: 435
I want to create a little testing tool for my program, which fills all properties of a random object (unknown type at compile time). A sample structure:
public class HeadObject
{
public Company Company { get; set; }
public CompanyAddress CompanyAddress { get; set; }
public List<Details> Details{ get; set; }
public ApplicationUser AppUser { get; set; }
}
and e.g the class Company would look like this:
public class Company
{
public string CompanyName{ get; set; }
public string PhoneNumber{ get; set; }
public Address Adress{ get; set; }
public int CompanyNo{ get; set; }
public List<Employee> Employees{ get; set; }
}
its pretty simplified because in each HeadOjbect there are around 30 properties which may contain sub properties or a property can be a list etc.. I need to populate ~30 HeadObjects at runtime. I already tried it with different libraries like GenFu, nBuilder or Bogus.
The last 2 have the problem that I have to fill the properties by myself only the data is generated. GenFu looks like it can only deal with primitive properties like int, string, ... And if you imagine the HeadObject as a root of a tree, then there would be
~ 300 Nodes per tree
Height of a tree: between 1 and 7(!)
~30 Different trees (HeadObjects)
so it would take days to write this all down by myself and maintenance would be a pain.
I appreciate any kind of idea.
Thanks for your replies! How can I initialize the objects? e.g I get the Company property of my head object and then I want to initialize it to be able to fill it. My method (its recursive) starts like this:
private static T FillAllProperties<T>(T masterObject) where T : new()
{
try
{
Type masterType = masterObject.GetType();
T headObject = new T();
......IF primitive Type fill it and return the value
otherwise get Properties into firstProperties.......
foreach (var propertyInfo in firstProperties)
{
var objectInstance = FillAllProperties(propertyInfo.PropertyType);
headObject.GetType().GetProperty($"{propertyInfo.Name}").SetValue(headObject, objectInstance, null);
}
Now I have 2 questions:
I probably need another "construction" for this algorithm, but how..?
Upvotes: 2
Views: 2280
Reputation: 9824
If you do not know the properties at runtime, you will have to use Reflection. But starting with 30 properties, I would probably use it regardless (or look if I made any mistakes in my design). Writing that much manually is just too prone to mistakes.
A alternative might be to have a ISelfRandomizing
interface with a SelfRandomize()
function, so each type input can carry it's own randomization code. And hope people actually provide it.
Something that might be viable for your case: structs by default use reflection for comparison. What would be the equivalent of a base class for them, has reflection based fallback code. You are invited to override it, but if you do not it just "works". You could make a abstract base class that you use for all those classes. That way you only need to write the reflection code once.
As for the actual randomization: Random. A common mistake is creating new instances of Random in a loop. Do not do that. You want to keep a single Random instance around as long as possible, for optimal randomisation. I have no sensible way to transform a Integer return into a string, so the next best non-sensible thing is to create a large random number and call ToString()
on it. That will give you something to put in those spots at least.
Upvotes: 1
Reputation: 4806
You are going to go through deep pain...
Basically the idea is to iterate through the object's properties and randomly fill them.
You can iterate using YourObject.GetType().GetProperties() then using PropertyInfo.PropertyType to know the type.
Then with each Proprety Type you can check whether it is a simple (i.e. int, double...) structure or a more complex object (by using Type.IsPrimitive, Type.IsClass or Type.IsValueType).
If it a class, you recursively call the same method, because it means you have a complex type.
If it is a structure, then maybe you should iterate over the fields instead of the properies ?
If it is a primitive you can set its value using PropertyInfo.SetValue(), but how are you going to randomize anything ? You need to perform a switch on .Net base types then generate a value at random for each type.
By the way, a string is a class, not a primitive, so you will need to make a special case for this one.
Also, List<string>
is a funny one, because it is an Enumerable object. So it is another specific case.
And if you want to have fun, try out a Dictionary, or better, Tuple...
Anyway, there is no simple way to perform this. Your simple testing tool will soon become a nightmare because of all the cases you couldn't even see from far away...
Maybe there is a better option to test your program than filling it with random values that don't have any actual meaning ?
Upvotes: 2