我需要使用如下通用界面:
public interface IContainer<T>
{
IEnumerable<IContent<T>> Contents { get; }
}
实现此接口的对象由以下通用方法返回:
IContainer<T> GetContainer<T>(IProperty property);
在运行时之前,类型T
是未知的。
使用反射我可以调用GetContainer<T>
方法并获得结果。
我的问题是我不知道如何枚举类型为Object
的结果(因此我无法将其强制转换为IEnumerable
)。
我也尝试过如下投射,但它不起作用(它说“预期类型”):
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/
答案 0 :(得分:1)
您的类型T必须由编译器知道,因此这不起作用。您可以尝试制作非通用版本的界面,如下所示:
public interface IContainer
{
IEnumerable<IContent> Contents { get; }
}
public interface IContainer<T> : IContainer { ... }
通过这种方式你可以投射并能够使用它。
答案 1 :(得分:1)
typeof(IContainer&lt;&gt;)。MakeGenericType(type)仅在运行时评估,而“as”需要在编译时知道类型。
我真正不理解的是这个评论:我的问题是我不知道如何枚举具有Object类型的结果(因此我无法将其强制转换为IEnumerable)。
myContainer可能是一个Object,但它肯定可以转换为IEnumerable?如果不能,则无法枚举。
答案 2 :(得分:1)
首先,在施法时你需要一个类型(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);
}
}
}
答案 3 :(得分:0)
如果您打算转移到{4}}类型提供的.Net 4。
答案 4 :(得分:0)
我假设你的对象只会作为有限数量的类型之一返回,所以为什么不在测试之前测试它们,例如如果object是thisclass?
答案 5 :(得分:0)
对不起,如果我误解了,我无法准确理解你的目标是什么。你在找这样的东西吗?
var myContainer = typeof(ClassWithGetContainer)
.GetMethod("GetContainer")
.MakeGenericMethod(runtimeType)
.Invoke(InstanceOfClassWithGetContainer, new object[] { property });