Created
July 23, 2020 17:20
-
-
Save ZacharyPatten/39fed42830b6f9c2e34269a7057a0ad4 to your computer and use it in GitHub Desktop.
An example of using attributes to override default method implementations.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Linq.Expressions; | |
using System.Reflection; | |
using static Syntax; | |
static class Program | |
{ | |
static void Main() | |
{ | |
CustomClass a = new CustomClass() { _a = 1 }; | |
CustomClass b = new CustomClass() { _a = 2 }; | |
CustomClass c = Addition(a, b); | |
Console.WriteLine($"c = {c._a}"); | |
Console.ReadLine(); | |
} | |
} | |
[AddMethod(type: "CustomClass", name: "AddOverride")] | |
public class CustomClass | |
{ | |
public int _a; | |
public static CustomClass AddOverride(CustomClass a, CustomClass b) => new CustomClass() { _a = 2 * a._a + 2 * b._a }; | |
public static CustomClass operator +(CustomClass a, CustomClass b) => new CustomClass() { _a = a._a + b._a }; | |
} | |
#region FRAMEWORK CODE | |
public class AddMethodAttribute : MethodAttribute | |
{ | |
public AddMethodAttribute( | |
//string assembly = null, | |
string @namespace = null, | |
string type = null, | |
string name = null) : base( | |
@namespace, | |
type, | |
name) { } | |
} | |
public class MethodAttribute : Attribute | |
{ | |
public string _namespace; | |
public string _type; | |
public string _name; | |
//// would need some additional fields too | |
//public string _assembly; | |
//public string _returnType; | |
//public string[] _genericParameterTypes; | |
//public string[] _parameterTypes; | |
public MethodAttribute( | |
//string assembly = null, | |
string @namespace = null, | |
string type = null, | |
string name = null) | |
{ | |
//_assembly = assembly; | |
_namespace = @namespace; | |
_type = type; | |
_name = name; | |
} | |
} | |
public static class Syntax | |
{ | |
public static T Addition<T>(T a, T b) | |
{ | |
return AdditionImplementation<T>.Function(a, b); | |
} | |
internal static class AdditionImplementation<T> | |
{ | |
internal static Func<T, T, T> Function = (T a, T b) => | |
{ | |
// override via attribute | |
object[] addMethodAttributes = typeof(T).GetCustomAttributes(typeof(AddMethodAttribute), false); | |
if (addMethodAttributes.Length == 1 && addMethodAttributes[0] is AddMethodAttribute addMethodAttribute) | |
{ | |
Type type = Type.GetType(addMethodAttribute._namespace + "." + addMethodAttribute._type); | |
MethodInfo methodInfo = type.GetMethod(addMethodAttribute._name); | |
Function = (Func<T, T, T>)methodInfo.CreateDelegate(typeof(Func<T, T, T>)); | |
return Function(a, b); | |
} | |
// default implementation | |
ParameterExpression A = Expression.Parameter(typeof(T)); | |
ParameterExpression B = Expression.Parameter(typeof(T)); | |
Expression BODY = Expression.Add(A, B); | |
Function = Expression.Lambda<Func<T, T, T>>(BODY, A, B).Compile(); | |
return Function(a, b); | |
}; | |
} | |
} | |
#endregion |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
If you comment out
line 19
you can remove the attribute override.