3

I'm trying to execute an extension method that returns and object of type T, but I'm trying to have type T dynamic based on a Header/Detail dynamic generic type.

This maybe a bit verbose...

using System;
using System.Collections.Generic;

namespace Blah
{
    public interface IHeader
    {
        string Name { get; set; }
        IDetail Detail { get; set; }
    }

    public interface IDetail
    {
        //Nothing the 'Real' implementation of this 
        //interface will have it's own properties.
    }

    public class GenericHeader : IHeader
    {
        public string Name { get; set; }
        public IDetail Detail { get; set; }
    }

    public class RealHeader : GenericHeader
    {
        public new RealDetail Detail
        {
            get { return (RealDetail) base.Detail; }
            set { base.Detail = value; }
        }
    }

    public class RealDetail : IDetail
    {
        public string ThisImportantOnlyToRealDetail { get; set; }
    }

    public static class ExtensionHelpers
    {
        public static T ToObject<T>(this IDictionary<string, string> reader) where T : new()
        {
            //This maps the dictionary to Key Value Pairs of the Object's properties
            //it then will return a object filled with the values
            return new T();
        }
    }

    public class MyRepo<THeader> where THeader : class, IHeader, new()
    {
        public THeader GetById(int ID)
        {
            THeader returnHeader = new THeader();
            //Process to fill Header

            var dictDetail = new Dictionary<string, string>();
            //Process to fill Detail Dictionary

            //Use extension method to create an Object 
            //based on Key Value Pairs from Dictionary
            // !!!!!!!!!!!!!!!! This Is The Problem !!!!!!!!!!!!!!!!
            // Can't use typeof for returnHeader.Detail, reflection?
            returnHeader.Detail = dictDetail.ToObject<typeof(returnHeader.Detail)>();

            return returnHeader;
        }
    }

    public class Worker
    {
        public void DoWork()
        {
            var myRealRepo = new MyRepo<RealHeader>();
            var myRealHeader = myRealRepo.GetById(123);

            Console.WriteLine(myRealHeader.Detail.ThisImportantOnlyToRealDetail);
        }
    }
}

1 Answers1

6

This has to be done using reflection.

typeof(ExtensionHelpers)
    .GetMethod("ToObject", BindingFlags.Static | BindingFlags.Public)
    .MakeGenericMethod(returnHeader.Detail.GetType())
    .Invoke(null, new object[] { dictDetail });

Note that since extension methods are a language feature, you have to call the method like a regular static method when using reflection.

If the type is always dynamic, it's probably a lote easier to change your ToObject to be a regular non-generic method that takes a Type as a parameter.


Your design is a bit problematic actually, as you seem to need to know the actual type of the object behind the Detail property, but that requires that property to already have a value, yet your code is setting that property.

I suggest you think about alternative ways to deal with this.

Sven
  • 21,903
  • 4
  • 56
  • 63
  • I'm having a slight problem and been trying to go over the reflection to see if i can fix it but hit a brick wall. The returnHeader.Detail is null and it can't get the 'GetType()' from it. – Eric James Deiter Aug 26 '11 at 21:17
  • That's the problem with your design I mentioned. You need to have a way to communicate the type you want the `Detail` property to be, because as long as its value is `null` the only type you know about is `IDetail`, which obviously can't be instantiated. Perhaps you could add a `Type DetailType { get; }` property to the `IHeader` interface that allows implementations to inform you of what type they want to use? – Sven Aug 27 '11 at 03:33
  • Unfortunately I inherited this project and the code is used in other assemblies. I fixed it by passing in the type during creation of the repo object MyRepo, then I'm able to cast it to (TDetail). – Eric James Deiter Aug 29 '11 at 14:48