@nileshkumar был прав в том, что ошибка была обнаружена в моей модели проекта. Код в моем приложении был написан как метка инструмента, тогда как модель была создана как метка инструмента.
Вместо того, чтобы использовать bool и установить его непосредственно, попытайтесь использовать длинное и Взаимно блокируемый класс:
long m_InFunction=0;
if(Interlocked.CompareExchange(ref m_InFunction,1,0)==0)
{
// We're not in the function
try
{
}
finally
{
m_InFunction=0;
}
}
else
{
// We're already in the function
}
Это осуществит ориентированную на многопотоковое исполнение проверку.
Без блока и перезаписи IL, нет никакого способа для Вас создать пользовательский атрибут, который изменяет код в способе, которым Вы описываете.
Я предлагаю, чтобы Вы использовали основанный на делегате подход вместо этого, например, для функций отдельного аргумента:
static Func<TArg,T> WrapAgainstReentry<TArg,T>(Func<TArg,T> code, Func<TArg,T> onReentry)
{
bool entered = false;
return x =>
{
if (entered)
return onReentry(x);
entered = true;
try
{
return code(x);
}
finally
{
entered = false;
}
};
}
Этот метод берет функцию для обертывания (предположение, что это соответствует Func <TArg, T> - можно записать другие варианты или полностью универсальную версию с большим усилием), и альтернативная функция для вызова в случаи возвращения. (Альтернативная функция могла выдать исключение или сразу возвратиться, и т.д.) Затем всюду по Вашему коду, где Вы будете обычно называть переданный метод, Вы называете делегата возвращенным WrapAgainstReentry () вместо этого.
Вы могли создать атрибут PostSharp для проверки, чтобы видеть, находится ли название метода в текущем отслеживании стека
[MethodImpl(MethodImplOptions.NoInlining)]
private static bool IsReEntry() {
StackTrace stack = new StackTrace();
StackFrame[] frames = stack.GetFrames();
if (frames.Length < 2)
return false;
string currentMethod = frames[1].GetMethod().Name;
for (int i = 2; i < frames.Length; i++) {
if (frames[i].GetMethod().Name == currentMethod) {
return true;
}
}
return false;
}
Можно найти, что Вы могли использовать PostSharp для выполнения этого - наряду с предложениями от Anthony об использовании попытки/наконец. Это, вероятно, будет грязно все же. Также рассмотрите, хотите ли Вы, чтобы повторная входимость была на основе на экземпляр или на поток. (Несколько потоков могли звонить в метод для начала, или нет?)
Нет ничего как это в самой платформе.
Нет такого предопределенного атрибута. Можно сделать новые атрибуты, но это не поможет Вам. Проблема заставляет пользовательский атрибут предотвратить метод, называемый снова, который я не думаю, является выполнимым.
Оператор блокировки не то, что Вы хотите, так как это заставит вызовы блокироваться и ожидать, не сразу возвращаются.
PS: используйте попытку... наконец блок в вышеупомянутом образце. Иначе, если исключение будет выдано посреди функции, то inFunction1 оставят верным, и все вызовы сразу возвратятся.
например:
if (inFunction1)
return;
try
{
inFunction1 = true;
// do stuff which might cause function1 to get called
...
}
finally
{
inFunction1 = false;
}
Я не думаю, что это будет возможно.
Самым близким будет 'Синхронизируемый' атрибут, но это заблокирует все последующие вызовы.
Если это для Потокобезопасности, необходимо быть осторожными с той переменной.
Возможно, что другой поток мог войти в функцию и пройти проверку, прежде чем первый поток установил переменную.
Удостоверьтесь, что это отметило энергозависимый как так:
private volatile bool inFunction1 = false;