Para acceder a un miembro no estático necesita crear una instancia de una clase en tiempo de ejecución. Tengo una solución para esto. Si desea utilizar una instancia de una clase específica, puede administrar una instancia nueva basada en el tipo específico enumerado o representado como una enumeración.
Utilicé el patrón de fábrica, el patrón de estrategia y la técnica de reflexión para hacer eso. El patrón de estrategia consiste en implementar diferentes algoritmos para envolver cada clase con el tipo de enumeración, mientras que la clase de fábrica debe ser responsable de registrar todos los tipos de clases implementadas y crear el adecuado en el tiempo de ejecución en función del atributo definido. Puede ser complejo al principio, sin embargo, se hizo obvio obtenerlo más tarde.Aquí está un ejemplo práctico:
continuación se muestran todos los tipos de validación representados en una enumeración
[Flags]
public enum AlgorithmTypes
{
None = 0,
All = 1,
AtLeastOne = 2
}
Ahora envuelva todos ellos en un patrón de estrategia:
public class NoneValidationMode : RequiredValidationMode
{
public NoneValidationMode() { }
public override bool IsValid(string properties, object value)
{
//validation code here
}
}
public class AllValidationMode: RequiredValidationMode
{
public override bool IsValid(string properties,object value)
{
//validation code here
}
}
public class AtLeastOneValidationMode : RequiredValidationMode
{
public override bool IsValid(string properties, object value)
{
//validation code here
}
}
public abstract class RequiredValidationMode
{
public abstract bool IsValid(string properties, object value);
}
Ahora aquí es el patrón de fábrica que es responsable de crear la instancia correcta para usted:
public class AlgorithmStrategyFactory
{
private static ArrayList _registeredImplementations;
static AlgorithmStrategyFactory()
{
_registeredImplementations = new ArrayList();
RegisterClass(typeof(NoneValidationMode));
RegisterClass(typeof(AllValidationMode));
RegisterClass(typeof(AtLeastOneValidationMode));
}
public static void RegisterClass(Type requestStrategyImpl)
{
if (!requestStrategyImpl.IsSubclassOf(typeof(RequiredValidationMode)))
throw new Exception("requestStrategyImpl must inherit from class RequiredValidationMode");
_registeredImplementations.Add(requestStrategyImpl);
}
public static RequiredValidationMode Create(AlgorithmTypes algorithmType)
{
// loop thru all registered implementations
foreach (Type impl in _registeredImplementations)
{
// get attributes for this type
object[] attrlist = impl.GetCustomAttributes(true);
// loop thru all attributes for this class
foreach (object attr in attrlist)
{
if (attr is AlgorithmAttribute)
{
if (((AlgorithmAttribute)attr).AlgorithmType.Equals(algorithmType))
{
return (RequiredValidationMode)System.Activator.CreateInstance(impl);
}
}
}
}
throw new Exception("Could not find a RequiredValidationMode implementation for this AlgorithmType");
}
}
Ahora el atributo de validación se puede usar sobre las clases, el constructor acepta un AlgorithmType que va a especificar más adelante qué algoritmo debe ser recogido y llamado.
[AttributeUsage(AttributeTargets.Class, AllowMultiple =false)]
public class MyAttribute : ValidationAttribute
{
AlgorithmTypes AlgorithmType;
public MyAttribute(AlgorithmTypes algorithm = AlgorithmTypes.None)
{
AlgorithmType = algorithm;
}
public override bool IsValid(object value)
{
return (AlgorithmStrategyFactory.Create(AlgorithmType)).IsValid(Properties, value);
}
}
¿Hay una manera de pasar los datos a partir del atributo de la instancia de clase o método? (por ejemplo, ¿puede un atributo realizar la autenticación y pasar el usuario autenticado al método?) –
Y esa es la limitación total, una de las mayores limitaciones de C#/.NET que he encontrado hasta ahora. Muy decepcionado. – liang