Почему этот код будет жаловаться на «определение универсального типа»? - PullRequest
12 голосов
/ 22 сентября 2010

У меня есть универсальный тип:

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 однако исключает с:

Количество предоставленных универсальных аргументов не равно арности определения общего типа.

Имя параметра: экземпляр

Я делал подобные вещи в прошлом, и по жизни я не могу понять, почему это не работает в этом случае. (плюс мне пришлось гуглить arity ).

Ответы [ 2 ]

13 голосов
/ 22 сентября 2010

Разобрался.

Я объявил 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;
        }
    }
}
1 голос
/ 22 января 2015

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) });
...