using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using Pfz.Caching;
using Pfz.Extensions.TypeExtensions;
using Pfz.InterfaceWrapping;
using Pfz.Threading;
namespace Pfz.Remoting.Internal
{
internal sealed class EventWrapper
{
private static object fStaticDictionaryLock = new object();
private static volatile Dictionary<MethodInfo, Type> fStaticDictionary = new Dictionary<MethodInfo, Type>();
static EventWrapper()
{
GCUtils.Collected += p_StaticCollected;
}
private static void p_StaticCollected()
{
try
{
AbortSafe.Lock
(
fStaticDictionaryLock,
() => fStaticDictionary = new Dictionary<MethodInfo, Type>(fStaticDictionary)
);
}
catch
{
}
}
private RemotingClient fClient;
internal EventWrapper(RemotingClient client)
{
fClient = client;
}
public Delegate GetWrapper(EventInfo eventInfo, long objectId, WeakList<object> wrappers)
{
Type handlerType = eventInfo.EventHandlerType;
MethodInfo method = handlerType.GetMethod("Invoke");
Delegate returnValue;
Type result = null;
AbortSafe.Lock
(
fStaticDictionaryLock,
delegate
{
var staticDictionary = fStaticDictionary;
if (!staticDictionary.TryGetValue(method, out result))
{
StringBuilder unit = new StringBuilder();
unit.Append("namespace Pfz.Remoting.InterfaceWrapping.EventWrapping\r\n");
unit.Append("{\r\n");
unit.Append("public sealed class ImplementedEventWrapper:System.IDisposable\r\n");
unit.Append("{\r\n");
unit.Append("public System.Reflection.EventInfo __SourceEventInfo;\r\n");
unit.Append("public long __Object__Id;");
unit.Append("public Pfz.Remoting.Internal.WrapperEventHandler OnInvoke;\r\n");
unit.Append("public System.EventHandler OnDestructor;\r\n");
unit.Append("~ImplementedEventWrapper()\r\n");
unit.Append("{\r\n");
unit.Append(" if (OnDestructor != null)\r\n");
unit.Append(" OnDestructor(this, null);\r\n");
unit.Append("}\r\n");
unit.Append("public void Dispose()\r\n");
unit.Append("{\r\n");
unit.Append(" System.GC.SuppressFinalize(this);");
unit.Append("}\r\n");
unit.Append("public ");
if (method.ReturnType == typeof(void))
unit.Append("void ");
else
{
p_AppendName(unit, method.ReturnType);
unit.Append(' ');
}
unit.Append("ImplementedMethod(");
ParameterInfo[] parameterInfos = method.GetParameters();
foreach(ParameterInfo parameterInfo in parameterInfos)
{
if (parameterInfo.IsOut)
unit.Append("out ");
else
if (parameterInfo.ParameterType.IsByRef)
unit.Append("ref ");
p_AppendName(unit, parameterInfo.ParameterType);
unit.Append(' ');
unit.Append(parameterInfo.Name);
unit.Append(", ");
}
unit.Length -= 2;
unit.Append(")\r\n");
unit.Append("{\r\n");
unit.Append("OnInvoke(__SourceEventInfo, __Object__Id, new object[]{");
foreach(ParameterInfo parameterInfo in parameterInfos)
{
unit.Append(parameterInfo.Name);
unit.Append(", ");
}
unit.Length -= 2;
unit.Append("});\r\n");
unit.Append("}\r\n");
unit.Append("}\r\n");
unit.Append("}\r\n");
CodeDomProvider provider = CodeDomProvider.CreateProvider("C#");
CompilerParameters options = new CompilerParameters();
options.GenerateExecutable = false;
options.GenerateInMemory = true;
options.IncludeDebugInformation = false;
foreach(Assembly assembly in (new Type[]{handlerType, typeof(EventWrapper)}).GetReferencedAssemblies())
options.ReferencedAssemblies.Add(assembly.Location);
CompilerResults results = provider.CompileAssemblyFromSource(options, unit.ToString());
if (results.Errors.Count > 0)
{
unit.Length = 0;
foreach(var error in results.Errors)
{
unit.Append(error.ToString());
unit.Append("\r\n");
}
throw new InterfaceWrapperException(unit.ToString());
}
result = results.CompiledAssembly.GetTypes()[0];
staticDictionary.Add(method, result);
}
}
);
object instance = result.GetConstructor(Type.EmptyTypes).Invoke(null);
result.GetField("OnInvoke").SetValue(instance, new WrapperEventHandler(p_Handler));
result.GetField("OnDestructor").SetValue(instance, new EventHandler(fClient.i_DestroyingImplementedEvent));
result.GetField("__Object__Id").SetValue(instance, objectId);
result.GetField("__SourceEventInfo").SetValue(instance, eventInfo);
returnValue = Delegate.CreateDelegate(eventInfo.EventHandlerType, instance, result.GetMethod("ImplementedMethod"));
wrappers.Add(instance);
return returnValue;
}
private static void p_AppendName(StringBuilder unit, Type type)
{
string fullName = type.FullName;
if (fullName == null)
unit.Append(type.Name.Replace('+', '.'));
else
{
fullName = fullName.Replace('+', '.');
int pos = fullName.IndexOf('`');
if (pos == -1)
unit.Append(fullName);
else
{
fullName = fullName.Substring(0, pos);
unit.Append(fullName);
unit.Append('<');
Type[] arguments = type.GetGenericArguments();
bool first = true;
foreach(Type argument in arguments)
{
if (first)
first = false;
else
unit.Append(", ");
p_AppendName(unit, argument);
}
unit.Append('>');
if (type.IsArray)
unit.Append("[]");
}
}
}
public event WrapperEventHandler OnInvoke;
private void p_Handler(EventInfo sourceEventInfo, long objectId, object[] parameters)
{
try
{
if (OnInvoke != null)
OnInvoke(sourceEventInfo, objectId, parameters);
}
catch
{
if (!fClient.WasDisposed)
throw;
}
}
}
}