我正在尝试制作一个非常基本的通用对象打印机进行调试,灵感来自于你在LinqPad中获得的超棒程。
下面是我的打印功能的伪代码。我的反射foo目前有点弱,当对象是ILookup时我正在努力处理这种情况,因为我想枚举查找,在其相关集合旁边打印每个键。
ILookup没有非通用接口而且它没有实现IDictionary,所以我现在有点卡住了,因为我不能说o as ILookup<object,object>
...就此而言,我想知道如何深入研究任何通用接口...假设我想为CustomObject<,,>
设置一个特例。
void Print(object o)
{
if(o == null || o.GetType().IsValueType || o is string)
{
Console.WriteLine(o ?? "*nil*");
return;
}
var dict = o as IDictionary;
if(dict != null)
{
foreach(var key in (o as IDictionary).Keys)
{
var value = dict[key];
Print(key + " " + value);
}
return;
}
//how can i make it work with an ILookup?
//?????????
var coll = o as IEnumerable;
if(coll != null)
{
foreach(var item in coll)
{ print(item); }
return;
}
//else it's some object, reflect the properties+values
{
//reflectiony stuff
}
}
答案 0 :(得分:4)
我不确定你要完成什么,但要回答你的具体问题,你可以使用这样的反映:
public static void PrintIfLookup(object obj)
{
if (obj == null)
throw new ArgumentNullException("obj");
// Find first implemented interface that is a constructed version of
// ILookup<,>, or null if no such interface exists.
var lookupType = obj
.GetType()
.GetInterfaces()
.FirstOrDefault
(i => i.IsGenericType &&
i.GetGenericTypeDefinition() == typeof(ILookup<,>));
if (lookupType != null)
{
// It is an ILookup<,>. Invoke the PrintLookup method
// with the correct type-arguments.
// Method to invoke is private and static.
var flags = BindingFlags.NonPublic | BindingFlags.Static;
// Assuming the containing type is called Foo.
typeof(Foo).GetMethod("PrintLookup", flags)
.MakeGenericMethod(lookupType.GetGenericArguments())
.Invoke(null, new[] { obj });
}
}
private static void PrintLookup<TKey, TElement>(ILookup<TKey, TElement> lookup)
{
// TODO: Printing logic
}
我试图用这样的方式编写它,你可以用泛型的强类型方式编写打印逻辑。如果您愿意,可以使用更多反射来获取查找中每个IGrouping<,>
的键和值。
编辑:顺便说一句,如果您使用的是C#4,则可以将if
语句的整个主体替换为:
PrintLookup((dynamic)obj);
答案 1 :(得分:1)
多态性可能会使您的代码变得更简单。
void Print(IDictionary dict)
{
foreach (var key in dict.Keys)
{
var value = dict[key];
Print(key + " " + value);
}
}
void Print(object o)
{
if (o == null || o.GetType().IsValueType || o is string)
{
Console.WriteLine(o ?? "*nil*");
return;
}
}
void Print(string s)
{
Console.WriteLine(s);
}
void Print(IEnumerable ie)
{
foreach (dynamic obj in ie)
{
Print(obj);
}
}
答案 2 :(得分:0)
确定该类型使用反射实现一些通用接口:
var objType = o.GetType();
// get the ILookup<,> interface type (if the type implements it)
var lookupInterface = objType.GetInterface("System.Linq.ILookup`2");
// the type implemented the interface if returned non-null value
var isILookup = lookupInterface != null;
泛型类型名称修改的模式是
type_name`generic_parameter_count
对于泛型类型的特定实例:
type_name`generic_parameter_count[type_name_1,...,type_name_n]
在这种情况下,ILookup<,>
有两个参数,所以它是:
System.Linq.ILookup`2
我们对确切的实例不感兴趣,因此我们不需要指定类型参数。