繁体   English   中英

函数返回一个泛型类型,其值仅在运行时已知

[英]Function returning a generic type whose value is known only at runtime

我需要使用如下通用接口:

public interface IContainer<T>
{
    IEnumerable<IContent<T>> Contents { get; }
}

实现此接口的对象由以下通用方法返回:

IContainer<T> GetContainer<T>(IProperty property);

直到运行时,类型T才是未知的。

使用反射我可以调用GetContainer<T>方法并获得结果。

我的问题是我不知道如何枚举具有Object类型的结果(因此我无法将其IEnumerableIEnumerable )。

我也试过如下铸造,但它不起作用(它说“预期类型”):

var myContainer = genericMethodInfo.Invoke(
                           myService, 
                           new object[] { property })
    as typeof(IContainer<>).MakeGenericType(type);

其中type是运行时类型, myService是公开GetContainer<T>方法的服务, property的类型为IProperty

更新 :在我的博客中查看我的完整解决方案: http//stefanoricciardi.com/2010/02/18/generics-with-type-uknown-at-compile-time/

您的类型T必须由编译器知道,因此这不起作用。 您可以尝试制作非通用版本的界面,如下所示:

public interface IContainer
{
    IEnumerable<IContent> Contents { get; }
}

public interface IContainer<T> : IContainer { ... }

这样你就可以投射并能够使用它了。

typeof(IContainer <>)。MakeGenericType(type)仅在运行时进行求值,而“as”需要在编译时知道类型。

我真正不明白的是这个评论:我的问题是我不知道如何枚举具有Object类型的结果(因此我无法将其强制转换为IEnumerable)。

myContainer可能是一个Object但它肯定可以转换为IEnumerable? 如果它不能那么它就不能枚举。

首先,在转换时你需要一个类型(double,int); typeof接受一个类型参数并返回一个Type类型的类。

     object x = 0.0;
     Type t = typeof(double);
     double y = x as t; //does not compile - t is not a type - it's an instance of type Type
     double y = x as typeof(double); //same as above
     double y = x as double; //compiles - double is a type
     Type z = x as Type; //compiles - Type is a type

其次,这是一些示例代码:

using System;
using System.Collections.Generic;
using System.Collections;
using System.Reflection;
using System.Diagnostics;

namespace TryThis
{
   public interface IContainer<T>
   {
      IEnumerable<IContent<T>> Contents { get; }
   }
   public interface IContent<T>
   { 
      T GetMyContent(); 
   }
   public interface IProperty 
   { }

   public class Content<T> : IContent<T>
   {
      T m_content = default(T);
      public T GetMyContent() { return m_content; }
      public Content(T val) { m_content = val; }
   }

   public class Contents<T> : IEnumerable<IContent<T>>
   {
      List<IContent<T>> m_contents = new List<IContent<T>>();
      IEnumerator<IContent<T>> IEnumerable<IContent<T>>.GetEnumerator() { return m_contents.GetEnumerator(); }
      IEnumerator IEnumerable.GetEnumerator() { return m_contents.GetEnumerator(); }
      public Contents(params T[] contents) { foreach (T item in contents) m_contents.Add(new Content<T>(item)); }
   }

   public class TestGenericContent : IContainer<int>
   {
      public IContainer<int> GetContainer(IProperty property) { return this; }
      public IEnumerable<IContent<int>> Contents { get { return new Contents<int>(1, 2, 3); } }
   }

   public static class TryThisOut
   {
      static void Test2(object o)
      {
         Type t = o.GetType();
         Type tInterface = t.GetInterface("IContainer`1"); //could be null if o does not implement IContainer<T>
         Type tGenericArg = tInterface.GetGenericArguments()[0]; //extracts T from IContainer<T>
         MethodInfo info = t.GetMethod("GetContainer");
         IProperty propArg = null; //null in this example
         object oContainer = info.Invoke(o, new object[] { propArg });

         PropertyInfo prop = tInterface.GetProperty("Contents");
         object oContents = prop.GetGetMethod().Invoke(oContainer, null);
         //oContents is of type IEnumerable<IContent<T>>, which derives from IEnumerable, so we can cast
         IEnumerable enumeratedContents = oContents as IEnumerable;

         MethodInfo getContentItem = typeof(IContent<>).MakeGenericType(tGenericArg).GetMethod("GetMyContent");
         foreach (object item in enumeratedContents)
         {            
            object oContentItem = getContentItem.Invoke(item, null);
            Debug.Print("Item {0} of type {1}", oContentItem, oContentItem.GetType());
            //...
         }
      }

      public static void Test()
      {
         object o = new TestGenericContent();
         Test2(o);
      }
   }
}

如果您正在考虑迁移到动态类型提供的.Net 4。

我假设您的对象只会作为有限数量的类型之一返回,那么为什么不在转换之前测试它们,例如,如果object是thisclass?

对不起,如果我误解了,我无法准确理解你的目标是什么。 你在找这样的东西吗?

var myContainer = typeof(ClassWithGetContainer)
                 .GetMethod("GetContainer")
                 .MakeGenericMethod(runtimeType)
                 .Invoke(InstanceOfClassWithGetContainer, new object[] { property });

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM