Skip to content

Instantly share code, notes, and snippets.

@KOZ60
Last active October 6, 2023 16:58
Show Gist options
  • Save KOZ60/3cd4917cdc5fbe5e26006871ab8f2437 to your computer and use it in GitHub Desktop.
Save KOZ60/3cd4917cdc5fbe5e26006871ab8f2437 to your computer and use it in GitHub Desktop.
PlayOfInheritance
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Proxies;
using System.Diagnostics;
static class UTL
{
public static Test<A, object> CreateProxy<A, B>(Test<A, B> test) {
var proxy = new TestProxy<A, B>(test);
return (Test<A, object>)proxy.GetTransparentProxy();
}
internal abstract class TestProxy : RealProxy
{
protected Type proxyType;
protected TestProxy(Type classToProxy)
: base(classToProxy) {
proxyType = classToProxy;
}
public abstract object Instanse { get; }
}
internal class TestProxy<A, B> : TestProxy
{
public override object Instanse => instance;
private readonly Test<A, B> instance;
private readonly Type instanceType;
private readonly Dictionary<MethodInfo, MethodInfo> mappings
= new Dictionary<MethodInfo, MethodInfo>();
const BindingFlags bindingFlags
= BindingFlags.Public | BindingFlags.Instance;
public TestProxy(Test<A, B> instance)
: base(typeof(Test<A, object>)) {
this.instance = instance;
instanceType = instance.GetType();
// public Method and Property Getter/Setter Mapping
MethodInfo[] proxyMethods = proxyType.GetMethods(bindingFlags);
MethodInfo[] instanceMethods = instanceType.GetMethods(bindingFlags);
for (int i = 0; i < instanceMethods.Length; i++) {
if (proxyMethods[i].Name != instanceMethods[i].Name) {
throw new InvalidProgramException();
}
mappings.Add(proxyMethods[i], instanceMethods[i]);
}
}
public override IMessage Invoke(IMessage msg) {
try {
IMethodMessage mm = msg as IMethodMessage;
object[] args = mm.Args;
MethodInfo proxyMethod = (MethodInfo)mm.MethodBase;
object ret = InvokeToInstance(proxyMethod, args);
return new ReturnMessage(ret, args, args.Length,
mm.LogicalCallContext, (IMethodCallMessage)msg);
} catch (Exception ex) {
if (ex.InnerException != null) {
return new ReturnMessage(ex.InnerException, (IMethodCallMessage)msg);
}
return new ReturnMessage(ex, (IMethodCallMessage)msg);
}
}
private object InvokeToInstance(MethodInfo proxyMethod, object[] args) {
if (mappings.TryGetValue(proxyMethod, out MethodInfo instanceMethod)) {
return instanceMethod.Invoke(instance, args);
}
// Field Get/Set
string fieldName = (string)args[1];
FieldInfo fi = instanceType.GetField(fieldName);
switch (proxyMethod.Name) {
case "FieldSetter":
fi.SetValue(instance, args[2]);
break;
case "FieldGetter":
args[2] = fi.GetValue(instance);
break;
default:
throw new InvalidProgramException("ProxyInvoke");
}
return null;
}
}
}
abstract class Test<A, B> : MarshalByRefObject
{
// Field
public A ValueA;
// Property
public B ValueB { get; set; }
// Method
public void SetValue(A valueA, B valueB) {
ValueA = valueA;
ValueB = valueB;
}
// Method
public void GetValue(out A valueA, out B valueB) {
valueA = ValueA;
valueB = ValueB;
}
private Test<B, object> t1;
protected Test(Test<B, object> t) {
t1 = t;
ValueA = default(A);
if (t != null) {
ValueB = t.ValueA;
}
}
public static implicit operator
Test<A, object>(Test<A, B> value) {
return UTL.CreateProxy(value);
}
public static explicit operator
Test<A, B>(Test<A, object> value) {
if (RemotingServices.IsTransparentProxy(value)) {
if (RemotingServices.GetRealProxy(value)
is UTL.TestProxy proxy) {
return (Test<A, B>)proxy.Instanse;
}
throw new ArgumentException("object not TestProxy");
}
throw new ArgumentException("object not TransparentProxy");
}
}
class Child1 : Test<int, string>
{
public Child1(Test<string, object> t) : base(t) { }
}
class Child2 : Test<string, bool>
{
public Child2(Test<bool, object> t) : base(t) { }
}
class Child3 : Test<bool, int>
{
public Child3(Test<int, object> t) : base(t) { }
}
@KOZ60
Copy link
Author

KOZ60 commented Oct 4, 2023

How to play? :)

static void Main(string[] args) {
    Child3 c3 = new Child3(null);
    c3.ValueA = true;
    c3.ValueB = 1;
    Test<bool, object> proxy = c3;
    bool valueA = proxy.ValueA;
    object valueB = proxy.ValueB;
    proxy.ValueA = false;
    try {
        proxy.ValueB = "A";
    } catch {
        proxy.ValueB = 2;
    }
    Test<bool, int> original = (Test<bool, int>)proxy;
    valueA = original.ValueA;
    valueB = original.ValueB;
    Test<int, object> define = definedTest();
}

public static Test<int, object> definedTest() {
    Child3 c3 = new Child3(null);
    Child2 c2 = new Child2(c3);
    Child1 c1 = new Child1(c2);
    return c1;
}

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