使用动态类型调用通用扩展方法

3
我想要执行一个返回T类型对象的扩展方法,但是我希望T类型是基于Header/Detail动态泛型类型而动态决定的。
可能有点啰嗦……
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个回答

6

这必须使用反射完成。

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

请注意,扩展方法是一种语言特性,因此在使用反射时,必须像调用常规静态方法一样调用该方法。
如果类型始终是动态的,则将您的ToObject更改为常规非泛型方法并将Type作为参数传递可能会更容易些。
实际上,您的设计有些问题,因为您似乎需要知道Detail属性后面的对象的实际类型,但这要求该属性已经有一个值,而您的代码正在设置该属性。
我建议您考虑其他处理方式。

我遇到了一个小问题,一直在尝试通过反射来解决它,但是卡住了。returnHeader.Detail为空,无法从中获取“GetType()”。 - Eric James Deiter
这就是我提到的你设计中的问题。你需要有一种方式来传达你想要Detail属性的类型,因为只要它的值是null,你所知道的唯一类型就是IDetail,显然无法实例化。也许你可以在IHeader接口中添加一个Type DetailType { get; }属性,允许实现通知你他们想要使用什么类型? - Sven
不幸的是,我继承了这个项目,而且代码被用在其他程序集中。我通过在创建仓库对象MyRepo<THeader, TDetail>时传递类型来修复它,然后我可以将其强制转换为(TDetail)。 - Eric James Deiter

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接