public interface IMixinAlpha { }
public interface IMixinBeta { }
 
public static class ComponentExtensions {
    #region MI Impl
    private static readonly ConditionalWeakTable<IMixinAlpha, MixinAlphaProperties> alphaEphemerons = new ConditionalWeakTable<IMixinAlpha, MixinAlphaProperties>();
    private static readonly ConditionalWeakTable<IMixinBeta, MixinBetaProperties> betaEphemerons = new ConditionalWeakTable<IMixinBeta, MixinBetaProperties>();
 
    private static readonly Dictionary<string, Dictionary<Type, MethodInfo>> vtable = new Dictionary<string, Dictionary<Type, MethodInfo>>();
 
    internal static void PopulateVirtualTable() {
        var allLoadedTypes = AppDomain.CurrentDomain.GetAssemblies()
            .SelectMany(ass => ass.GetReferencedAssemblies().Select(Assembly.Load).Concat(new[] { ass }))
            .Distinct()
            .SelectMany(ass => ass.GetTypes());
 
        var allComponentExtensions = typeof(ComponentExtensions).GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static)
                .Where(mi => mi.GetCustomAttributes(typeof(ExtensionAttribute), false).Length > 0);
 
        foreach (Type t in allLoadedTypes) {
            foreach (MethodInfo extMethod in allComponentExtensions) {
                string callerMemberName = extMethod.Name;
                var matchingOverride = t.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
                    .FirstOrDefault(mi => mi.Name == callerMemberName);
                if (matchingOverride != null) {
                    if (!vtable.ContainsKey(callerMemberName)) vtable[callerMemberName] = new Dictionary<Type, MethodInfo>();
                    vtable[callerMemberName][t] = matchingOverride;
                }
            }
        }
    }
 
    private static bool HasOverride(object targetObj, [CallerMemberName] string callerName = null) {
        if (!vtable.ContainsKey(callerName)) return false;
        var overridesForMember = vtable[callerName];
        var targetType = targetObj.GetType();
        return overridesForMember.ContainsKey(targetType);
    }
    private static T InvokeOverride<T>(object targetObj, object[] parameters, [CallerMemberName] string callerName = null) {
        var overridesForMember = vtable[callerName];
        var targetType = targetObj.GetType();
        return (T) overridesForMember[targetType].Invoke(targetObj, parameters);
    }
    private static void InvokeOverride(object targetObj, object[] parameters, [CallerMemberName] string callerName = null) {
        var overridesForMember = vtable[callerName];
        var targetType = targetObj.GetType();
        overridesForMember[targetType].Invoke(targetObj, parameters);
    }
 
    private static MixinAlphaProperties GetAdjunctProperties(IMixinAlpha target) {
        MixinAlphaProperties result;
        if (alphaEphemerons.TryGetValue(target, out result)) return result;
 
        MixinAlphaProperties defaultProps = new MixinAlphaProperties();
        alphaEphemerons.Add(target, defaultProps);
        return defaultProps;
    }
 
    private static MixinBetaProperties GetAdjunctProperties(IMixinBeta target) {
        MixinBetaProperties result;
        if (betaEphemerons.TryGetValue(target, out result)) return result;
 
        MixinBetaProperties defaultProps = new MixinBetaProperties();
        betaEphemerons.Add(target, defaultProps);
        return defaultProps;
    }
    #endregion
 
    #region Alpha Impl
    private class MixinAlphaProperties {
        public int AlphaInt = 10;
        public string AlphaString = "Hello!";
    }
 
    public static int GetAlphaInt(this IMixinAlpha @this) {
        if (HasOverride(@this)) {
            return InvokeOverride<int>(@this, new object[] { });
        }
             
        return GetAdjunctProperties(@this).AlphaInt;
    }
 
    public static void SetAlphaInt(this IMixinAlpha @this, int newValue) {
        if (HasOverride(@this)) {
            InvokeOverride(@this, new object[] { newValue });
            return;
        }
             
        GetAdjunctProperties(@this).AlphaInt = newValue;
    }
 
    public static string GetAlphaString(this IMixinAlpha @this) {
        if (HasOverride(@this)) {
            return InvokeOverride<string>(@this, new object[] { });
        }
             
        return GetAdjunctProperties(@this).AlphaString;
    }
 
    public static void SetAlphaString(this IMixinAlpha @this, string newValue) {
        if (HasOverride(@this)) {
            InvokeOverride(@this, new object[] { newValue });
            return;
        }
 
        GetAdjunctProperties(@this).AlphaString = newValue;
    }
    #endregion
 
    #region Beta Impl
    private class MixinBetaProperties {
        public int BetaInt = 0;
        public float BetaFloat = 0f;
    }
 
    public static int GetBetaInt(this IMixinBeta @this) {
        if (HasOverride(@this)) {
            return InvokeOverride<int>(@this, new object[] { });
        }
 
        return GetAdjunctProperties(@this).BetaInt;
    }
 
    public static void SetBetaInt(this IMixinBeta @this, int newValue) {
        if (HasOverride(@this)) {
            InvokeOverride(@this, new object[] { newValue });
            return;
        }
 
        GetAdjunctProperties(@this).BetaInt = newValue;
    }
 
    public static float GetBetaFloat(this IMixinBeta @this) {
        if (HasOverride(@this)) {
            return InvokeOverride<float>(@this, new object[] { });
        }
 
        return GetAdjunctProperties(@this).BetaFloat;
    }
 
    public static void SetBetaFloat(this IMixinBeta @this, float newValue) {
        if (HasOverride(@this)) {
            InvokeOverride(@this, new object[] { newValue });
            return;
        }
 
        GetAdjunctProperties(@this).BetaFloat = newValue;
    }
 
    public static bool BetaFoobar(this IMixinBeta @this) {
        if (HasOverride(@this)) {
            return InvokeOverride<bool>(@this, new object[] { });
        }
 
        var adjunctData = GetAdjunctProperties(@this);
        return adjunctData.BetaFloat >= adjunctData.BetaInt * 2;
    }
    #endregion
}