// // Copyright (c) ZeroC, Inc. All rights reserved. // using System; using System.Collections.Generic; using System.Reflection; namespace IceInternal { public sealed class Patcher { static public System.Action arrayReadValue(T[] arr, int index) where T : Ice.Value { return (T v) => { arr[index] = v; }; } static public System.Action listReadValue(List seq, int index) where T : Ice.Value { return (T v) => { int count = seq.Count; if(index >= count) // Need to grow the sequence. { for(int i = count; i < index; i++) { seq.Add(default(T)); } seq.Add(v); } else { seq[index] = v; } }; } static public System.Action customSeqReadValue(IEnumerable seq, int index) where T : Ice.Value { return (T v) => { var info = getInvokeInfo(seq.GetType()); int count = info.getCount(seq); if(index >= count) // Need to grow the sequence. { for(int i = count; i < index; i++) { info.invokeAdd(seq, default(T)); } info.invokeAdd(seq, v); } else { info.invokeSet(seq, index, v); } }; } private static InvokeInfo getInvokeInfo(Type t) { lock(_methodTable) { InvokeInfo i; if(_methodTable.TryGetValue(t, out i)) { return i; } MethodInfo am = t.GetMethod("Add", new Type[] { typeof(T) }); if(am == null) { throw new Ice.MarshalException("Cannot patch a collection without an Add() method"); } PropertyInfo pi = t.GetProperty("Item"); if(pi == null) { throw new Ice.MarshalException("Cannot patch a collection without an indexer"); } MethodInfo sm = pi.GetSetMethod(); if(sm == null) { throw new Ice.MarshalException("Cannot patch a collection without an indexer to set a value"); } pi = t.GetProperty("Count"); if(pi == null) { throw new Ice.MarshalException("Cannot patch a collection without a Count property"); } MethodInfo cm = pi.GetGetMethod(); if(cm == null) { throw new Ice.MarshalException("Cannot patch a collection without a readable Count property"); } i = new InvokeInfo(am, sm, cm); _methodTable.Add(t, i); return i; } } private class InvokeInfo { public InvokeInfo(MethodInfo am, MethodInfo sm, MethodInfo cm) { _addMethod = am; _setMethod = sm; _countMethod = cm; } internal int getCount(System.Collections.IEnumerable seq) { try { return (int)_countMethod.Invoke(seq, null); } catch(Exception ex) { throw new Ice.MarshalException("Could not read Count property during patching", ex); } } internal void invokeAdd(System.Collections.IEnumerable seq, object v) { try { object[] arg = new object[] { v }; _addMethod.Invoke(seq, arg); } catch(Exception ex) { throw new Ice.MarshalException("Could not invoke Add method during patching", ex); } } internal void invokeSet(System.Collections.IEnumerable seq, int index, object v) { try { object[] args = new object[] { index, v }; _setMethod.Invoke(seq, args); } catch(Exception ex) { throw new Ice.MarshalException("Could not call indexer during patching", ex); } } private MethodInfo _addMethod; private MethodInfo _setMethod; private MethodInfo _countMethod; } private static Dictionary _methodTable = new Dictionary(); } }