Ответ 1
Контракт в вашем строительстве не выполняется. Поскольку вы ссылаетесь на поле объектов (this.data), другие потоки могут иметь доступ к полю и могут изменять его значение между Соглашением и разрешением первого параметра и третьим разрешением параметра. (например, они могут быть тремя совершенно разными массивами.)
Вы должны назначить массив локальной переменной, а затем использовать эту переменную во всем методе. Тогда анализатор будет знать, что ограничения выполняются, потому что никакие другие потоки не смогут изменять ссылку.
var localData = this.data;
if (localData == null) return;
byte[] newData = new byte[localData.Length]; // Or whatever the datatype is.
Array.Copy(localData, newData, localData.Length); // Now, this cannot fail.
У этого есть добавленная польза от не только удовлетворения ограничения, но, в действительности, делая код более надежным во многих случаях.
Надеюсь, это приведет вас к ответу на ваш вопрос. Я не мог ответить на ваш вопрос напрямую, потому что у меня нет доступа к версии Visual Studio, которая включает в себя статическую проверку. (Я на VS2008 Pro.) Мой ответ основан на том, что мой собственный визуальный осмотр кода будет заключен, и похоже, что статический контролер транзакций использует аналогичные методы. Я заинтригован! Мне нужно достать мне одну из них.:-D
ОБНОВЛЕНИЕ: (Множество спекуляций)
При отражении, я думаю, я могу сделать довольно хорошее предположение о том, что можно или не может быть доказано (даже без доступа к статической проверке). Как указано в другом ответе, статический контролер не проводит межпроцедурный анализ. Таким образом, с нависшей возможностью многопоточных переменных доступа (как в OP), статический контролер может эффективно работать только с локальными переменными (как определено ниже).
Под "локальными переменными" я имею в виду переменную, к которой не может обращаться ни один другой поток. Это будет включать любые переменные, объявленные в методе или переданные в качестве параметра, если параметр не украшен ref
или out
, или переменная не будет записана анонимным методом.
Если локальная переменная является типом значений, то ее поля также являются локальными переменными (и так далее рекурсивно).
Если локальная переменная является ссылочным типом, то только сама ссылка, а не ее поля, может считаться локальной переменной. Это справедливо даже для объекта, построенного в методе, поскольку сам конструктор может утечка ссылки на построенный объект (например, для статического набора для кэширования).
Пока статический контролер не проводит никакого межпроцедурного анализа, любые предположения о переменных, которые не являются локальными, как определено выше, могут быть аннулированы в любое время и поэтому игнорируются в статическом анализе.
Исключение 1: поскольку строки и массивы известны тем, что среда выполнения является неизменяемой, их свойства (такие как длина) подлежат анализу, если сама строка или переменная массива являются локальными. Это не включает содержимое массива, которые изменяются другими потоками.
Исключение 2: конструктор массива может быть известен по времени выполнения, чтобы не утечка каких-либо ссылок на построенный массив. Поэтому массив, который сконструирован внутри тела метода и не просочился вне метода (передан как параметр другому методу, назначается нелокальной переменной и т.д.), Содержит элементы, которые также могут считаться локальными переменными.
Эти ограничения кажутся довольно обременительными, и я могу представить несколько способов, которыми это можно было бы улучшить, но я не знаю, что было сделано. Вот некоторые другие вещи, которые теоретически можно было бы сделать с помощью статической проверки. Кто-нибудь, у кого есть это, должен проверить, что сделано, а что нет:
- Он может определить, не вызывает ли конструктор утечки каких-либо ссылок на объект или его поля и рассматривает поля любого объекта, сконструированного таким образом как локальные переменные.
- Анализ без утечек может быть выполнен по другим методам, чтобы определить, может ли ссылочный тип, переданный методу, локально после вызова этого метода.
- Переменные, украшенные ThreadStatic или ThreadLocal, могут считаться локальными переменными.
- Параметры могут быть заданы, чтобы игнорировать возможность использования отражения для изменения значений. Это позволит считать частные поля readonly для ссылочных типов или статических частных полей readonly считающимися неизменяемыми. Кроме того, когда эта опция включена, частная или внутренняя переменная X, которая только когда-либо доступна в конструкции
lock(X){ /**/ }
и которая не протекает, может считаться локальной переменной. Тем не менее, эти вещи, по сути, уменьшат надежность статической проверки, поэтому, если это будет возможно.
Еще одна возможность, которая может открыть много нового анализа, будет декларативно назначать переменные и методы, которые их используют (и так далее рекурсивно) для конкретного уникального потока. Это было бы существенным дополнением к языку, но это могло бы стоить того.