1

If I have a class defined like this:

public class className
{
    public object this[string propertyName]
    {
        get { return this.GetType().GetProperty(propertyName).GetValue(this, null); }
        set { this.GetType().GetProperty(propertyName).SetValue(this, value, null); }
    }

    public string Foo{ get; set; }
    public string Bar { get; set; }

I can of course set and get the values like this:

className d = new className();
d["Foo"]="abcd" // set
string s = (string)f["Bar"];

(thanks to Eduardo Cuomo for his answer here)

But what I'd really like to do is something like:

Type target = Type.GetType(DocumentType);

// loop through list of key-value pairs and populate the data class defined in target object Type
foreach (Dictionary<string, string> PQList in LPQReq)
{

foreach (KeyValuePair<string, string> kvp in PQList)
{
    // populate the member in the data class with the value from the MQ String
    target[kvp.Key] = kvp.Value;                                                
    }    

but this wouldn't compile as Cannot apply indexing with [] to an expression of type 'System.Type'

so how could I do that?

I can use dynamic of course, but maybe there is a way to cast my Type to my target Class?

Community
  • 1
  • 1
Our Man in Bananas
  • 5,809
  • 21
  • 91
  • 148
  • 3
    `target` is a class; what's the *instance* of that class on which you would like to set all these properties, though? – Sergey Kalinichenko Aug 20 '15 at 20:00
  • @dasblinkenlight: Well, I have more than a dozen data classes, so I create a type based on the definition given in the string `DocumentType`. This means I can populate all the classes generically without having to specify the properties and members... – Our Man in Bananas Aug 20 '15 at 20:01
  • Whether you get the type or not, you do not have any instance of this object. Even you manage to do this, you will get that the object is not set to a reference of an object – Royal Bg Aug 20 '15 at 20:02
  • @dasblinkenlight: in my question, `DocumentType` would in this case reference `className` – Our Man in Bananas Aug 20 '15 at 20:03
  • 1
    Would defining the [indexer on an interface](https://msdn.microsoft.com/en-us/library/tkyhsw31.aspx) and having all your classes that have this pattern also implement the interface be viable? Then your code would create the object (say via `Activator.CreateInstance(target)`), cast it to the interface, and then you can read/write the properties. – Chris Sinclair Aug 20 '15 at 20:04
  • 1
    Have you tried `className["foo"]` because it would not work to use indexer from static context. You can manage your `target` to be from type `className`, but it WILL NOT BE an instance of `className` – Royal Bg Aug 20 '15 at 20:04
  • @RoyalBg: so is my whole house of cards falling over? How can I instantiate my `target`? Or is that a whole new question? – Our Man in Bananas Aug 20 '15 at 20:05
  • 1
    You can do it via reflection. Take a look at the `Activator` class. I also thing you'd better have a generic method that recieves that instance and apllies indexer to it, if you have dozen of that classes. `public void SomeMethod(T obj) { obj["foo"] = "bar"; }` – Royal Bg Aug 20 '15 at 20:06

2 Answers2

4

You can do it with reflection. Assuming that all possible DocumentTypes have a parameterless constructor, you can do it like this:

// Get the type (this comes from your example)
Type target = Type.GetType(DocumentType);
// Create an instance (that's the important part that was missing)
object instance = Activator.CreateInstance(target);
foreach (Dictionary<string, string> PQList in LPQReq) {
    foreach (KeyValuePair<string, string> kvp in PQList) {
        // This code again comes from your example,
        // except propertyName is kvp.Key and value is kvp.Value
        target.GetProperty(kvp.Key).SetValue(instance, kvp.Value, null);
    }
}
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
3

You need to instantiate the type in order to access the indexer, and you need to cast it to something that has an indexer.

You could define an interface:

public interface IIndexable_String
{
    object this[string index]
    {
        get;
        set;
    }
}

Apply it to your classes:

public class someclass : IIndexable_String

Then instantiate the instance and access the indexer.

Type target = Type.GetType(DocumentType);

// Instantiate
IIndexable_String instance = (IIndexable_String)Activator.CreateInstance(target);
foreach (Dictionary<string, string> PQList in LPQReq)
{
    foreach (KeyValuePair<string, string> kvp in PQList)
    {
        // populate the member in the data class with the value from the MQ String
        instance[kvp.Key] = kvp.Value;                                                
    } 

Of course, if you do it like @dasblinkenlight does, you don't even need the magic getters and setters in the class, nor the interface.

CodeCaster
  • 147,647
  • 23
  • 218
  • 272