Skip to content

Instantly share code, notes, and snippets.

@ZacharyPatten
Created July 23, 2020 17:20
Show Gist options
  • Save ZacharyPatten/39fed42830b6f9c2e34269a7057a0ad4 to your computer and use it in GitHub Desktop.
Save ZacharyPatten/39fed42830b6f9c2e34269a7057a0ad4 to your computer and use it in GitHub Desktop.
An example of using attributes to override default method implementations.
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
@ZacharyPatten
Copy link
Author

ZacharyPatten commented Jul 23, 2020

If you comment out line 19 you can remove the attribute override.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment