Pass instance of Class as parameter to Attribute constructor
I need an instance of class/model(for the purpose of accessing a non-static member) within my custom attribute.
public class LoginModel
{
[AutoComplete(currentInstance)] //pass instance of class or CompanyNames
public string DepartmentName { get; set; }
开发者_JS百科
public string[] DepartmentNames { get {...} }
}
Is there a way to do this without using new()
or Reflection.
That's totally impossible. Attributes are baked into the metadata of the assembly at compile-time so talking about passing an instance of a class to an attribute doesn't make any sense because instances exist only at runtime.
On the other hand attributes are always consumed by reflection, so I guess that at the moment you are checking for the presence of this custom attribute on the class metadata you could use the the instance.
You can only use primitives, or arrays of primitives as Attribute parameters, this is because they need to be 'in-lined' by the compiler at compile-time.
Impossible man, you can't pass instance, delegate, lambda expression into the constructor of Attribute. Some discuss about it at here
https://msdn.microsoft.com/en-us/library/aa288454(v=vs.71).aspx Based on MSDN, it totally can not done if you need to pass an instance of class to process here.
Attribute parameters are restricted to constant values of the following types: Simple types (bool, byte, char, short, int, long, float, and double) string System.Type enums object (The argument to an attribute parameter of type object must be a constant value of one of the above types.) One-dimensional arrays of any of the above types
Moreover, could you explain why we stand in attribute context and need get information from their own object. It sounds strange because we often use Attribute to explain more info about object but not to read object data.
For the purpose of accessing a non-static member you need to instantiate a class at runtime. I have got a workaround for this. If you want to use an instance of specific class you can manage to instantiate a new instance based on the specific type listed or represented as an enumeration.
I used Factory Pattern, Strategy Pattern and Reflection technique to do that. Strategy Pattern is to implement different algorithms with wrapping each class with enumeration type while the factory class should be responsible to register all types of implemented classes and create the suitable one at runtime based on the defined attribute. It might be complex at the start however it became obvious to get it later. Here is a practical example:
Here are all validation types represented in an enumeration
[Flags] public enum AlgorithmTypes { None = 0, All = 1, AtLeastOne = 2 }
Now wrap all of them in a strategy pattern:
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); }
Now Here is Factory pattern that is responsible for creating the right instance for you:
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"); } }
Now validation attribute can be used over classes, constructor is accepting an AlgorithmType which is going to specify later what algorithm should be picked up and called.
[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); } }
精彩评论