I've got a generic type:
class DictionaryComparer<TKey, TValue> : IEqualityComparer<IDictionary<TKey, TValue>>
And a factory method that will (should) create an instance of this class for a given dictionary type.
private static IEqualityComparer<T> CreateDictionaryComparer<T>()
{
Type def = typeof(DictionaryComparer<,>);
Debug.Assert(typeof(T).IsGenericType);
Debug.Assert(typeof(T).GetGenericArguments().Length == 2);
Type t = def.MakeGenericType(typeof(T).GetGenericArguments());
return (IEqualityComparer<T>)Activator.CreateInstance(t);
}
Stripping away all of the extraneous stuff - even this code throws the same exception.
private static object CreateDictionaryComparer()
{
Type def = typeof(DictionaryComparer<,>);
Type t = def.MakeGenericType(new Type[] { typeof(String), typeof(object) });
return Activator.CreateInstance(t);
}
The Asserts pass so I know that T
is generic and has two generic arguments. The line with MakeGenericType
however excepts with:
The number of generic arguments provided doesn't equal the arity of the generic type definition.
Parameter name: instantiation
I've done this sort of thing in the past and for the life of me can't figure out why this isn't working in this case. (plus I had to Google arity).
Figured it out.
I had DictionaryComparer
declared as an inner class. I can only assume that MakeGenericType
wanted to make a Query<T>.DictionaryComparer<string,object>
and was not provided T
.
Failing code
class Program
{
static void Main(string[] args)
{
var q = new Query<int>();
q.CreateError();
}
}
public class Query<TSource>
{
public Query()
{
}
public object CreateError()
{
Type def = typeof(DictionaryComparer<,>);
Type t = def.MakeGenericType(new Type[] { typeof(String), typeof(object) });
return Activator.CreateInstance(t);
}
class DictionaryComparer<TKey, TValue> : IEqualityComparer<IDictionary<TKey, TValue>>
{
public DictionaryComparer()
{
}
public bool Equals(IDictionary<TKey, TValue> x, IDictionary<TKey, TValue> y)
{
if (x.Count != y.Count)
return false;
return GetHashCode(x) == GetHashCode(y);
}
public int GetHashCode(IDictionary<TKey, TValue> obj)
{
int hash = 0;
unchecked
{
foreach (KeyValuePair<TKey, TValue> pair in obj)
{
int key = pair.Key.GetHashCode();
int value = pair.Value != null ? pair.Value.GetHashCode() : 0;
hash ^= key ^ value;
}
}
return hash;
}
}
}
CLR creates an internal data structure for each and every type in use by an application.These data structures are called type objects. A type with generic type parameters is called an open type, and the CLR does not allow any instance of an open type to be constructed (similar to how the CLR prevents an instance of an interface type from being constructed).
Change
Type t = def.MakeGenericType(new Type[] { typeof(String), typeof(object) });
on the
Type t = def.MakeGenericType(new Type[] { typeof(TSource), typeof(String), typeof(object) });
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With