public object DecodeRpcArgument(IRpcChannel channel, IRpcObjectRepository localRepository, IRpcObjectRepository remoteRepository, IRpcSerializer serializer, RpcArgument argument, Type argumentType) { switch (argument.Type) { case RpcType.Builtin: if (argument.Value == null || argumentType == typeof(void)) { return(null); } if (argumentType.IsAssignableFrom(argument.Value.GetType())) { return(argument.Value); } return(serializer.ChangeType(argument.Value, argumentType)); case RpcType.Proxy: var instanceId = (int)serializer.ChangeType(argument.Value, typeof(int)); var instance = localRepository.GetInstance(instanceId); if (instance == null) { var intfTypes = localRepository.ResolveTypes(argument.TypeId, argumentType); instance = remoteRepository.GetProxyObject(channel, intfTypes, instanceId); } return(instance); case RpcType.Serialized: var type = localRepository.ResolveTypes(argument.TypeId, argumentType)[0]; return(serializer.ChangeType(argument.Value, type)); case RpcType.ObjectArray: var arrayType = localRepository.ResolveTypes(argument.TypeId, argumentType)[0]; var elementType = arrayType?.GetElementType() ?? throw new InvalidOperationException(); var array = Array.CreateInstance(elementType, (int)argument.Value); for (int i = 0; i < array.Length; i++) { array.SetValue(DecodeRpcArgument(channel, localRepository, remoteRepository, serializer, argument.ArrayElements[i], elementType), i); } return(array); default: throw new InvalidDataException(); } }
private RpcArgument CreateRpcArgument(ITransportChannel channel, IRpcObjectRepository localRepository, object argument, Type argumentType) { string typeid = null; RpcType type = RpcType.Proxy; RpcArgument[] arrayElements = null; if (argument == null || argument is IConvertible) { type = RpcType.Builtin; } else if (argument is Array array) { if ((argument.GetType().GetElementType()?.IsPrimitive ?? false) || argument.GetType().GetElementType() == typeof(string)) { type = RpcType.Builtin; } else { type = RpcType.ObjectArray; // make sure we use the correct interface definition as base type (we might get a specific array here) var arrayTemplate = Array.CreateInstance(argumentType.GetElementType(), 0); typeid = localRepository.CreateTypeId(arrayTemplate); argument = array.Length; var elementType = argumentType.GetElementType(); arrayElements = new RpcArgument[array.Length]; for (int i = 0; i < array.Length; i++) { arrayElements[i] = CreateRpcArgument(channel, localRepository, array.GetValue(i), elementType); } } } else if (argumentType != typeof(object) && !argumentType.IsSubclassOf(typeof(Delegate)) && (argumentType.GetCustomAttribute <SerializableAttribute>() != null || (argument.GetType().GetCustomAttribute <SerializableAttribute>() != null))) { type = RpcType.Serialized; typeid = localRepository.CreateTypeId(argument); } else { typeid = localRepository.CreateTypeId(argument); if (argument is IRpcObjectProxy proxy) { /*var instance = localRepository.GetInstance(proxy.LocalInstanceId); * if (instance != null) // todo this check is not necessary * { * argument = proxy.LocalInstanceId; * }*/ argument = proxy.RemoteInstanceId; } else { argument = localRepository.AddInstance(argumentType, argument, channel).InstanceId; } } return(new RpcArgument { Type = type, Value = argument, TypeId = typeid, ArrayElements = arrayElements }); }