I want to develop a NotifyDataErrorInfoAspect with possharp.
The validation of the values depends on several changeable properties (MinValue, MaxValue ...). The contract can't work with variable parameters.
I want to build something similar to the DependencyPropertyAspect. Each property with [DependencyProperty] has a number of optional methods. For example ValidatePropertyName.
[DependencyProperty]
public string Email { get; set; }
private bool ValidateEmail(string value)
{
return EmailRegex.IsMatch(value);
}
How can I do this?
[NotifyDataErrorInfo]
public string Name{ get; set; }
private IList<DataErrorInfo> ValidateName(string value)
{
return this.IsValidName(value);
}
[NotifyDataErrorInfo]
public int Age{ get; set; }
private IList<DataErrorInfo> ValidateAge(int value)
{
return this.IsValidAge(value);
}
[NotifyDataErrorInfo]
public string Email { get; set; }
private IList<DataErrorInfo> ValidateEmail(string value)
{
return this.IsValidEmail(value);
}
The attribute ImportMethod () only allows a fixed method name. What is the best way?
When you need to import a method that doesn't have a fixed predefined name, you can implement IAdviceProvider
interface in your aspect and provide ImportMethodAdviceInstance
that takes a method name as a string argument.
Another important point is that your Validate methods take arguments of a specific type instead of object
. Currently, it's not possible to create a generic attribute in C#, so you need to create two aspect classes to handle this case: an attribute that is an aspect provider and a generic aspect implementation.
Below is a sample implementation of NotifyDataErrorInfo aspect:
[PSerializable]
public class NotifyDataErrorInfoAttribute : LocationLevelAspect, IAspectProvider
{
public IEnumerable<AspectInstance> ProvideAspects(object targetElement)
{
Type propertyType = ((LocationInfo)targetElement).LocationType;
Type aspectType = typeof(NotifyDataErrorInfoAspectImpl<>).MakeGenericType(propertyType);
yield return new AspectInstance(
targetElement, (IAspect) Activator.CreateInstance(aspectType));
}
}
[PSerializable]
public class NotifyDataErrorInfoAspectImpl<T> : ILocationInterceptionAspect,
IInstanceScopedAspect,
IAdviceProvider
{
public Func<T, IList<DataErrorInfo>> ValidateDelegate;
public IEnumerable<AdviceInstance> ProvideAdvices(object targetElement)
{
LocationInfo property = (LocationInfo)targetElement;
string validateMethodName = "Validate" + property.Name;
yield return new ImportMethodAdviceInstance(
typeof(NotifyDataErrorInfoAspectImpl<>).GetField("ValidateDelegate"),
validateMethodName,
true);
}
public void OnSetValue(LocationInterceptionArgs args)
{
if (ValidateDelegate((T) args.Value)?.Any() == true)
throw new ArgumentException("...");
args.ProceedSetValue();
}
public void OnGetValue(LocationInterceptionArgs args)
{
args.ProceedGetValue();
}
public void RuntimeInitialize(LocationInfo locationInfo)
{
}
public object CreateInstance(AdviceArgs adviceArgs)
{
return this.MemberwiseClone();
}
public void RuntimeInitializeInstance()
{
}
}