Почему этот код должен жаловаться на “арность определения универсального типа”?
-
04-10-2019 - |
Вопрос
У меня есть универсальный тип:
class DictionaryComparer<TKey, TValue> : IEqualityComparer<IDictionary<TKey, TValue>>
И фабричный метод, который будет (должен) создавать экземпляр этого класса для данного типа словаря.
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);
}
Удаляя все постороннее - даже этот код выдает одно и то же исключение.
private static object CreateDictionaryComparer()
{
Type def = typeof(DictionaryComparer<,>);
Type t = def.MakeGenericType(new Type[] { typeof(String), typeof(object) });
return Activator.CreateInstance(t);
}
Утверждения проходят, так что я знаю, что T
является универсальным и имеет два общих аргумента.Линия с MakeGenericType
однако за исключением:
Количество предоставленных универсальных аргументов не равно арности определения универсального типа.
Имя параметра:создание экземпляра
Я делал подобные вещи в прошлом и, хоть убейте, не могу понять, почему это не работает в данном случае.(к тому же мне пришлось погуглить арность).
Решение
Разобрался в этом.
У меня было DictionaryComparer
объявлен как внутренний класс.Я могу только предполагать , что MakeGenericType
хотел сделать Query<T>.DictionaryComparer<string,object>
и не был предоставлен T
.
Неисправный код
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 создает внутреннюю структуру данных для каждого типа, используемого приложением.Эти структуры данных называются объектами типов.Тип с универсальными параметрами типа называется открытым типом, а Среда CLR не допускает создания ни одного экземпляра открытого типа (аналогично тому, как среда CLR предотвращает создание экземпляра типа интерфейса).
Изменение
Type t = def.MakeGenericType(new Type[] { typeof(String), typeof(object) });
на
Type t = def.MakeGenericType(new Type[] { typeof(TSource), typeof(String), typeof(object) });