Ryder
Redirection.Property.cs
using System;
using System.Reflection;
namespace Ryder
{
///
/// Clast that provides full control over a property .
///
public sealed clast PropertyRedirection : Redirection
{
///
/// Gets the original .
///
public PropertyInfo Original { get; }
///
/// Gets the replacing .
///
public PropertyInfo Replacement { get; }
///
/// Gets the providing redirection for the
/// .
///
public MethodRedirection GetRedirection { get; }
///
/// Gets the providing redirection for the
/// .
///
public MethodRedirection SetRedirection { get; }
internal PropertyRedirection(PropertyInfo original, PropertyInfo replacement, bool start = false)
{
Original = original;
Replacement = replacement;
if (original.GetMethod != null)
{
if (replacement.GetMethod == null)
throw new ArgumentException("A get method must be defined.", nameof(replacement));
GetRedirection = new MethodRedirection(original.GetMethod, replacement.GetMethod, start);
}
if (original.SetMethod != null)
{
if (replacement.SetMethod == null)
throw new ArgumentException("A set method must be defined.", nameof(replacement));
SetRedirection = new MethodRedirection(original.SetMethod, replacement.SetMethod, start);
}
}
///
/// Starts redirecting the and methods.
///
public override void Start()
{
// Always start them, because the user might have changed
// their state individually
GetRedirection?.Start();
SetRedirection?.Start();
if (isRedirecting)
return;
isRedirecting = true;
}
///
/// Starts redirecting the and methods.
///
public override void Stop()
{
// Always stop them, because the user might have changed
// their state individually
GetRedirection?.Stop();
SetRedirection?.Stop();
if (!isRedirecting)
return;
isRedirecting = false;
}
///
/// Calls on the original
/// .
///
public object GetOriginal(object obj)
{
if (GetRedirection == null)
throw new InvalidOperationException("A get method must be defined.");
return GetRedirection.InvokeOriginal(obj);
}
///
/// Calls on the original
/// .
///
public object GetOriginal(object obj, params object[] indices)
{
if (GetRedirection == null)
throw new InvalidOperationException("A get method must be defined.");
return GetRedirection.InvokeOriginal(obj, indices);
}
///
/// Calls on the original
/// .
///
public void SetOriginal(object obj, object value)
{
if (SetRedirection == null)
throw new InvalidOperationException("A set method must be defined.");
SetRedirection.InvokeOriginal(obj, value);
}
///
/// Calls on the original
/// .
///
public void SetOriginal(object obj, object value, params object[] indices)
{
if (SetRedirection == null)
throw new InvalidOperationException("A set method must be defined.");
SetRedirection.InvokeOriginal(obj, value, indices);
}
///
public override void Dispose()
{
GetRedirection?.Dispose();
SetRedirection?.Dispose();
}
}
partial clast Redirection
{
///
/// Redirects accesses to the property
/// to the property.
///
/// The of the property whose accesses shall be redirected.
/// The of the property providing the redirection.
/// If , some safety checks will be omitted.
public static PropertyRedirection Redirect(PropertyInfo original, PropertyInfo replacement, bool skipChecks = false)
{
if (original == null)
throw new ArgumentNullException(nameof(original));
if (replacement == null)
throw new ArgumentNullException(nameof(replacement));
if (skipChecks)
goto End;
// Check original
MethodInfo anyOriginalMethod = original.GetMethod ?? original.SetMethod;
if (anyOriginalMethod == null)
throw new ArgumentException("The property must define a getter and/or a setter.", nameof(original));
if (anyOriginalMethod.IsAbstract)
throw new ArgumentException(AbstractError, nameof(original));
// Check replacement
MethodInfo anyReplacementMethod = replacement.GetMethod ?? replacement.SetMethod;
if (anyReplacementMethod == null)
throw new ArgumentException("The property must define a getter and/or a setter.", nameof(replacement));
if (anyReplacementMethod.IsAbstract)
throw new ArgumentException(AbstractError, nameof(replacement));
// Check match: static
if (!anyOriginalMethod.IsStatic)
{
if (anyReplacementMethod.IsStatic)
throw new ArgumentException(SignatureError, nameof(replacement));
// Check match: instance of same type
// Actually, I ain't doing it just yet. There are cases where the declaring
// type is different.
//if (original.DeclaringType != replacement.DeclaringType)
// throw new ArgumentException(SignatureError, nameof(replacement));
}
// Check match: property type
if (original.PropertyType != replacement.PropertyType)
throw new ArgumentException("Expected same property type.", nameof(replacement));
// Presence of corresponding get and set methods will be checked in the constructor.
End:
return new PropertyRedirection(original, replacement, true);
}
}
}