Last active
October 6, 2023 16:58
-
-
Save KOZ60/3cd4917cdc5fbe5e26006871ab8f2437 to your computer and use it in GitHub Desktop.
PlayOfInheritance
This file contains hidden or 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.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) { } | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
How to play? :)