Skip to content

Instantly share code, notes, and snippets.

@Ilchert
Created July 16, 2023 09:16
Show Gist options
  • Save Ilchert/f801b3d0110fd2c6f459ac93e8c07b5a to your computer and use it in GitHub Desktop.
Save Ilchert/f801b3d0110fd2c6f459ac93e8c07b5a to your computer and use it in GitHub Desktop.
TypeMagic.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Mail;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text.RegularExpressions;
var data = new Bar(1, new Foo(2));
var d = new Derive_SumEverything<Bar>();
var sum = d.GetSumOfEverything(data);
Console.WriteLine(sum);
public interface ISumEverything<T>
{
int GetSumOfEverything(T instance);
}
class Derive_SumEverything<T> : ISumEverything<T>
{
public int GetSumOfEverything(T instance)
{
if (instance is int i)
return i;
var sum = 0;
var sumMi = Mirror.GetLocalMethod(this.GetType(), nameof(GetSumOfEverything), nameof(Sum));
Mirror.EachProperty(instance, sumMi, p => sum += p);
return sum;
static void Sum<U>(U propertyValue, Action<int> callback)
{
var tcu = new Derive_SumEverything<U>();
var a = tcu.GetSumOfEverything(propertyValue);
callback(a);
}
}
}
record Foo(int a);
record Bar(int a, Foo foo);
static class Mirror
{
public static void EachProperty<T>(T instance, MethodInfo mi, Action<int> action)
{
foreach (var item in typeof(T).GetProperties())
{
var propertyMethod = mi.MakeGenericMethod(item.PropertyType);
propertyMethod.Invoke(null, new object[] { item.GetValue(instance), action });
}
}
public static bool IsMatchLocal(this MethodInfo localMethod,
string surroundingMethodName, string localMethodName)
=> Regex.IsMatch(localMethod.Name,
$@"^<{surroundingMethodName}>g__{localMethodName}\|\d+(_\d+)?");
public static MethodInfo? GetLocalMethod(this Type type,
string surroundingMethodName, string localMethodName)
{
var method = type.GetMethods(BindingFlags.NonPublic | BindingFlags.Static)
.FirstOrDefault(m => m.GetCustomAttribute<CompilerGeneratedAttribute>() != null
&& m.IsMatchLocal(surroundingMethodName, localMethodName));
if (method is not null) return method;
var nestedTypes = type.GetNestedTypes(BindingFlags.NonPublic)
.Where(t => t.GetCustomAttribute<CompilerGeneratedAttribute>() != null);
foreach (var nested in nestedTypes)
{
method = nested.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance)
.FirstOrDefault(m => m.IsMatchLocal(surroundingMethodName, localMethodName));
if (method is not null) return method;
}
return null;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment