As you try to do the following: WebServiceX.RunWebMethod(A); it bombed. Well... as it turns A and A are different since they come from a different domain. The first A is a proxy object, created when you reference the webservice in Visual Studio, the other A is the actual object whose binary exists locally. C# being strongly typed throws an exception.
The only way to get around this restriction is to make deep copy of object A via. reflection, or... XML serialization and deserialization. In this example I'll cover the first method, via. reflection.
So now after implementing the following code snippet, you want to run the webservice this way: WebServiceX.RunWebMethod((AnotherDomain.A) A.CopyTo(AnotherDomain.A))
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Reflection; namespace ReflectionHelpers { public static class DeepCopyUtils {/// <summary> /// We can't use generic with copy to but this wrapper allows it to wrap the logic around in a way that'll allow for type casting. /// </summary> /// <typeparam name="TSource"></typeparam> /// <typeparam name="TTarget"></typeparam> /// <param name="Source"></param> /// <param name="Target"></param> /// <returns></returns> public static TTarget CopyTo<TSource, TTarget>(this TSource Source, TTarget Target) { return (TTarget) Source.CopyTo_Base(Target); } /// <summary> /// Make a deep copy of source to target type of object. /// NOTE: Unfortunately the 2nd argument cannot be generic as that would cause problems when creating linq anonymous type. /// </summary> /// <param name="Source">The source</param> /// <param name="Target">The target object.</param> /// <returns>An object of type Target.</returns> private static Object CopyTo_Base(this Object Source, Object Target) { //The requisite null case scenerio. if (Source == null) return null; //If the source is null, then target will have a null value also, simple. else if (Target == null && Source != null) Target = Source; //If the target is null, but source is not null, then we want to return the shallow copy of the target, by letting this function falls through. Type BType = Target.GetType(); Type AType = Source.GetType(); //Members or properties. MemberInfo[] BProperties = ((MemberInfo[])BType.GetProperties()).Union((MemberInfo[])BType.GetFields()).ToArray(); MemberInfo[] AProperties = ((MemberInfo[])AType.GetProperties()).Union((MemberInfo[])AType.GetFields()).ToArray(); //Creates a new target object. Object Result; if (Target.GetType().GetConstructor(new Type[] { }) != null) Result = Target.GetType().GetConstructor(new Type[] { }).Invoke(new Object[0]); //The requisite null case scenerio. else //No default constructor, it may be a semi-primitive eg. string or array, so we can do nothing more return Source.Clone(); //Find all similar property names between Source and Target, put them to a list, along with the content of the Source. var x = from b in BProperties join a in AProperties on new{ Name = b.Name, TypeName = b.GetMemberType().Name } equals new { Name = a.Name, TypeName = a.GetMemberType().Name } select new { //The name of the property. ID = a.Name, //3 cases for content: 1) Array, 2) Struct Type and 3) Value Type. Content = a.GetType().IsArray ? ((System.Array)a.GetValue(Source)).CopyTo((System.Array)b.GetValue(Target)) : !a.GetType().IsValueType ? a.GetValue(Source).CopyTo(b.GetValue(Target)) : a.GetValue(Source) }; Dictionary<string, object> MergeResult = new Dictionary<string, object>(); foreach (var y in x) { MergeResult[y.ID] = y.Content; } //Copy if the same name exists in the dictionary as in the result. foreach (var z in ((MemberInfo[]) Result.GetType().GetProperties()).Union((MemberInfo[]) Result.GetType().GetFields())) { if (MergeResult.Keys.Contains(z.Name)) { if(z is PropertyInfo) ((PropertyInfo) z).SetValue(Result, MergeResult[z.Name], null); else if (z is FieldInfo) ((FieldInfo)z).SetValue(Result, MergeResult[z.Name]); } } return Result; }/// <summary> /// Retrieves the value of a member, if the member is of type property or field. /// NOTE: Only works for field and properties, all else returns null. /// </summary> /// <param name="Member"></param> /// <returns></returns> public static object GetValue(this MemberInfo Member, object ObjectInstance) { if (Member.MemberType == MemberTypes.Property) return ((PropertyInfo)Member).GetValue(ObjectInstance, new object[] { }); else if (Member.MemberType == MemberTypes.Field) return ((FieldInfo)Member).GetValue(ObjectInstance); return null; } /// <summary> /// Return the property type of a field, properties or method (return type). /// eg. int a = 0; will return "int". /// </summary> /// <param name="Member">The name of the member to look for.</param> /// <returns>The type of the field/property or method.</returns> public static Type GetMemberType(this MemberInfo Member) { if (Member.MemberType == MemberTypes.Property) return ((PropertyInfo)Member).PropertyType; else if (Member.MemberType == MemberTypes.Field) return ((FieldInfo)Member).FieldType; else if (Member.MemberType == MemberTypes.Method) return ((MethodInfo)Member).ReturnType; return null; } /// <summary> /// Shallow copy one array to the next. /// </summary> /// <param name="Source"></param> /// <param name="Target"></param> /// <returns></returns> public static System.Array CopyTo(this System.Array Source, System.Array Target) { //The requisite null case scenerio. if (Source == null) return null; //If the source is null, then target will have a null value also, simple. else if (Target == null && Source != null) Target = Source; //If the target is null, but source is not null, then we want to return the shallow copy of the target, by letting this function falls through. LinkedList<object> CopyResult = new LinkedList<object>(); for (int i = 0; i < Min(Source.GetLength(0), Target.GetLength(0)); i++) { CopyResult.AddLast(Source.GetValue(i).CopyTo(Target.GetValue(i))); } return (System.Array)CopyResult.ToArray(); } public static int Min(int a, int b) { if (a <= b) return a; else return b; } } }
No comments:
Post a Comment