c# - texto - que significa atributo alt
¿Puedo agregar un atributo a una función para evitar el reingreso? (9)
En lugar de usar un bool y configurarlo directamente, intente usar una clase larga y enclavada:
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
}
Esto hará que el hilo de verificación sea seguro.
Por el momento, tengo algunas funciones que se ven así:
private bool inFunction1 = false;
public void function1()
{
if (inFunction1) return;
inFunction1 = true;
// do stuff which might cause function1 to get called
...
inFunction1 = false;
}
Me gustaría poder declararlos así:
[NoReEntry]
public void function1()
{
// do stuff which might cause function1 to get called
...
}
¿Hay algún atributo que pueda agregar a una función para evitar el reingreso? Si no, ¿cómo podría hacer una? He oído acerca de los atributos de AOP que se pueden usar para agregar código antes y después de las llamadas a funciones; Serían adecuados?
Puede encontrar que podría usar PostSharp para lograr esto, junto con las sugerencias de Anthony sobre el uso de try / finally. Sin embargo, es probable que sea complicado. También considere si desea que la reentrada sea por subproceso o por instancia. (¿Pueden varios hilos llamar al método para comenzar, o no?)
No hay nada como esto en el marco mismo.
Sin el ensamblaje y la reescritura de IL, no hay forma de que pueda crear un atributo personalizado que modifique el código en la forma que describe.
Sugiero que utilice un enfoque basado en delegado, por ejemplo, para funciones de un solo argumento:
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;
}
};
}
Este método toma la función para envolver (suponiendo que coincida con Func <TArg, T> - puede escribir otras variantes, o una versión totalmente genérica con más esfuerzo) y una función alternativa para llamar en casos de reingreso. (La función alternativa podría arrojar una excepción, o regresar inmediatamente, etc.) Luego, a lo largo de su código, donde normalmente estaría llamando al método aprobado, llame al delegado devuelto por WrapAgainstReentry () en su lugar.
No creo que eso sea posible.
El más cercano será el atributo ''Sincronizado'', pero eso bloqueará todas las llamadas posteriores.
No hay tal atributo predefinido. Puedes crear nuevos atributos, pero eso no te ayudará. El problema es hacer que el atributo personalizado impida que se vuelva a llamar al método, lo que no creo posible.
La instrucción de bloqueo no es lo que desea, ya que eso hará que las llamadas se bloqueen y esperen, no se devolverán de inmediato.
PD: use un intento ... finalmente bloquee en la muestra anterior. De lo contrario, si se lanza una excepción en el medio de la función, inFunction1 se dejará en verdadero y todas las llamadas volverán inmediatamente.
p.ej :
if (inFunction1)
return;
try
{
inFunction1 = true;
// do stuff which might cause function1 to get called
...
}
finally
{
inFunction1 = false;
}
Puedes construir un atributo PostSharp para verificar si el nombre del método está en el rastro actual de la pila
[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;
}
Este hilo es un poco viejo, pero pensé que valdría la pena llevarlo a 2012 porque este problema aún existe (más o menos). Pude resolver este problema usando objetos proxy generados usando Reflection.Emit (específicamente usando LinFu.DynamicProxy ). El artículo de LinFu es anterior a este artículo, por lo que supongo que todo lo que se discutió fue relevante cuando se lo preguntaron (y aún de alguna manera todavía hoy).
Utilicé LinFu porque ya lo estaba usando para otros fines, pero estoy seguro de que algunos de los otros frameworks DynamicProxy disponibles funcionarían para usted (por ejemplo, Castle.DynamicProxy) o podría implementar el suyo basado en Reflection.Emit (no para aquellos con disposiciones débiles). Proporcionan un mecanismo que ocupa una gran parte de la función de AOP mientras te mantiene en control de tu código.
Si esto es para la seguridad del hilo, debe tener cuidado con esa variable.
Es posible que otro hilo pueda entrar en la función y pasar el cheque antes de que el primer hilo haya establecido la variable.
Asegúrate de que esté marcado como volátil:
private volatile bool inFunction1 = false;
Es posible que desee considerar evitar la reentrada modificando su diseño para que nunca llame a function1 () antes de que se complete su invocación anterior. Para mí, parece que falta una capa desde arriba function1 ().