1 // 2 // Copyright (c) ZeroC, Inc. All rights reserved. 3 // 4 5 using System; 6 using System.Collections.Generic; 7 using System.Reflection; 8 9 namespace IceInternal 10 { 11 public sealed class Patcher 12 { 13 static public System.Action<T> arrayReadValue<T>(T[] arr, int index) where T : Ice.Value 14 { 15 return (T v) => { arr[index] = v; }; 16 } 17 18 static public System.Action<T> listReadValue<T>(List<T> seq, int index) where T : Ice.Value 19 { 20 return (T v) => { 21 int count = seq.Count; 22 if(index >= count) // Need to grow the sequence. 23 { 24 for(int i = count; i < index; i++) 25 { 26 seq.Add(default(T)); 27 } 28 seq.Add(v); 29 } 30 else 31 { 32 seq[index] = v; 33 } 34 }; 35 } 36 37 static public System.Action<T> customSeqReadValue<T>(IEnumerable<T> seq, int index) where T : Ice.Value 38 { 39 return (T v) => { 40 var info = getInvokeInfo<T>(seq.GetType()); 41 int count = info.getCount(seq); 42 if(index >= count) // Need to grow the sequence. 43 { 44 for(int i = count; i < index; i++) 45 { 46 info.invokeAdd(seq, default(T)); 47 } 48 info.invokeAdd(seq, v); 49 } 50 else 51 { 52 info.invokeSet(seq, index, v); 53 } 54 }; 55 } 56 getInvokeInfo(Type t)57 private static InvokeInfo getInvokeInfo<T>(Type t) 58 { 59 lock(_methodTable) 60 { 61 InvokeInfo i; 62 if(_methodTable.TryGetValue(t, out i)) 63 { 64 return i; 65 } 66 67 MethodInfo am = t.GetMethod("Add", new Type[] { typeof(T) }); 68 if(am == null) 69 { 70 throw new Ice.MarshalException("Cannot patch a collection without an Add() method"); 71 } 72 73 PropertyInfo pi = t.GetProperty("Item"); 74 if(pi == null) 75 { 76 throw new Ice.MarshalException("Cannot patch a collection without an indexer"); 77 } 78 MethodInfo sm = pi.GetSetMethod(); 79 if(sm == null) 80 { 81 throw new Ice.MarshalException("Cannot patch a collection without an indexer to set a value"); 82 } 83 84 pi = t.GetProperty("Count"); 85 if(pi == null) 86 { 87 throw new Ice.MarshalException("Cannot patch a collection without a Count property"); 88 } 89 MethodInfo cm = pi.GetGetMethod(); 90 if(cm == null) 91 { 92 throw new Ice.MarshalException("Cannot patch a collection without a readable Count property"); 93 } 94 95 i = new InvokeInfo(am, sm, cm); 96 _methodTable.Add(t, i); 97 return i; 98 } 99 } 100 101 private class InvokeInfo 102 { InvokeInfo(MethodInfo am, MethodInfo sm, MethodInfo cm)103 public InvokeInfo(MethodInfo am, MethodInfo sm, MethodInfo cm) 104 { 105 _addMethod = am; 106 _setMethod = sm; 107 _countMethod = cm; 108 } 109 getCount(System.Collections.IEnumerable seq)110 internal int getCount(System.Collections.IEnumerable seq) 111 { 112 try 113 { 114 return (int)_countMethod.Invoke(seq, null); 115 } 116 catch(Exception ex) 117 { 118 throw new Ice.MarshalException("Could not read Count property during patching", ex); 119 } 120 } 121 invokeAdd(System.Collections.IEnumerable seq, object v)122 internal void invokeAdd(System.Collections.IEnumerable seq, object v) 123 { 124 try 125 { 126 object[] arg = new object[] { v }; 127 _addMethod.Invoke(seq, arg); 128 } 129 catch(Exception ex) 130 { 131 throw new Ice.MarshalException("Could not invoke Add method during patching", ex); 132 } 133 } 134 invokeSet(System.Collections.IEnumerable seq, int index, object v)135 internal void invokeSet(System.Collections.IEnumerable seq, int index, object v) 136 { 137 try 138 { 139 object[] args = new object[] { index, v }; 140 _setMethod.Invoke(seq, args); 141 } 142 catch(Exception ex) 143 { 144 throw new Ice.MarshalException("Could not call indexer during patching", ex); 145 } 146 } 147 148 private MethodInfo _addMethod; 149 private MethodInfo _setMethod; 150 private MethodInfo _countMethod; 151 } 152 153 private static Dictionary<Type, InvokeInfo> _methodTable = new Dictionary<Type, InvokeInfo>(); 154 } 155 } 156