3

The closest answers I found related to this question didn't really do anything to help solve it, though perhaps I did a poor job searching for it.

Get a new object instance from a Type

Reflection instantiation

Instantiate an object with a runtime-determined type

Now, what I'm trying to solve is:

I want to fully and entirely fill out and initialize an object, where I only have the Type, and this object does not have a constructor, and I don't know what type it is until runtime.

private readonly Dictionary<string, object> exampleDict = new Dictionary<string, string> { { "String", "\"String\"" }, { "Guid", Guid.NewGuid() }, { "Boolean", False }, { "int", 0 }, { "Decimal", 5.004 }, { "Int32", 0 }, { "Float", 10.01 }, { "Double", 0.101 } };
//Essentially a dictionary of what to init properties to
private object PopulateType(Type propertyType)
{
    object o = Activator.CreateInstance(propertyType);
    if(exampleDict.hasKey(propertyType.ToString())) //If it is in the dictionary, init it
        o = exampleDict[propertyType.Name];
    else
        foreach(var property in o.getProperties())//Otherwise look at each of its properties and init them to init the object
            PopulateType(typeof(property));
}

The above isn't what I actually have and I doubt it'd work out of the box (the actual code currently has a slew of different things I tried from SO answers, and it was easier to just rewrite it how I wanted it)

I will also need to worry about arrays (and by extension lists and dictionaries) which'll act a bit differently, but I'm primarily trying to get the main part of the question down.

Thanks in advance for all the help - I'm just hoping this is possible :)

EDIT with more details: To put it another way, say I have the following classes:

public class ClassOne
{
    public string BirthCountry {get; set;}
    public string BirthCity {get; set;}
}
public class ClassTwo
{
    public string FirstName {get; set;}
    public string LastName {get; set;}
    public ClassOne BirthPlace {get; set;}
}

What I want to do is call:

object newObject = PopulateType(typeof(ClassOne))

OR

object newObject = PopulateType(typeof(ClassTwo))

I don't know in advance which one I'll use, and neither has a constructor. I want to be able to set BirthCountry and BirthCity to "String" if it is a ClassOne put into PopulateType, and I want to be able to set FirstName="String", LastName="String" and BirthPlace=new ClassOne { BirthCountry="String", BirthCity="String" } But I want to be able to do this for ANY class that I happen to have (these are just examples).

Edit further

I am able to make the base class from the type. But I haven't been able to hit the properties to set them to anything except null.

EDIT - With the help of Fruity Geek (many thanks friend) I was able to get the program working.

private object PopulateType(Type propertyType)
{
    object o = null;
    if (exampleDict.ContainsKey(propertyType.Name))
        o = exampleDict[propertyType.Name];
    else
    {
        var types = AppDomain.CurrentDomain.GetAssemblies().ToList().SelectMany(s => s.GetTypes()).Where(p => propertyType.IsAssignableFrom(p));
        try{o = Activator.CreateInstance(propertyType);}
        catch{o = Activator.CreateInstance(types.Last());}   
        foreach (PropertyInfo prop in o.GetType().GetProperties())
            try
            {
                prop.SetValue(o, PopulateType(prop.PropertyType), null);
            }
            catch (Exception){}
    }
    return o;
}

Note that the try/catch are to: Prevent exploding if the interface isn't implemented, and to not try to instance dicts/lists/arrays (those still need work)

Community
  • 1
  • 1
K M
  • 55
  • 1
  • 7
  • 1
    So do you want to construct a type (set what members does it have) in runtime? – abatishchev Jan 24 '13 at 02:27
  • I'll edit it with more details. – K M Jan 24 '13 at 02:55
  • 1
    Don't forget that if you don't define any constructors in code, you get an automatic no-argument constructor that you can invoke via reflection. – Carl Raymond Jan 24 '13 at 03:16
  • Good point - I didn't mean that it had no-constructor period, but more that I didn't have a constructor that would set the properties - so I haven't been able to find a way to set those properties – K M Jan 24 '13 at 03:37
  • Can someone explain to me why I was downvoted? If I did something wrong, I'd prefer not to do so again :) – K M Jan 24 '13 at 05:01

1 Answers1

4

You can use reflection to check if a property exists and set it.

PopulateType(Object obj)
{
    //A dictionary of values to set for found properties
    Dictionary<String, Object> defaultValues = new Dictionary<String, Object>();
    defaultValues.Add("BirthPlace", "Amercia");
    for (var defaultValue in defaultValues)
    {
        //Here is an example that just set BirthPlace to a known value Amercia
        PropertyInfo prop = obj.GetType().GetProperty(defaultValue.Key, BindingFlags.Public | BindingFlags.Instance);
        if(null != prop && prop.CanWrite)
        {
            prop.SetValue(obj, defaultValue.Value, null);
        }
    }
}
Fruity Geek
  • 7,351
  • 1
  • 32
  • 41
  • You are casting it to (myClass) - I suppose my edit made it more unclear, but I more meant that I don't actually know what is going in. It COULD be ClassOne, OR ClassTwo, but I don't know and they don't override or inherent from any common source. – K M Jan 24 '13 at 03:34
  • Your question says you want to create an instance without calling a constructor. Are you really just trying to figure out how to set a property on an object using reflection? – Fruity Geek Jan 24 '13 at 03:41
  • In essence, yes - I want to create an instance without calling a constructor (or calling the empty one, it doens't matter) and then populate/create an instance of every property of that object using reflection – K M Jan 24 '13 at 03:58
  • Updated answer. You want to set a property using reflection. – Fruity Geek Jan 24 '13 at 03:59
  • +1. Note that trying to hydrate object via reflection may not necessary create working object in genreal case - consider something like Socket or FileStream - no amount of setting properties will make object that actually useful. – Alexei Levenkov Jan 24 '13 at 04:26
  • Aha, I think this is exactly what I'm looking for - thanks! I'll mark it as the answer if it works out. Thanks! :) – K M Jan 24 '13 at 04:58
  • Okay, that mostly worked. The object is created, the default properties are filled out! I'll mark your answer as correct but I'm wondering if you can help me with one more thing: Can you think of a way to init Lists/Dicts/Arrays if I don't know their type (this could be another question I suppose). These could be lists of custom classes, so I can't just fill up the defaultValues dict with default lists. – K M Jan 24 '13 at 16:15
  • @KM Why aren't you using the built-in deserialization capabilities of .Net? It does all the stuff you are asking about for you. – Fruity Geek Jan 24 '13 at 17:59
  • @FruityGeek - Primarily because I'm not overly familiar with deserialization or reflection. All I need in the end is some way to go from a Type, to a fully instanced version of that Type, with every property initialized and every properties' properties initialized etc. If there is some built in capabilities that do this, great! I'll use those. The part I'm having trouble with is not knowing what Type it will be in advanced, so I don't even have a foundation of classes to work with other than that they will be interfaces composed of eventually strings, guids, ints, etc – K M Jan 24 '13 at 19:17
  • ((Ran out of characters)) - if you have a better method, I'll gladly use it :) – K M Jan 24 '13 at 19:17
  • Did some research - deserialization won't work in this case. I don't know in advance what I'm creating, so I can't create a deserialization string for it. – K M Jan 25 '13 at 18:06
  • What exactly is instructing you to create objects in the first place? – Fruity Geek Jan 25 '13 at 18:41
  • Part of a program is basically: object InstanceType(Type type). I fiddled with it this morning and got it to mostly work with prop.SetValue - I just need to get it to work with dicts/lists/arrays and the entire thing will work perfectly. I'll edit my original question with the code that worked (which was a mild derivative from yours, thanks!) – K M Jan 29 '13 at 17:14