Reputation: 494
I have created a generic JavaScriptConverter
derivation for a custom generic class (TabularList<>
) which I have dubbed ITabularConverter<>
. The ITabularConverter
uses reflection to retrieve all of the closed types derived from the TabularList<>
generic type definition to inform the JavaScriptSerializer that it is capable of converting all closed types of ITabularConverter<>
. That code looks like this:
public override IEnumerable<Type> SupportedTypes
{
get
{
var type = typeof (TabularList<>);
var itabulars = Assembly.GetAssembly(type).GetTypes()
.Where(t => t.IsGenericType
&& t.GetGenericTypeDefinition() == type);
return itabulars;
}
}
The problem is, even though there is at least one closed type of TabularList<> in existence by the time this code executes, only the open generic type definition is returned by the above code. The same is true when I expand the search to all currently loaded assemblies.
What's even stranger is that if I examine the call stack, I can see where the JavaScriptSerializer.Serialize method is being invoked and use the immediate window to examine the object being serialized and prove that a closed version of the generic definition exists. Yet, when I execute the following code in the Immediate Window, the result is false
:
Assembly.GetAssembly(obj.TabularListProp.GetType())
.GetTypes()
.Contains(obj.TabularListProp.GetType());
So I retrieve the assembly in which the closed generic is defined and then look for the closed generic type among the types defined by that assembly, and the closed type is not found. How does that make any sense?
Here is the declaration of TabularList<>
:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Xml.Serialization;
namespace Central.Claims.UX.ClaimWFMgrViewModel
{
[Serializable]
public class TabularList<T> : List<T>, ITabular
{
private List<List<object>> _tableView;
[XmlIgnore]
public List<List<object>> TableView
{
get { return GetTableView(); }
}
private List<KeyValuePair<string, Func<object, object>>> Schema { get; set; }
public TabularList()
{
Initialize();
}
public TabularList(IEnumerable<T> source) : base(source)
{
Initialize();
}
private void Initialize()
{
RefreshTableView = true;
var type = typeof(T);
if (Schemas.ContainsKey(type.Name))
{
Schema = Schemas[type.Name];
}
else
{
Schema = new List<KeyValuePair<string, Func<object, object>>>();
}
}
protected List<List<object>> GetTableView()
{
GetSchema();
BuildTable();
return _tableView;
}
private void GetSchema()
{
if (this.Any())
{
var properties = this.First().GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public);
foreach (var property in properties)
{
var getter = property.GetGetMethod();
Schema.Add(new KeyValuePair<string, Func<object, object>>(
property.Name,
(Func<object, object>) Delegate.CreateDelegate(typeof (Func<object, object>), getter)
));
}
}
}
private void BuildTable()
{
_tableView = new List<List<object>>();
foreach (var item in this)
{
TableView.Add(ToTableRow(item));
}
}
private List<object> ToTableRow(T item)
{
var row = new List<object>();
foreach (var column in Schema)
{
row.Add(column.Value(item));
}
return row;
}
}
}
Based on the answers provided here, I have rephrased this question in the SO question How to retrieve a list of all closed generic types generated by the .NET runtime?
Upvotes: 2
Views: 768
Reputation: 152644
Remember that reflection is just querying metadata, so any information contained within it is purely compile-type information. The fact that you have an instance of TabularList<SomeType>)
does not change the metadata contained within the assembly that defines it.
A closed generic type is not defined within either the assembly that defined the open generic type, nor the assembly that creates that particular closed type.
Would you expect to find metadata for every possible closed definition of List<T>
within mscorlib
? Would you expect to find it in an assembly that create a List<int>
variable?
Note that it does work the other way - if you call
Assembly a = Assembly.GetAssembly(typeof(List<int>));
you get the Assembly
mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
So you might be able to reverse your logic - rather than searching for all closed types within an assembly, look for the assembly of the closed type to see if it's "supported".
Upvotes: 1
Reputation: 388413
Generic types generally don’t exist in an assembly. If that was the case, then every possible combination for the type argument would need to be present, which very quickly gives you an infinite amount of different types.
So instead, the generic type definition is the concrete type that exists in the assembly. You can get the generic type definition by calling GetGenericTypeDefinition()
on the type:
Type t = typeof(List<int>);
t.Assembly.GetTypes().Contains(t); // false
t.Assembly.GetTypes().Contains(t.GetGenericTypeDefinition()); // true
Upvotes: 1