Как c # может совместно использовать универсальные реализации ссылочных типов, когда используются typeof и is? - PullRequest
0 голосов
/ 27 июня 2018

Насколько я понимаю, во время выполнения реализация CLR создает другой машинный код (или любое другое представление времени выполнения) для одного и того же универсального типа с разными параметризованными типами значений, но разделяет машинный код для ссылочных типов. Это имеет смысл, поскольку ссылочные типы будут иметь одинаковый размер (размер ссылки).

Что я не понимаю, так это то, как это может работать с кодом, который явно использует код, который напрямую зависит от типа T через что-то вроде typeof (T) или T. Например, в классе:

class TestClass<T> 
{
    public static bool TestAType(Object pObj) { return pObj is T; }
}

Я не вижу, как одна и та же реализация для T = List и T = String может позволить TestClass<String>.TestAType("hello") быть истинным и TestClass<List<int>>.TestAType("hello") ложным.

Здесь я делаю предположение, что машинный код одинаков для скомпилированных универсальных типов, что, конечно, может быть ложным.

Ответы [ 2 ]

0 голосов
/ 05 июля 2018

Собственный код, сгенерированный для каждого универсального экземпляра с использованием ссылочных типов, действительно одинаков (имеет внутренний параметр System.__Canon), но это не означает, что код не должен иметь доступа к исходным аргументам типа. Собственный код может обращаться к метаданным через вспомогательные функции и получать типы.

Было бы полезно изучить реальный нативный код, сгенерированный таким методом, но при просмотре SSCLI это выглядит так: эта функция выполняет свою работу в соответствии с ее описанием:

// Given information about how to do a runtime lookup, generate the tree
// for the runtime lookup.
//
// Run-time lookup is required if the enclosing method is shared between instantiations
// and the token refers to formal type parameters whose instantiation is not known
// at compile-time.
0 голосов
/ 27 июня 2018

Взрыв кода

Поскольку вопрос не о сгенерированном IL, а скорее о JIT-скомпилированном коде, вот небольшое обновление к моему ответу. Большая часть этого взята из CLR Джеффри Рихтера через C # .

Как вы уже указали, CLR генерирует собственный код для каждого отдельного параметра того же универсального типа, который называется Code Explosion . Но CLR может выполнить ряд оптимизаций, чтобы уменьшить сгенерированный собственный код в некоторых случаях, и одним из наиболее важных является то, что собственный код для TestClass<T> может использоваться совместно для всех T это ссылочные типы . Вот почему:

CLR может выполнить эту оптимизацию, поскольку все аргументы ссылочного типа [...] действительно просто указатели [...] на объекты в куче, а указатели объектов все манипулируют одинаково . ¹

(выделено мое)

Итак, ключ к пониманию , почему один и тот же код может использоваться для ссылочных типов, но не для типов значений, заключается в том, что аргументы ссылочного типа являются указателями, а их размер не меняется, в то время как размер типов значений равен - поэтому для каждого типа значений должен быть сгенерирован собственный нативный код.


¹ CLR via C #, Jeffrey Richter, 4. ed, 2012, p.277

...