New test.
[mono.git] / mcs / class / corlib / System.Runtime.Serialization / SerializationCallbacks.cs
1 //
2 // System.Runtime.Serialization.SerializationCallbacks.cs
3 //
4 // Author:
5 //   Robert Jordan (robertj@gmx.net)
6 //
7 // Copyright (C) 2006 Novell, Inc (http://www.novell.com)
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 // 
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 // 
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28
29 #if NET_2_0
30
31 using System;
32 using System.Collections;
33 using System.Reflection;
34        
35 namespace System.Runtime.Serialization {
36
37         internal sealed class SerializationCallbacks
38         {
39                 public delegate void CallbackHandler (StreamingContext context);
40
41                 readonly ArrayList onSerializingList;
42                 readonly ArrayList onSerializedList;
43                 readonly ArrayList onDeserializingList;
44                 readonly ArrayList onDeserializedList;
45
46                 public bool HasSerializingCallbacks {
47                         get {return onSerializingList != null;}
48                 }
49
50                 public bool HasSerializedCallbacks {
51                         get {return onSerializedList != null;}
52                 }
53
54                 public bool HasDeserializingCallbacks {
55                         get {return onDeserializingList != null;}
56                 }
57
58                 public bool HasDeserializedCallbacks {
59                         get {return onDeserializedList != null;}
60                 }
61
62                 public SerializationCallbacks (Type type)
63                 {
64                         onSerializingList   = GetMethodsByAttribute (type, typeof (OnSerializingAttribute));
65                         onSerializedList    = GetMethodsByAttribute (type, typeof (OnSerializedAttribute));
66                         onDeserializingList = GetMethodsByAttribute (type, typeof (OnDeserializingAttribute));
67                         onDeserializedList  = GetMethodsByAttribute (type, typeof (OnDeserializedAttribute));
68                 }
69
70                 const BindingFlags DefaultBindingFlags = BindingFlags.Public | BindingFlags.NonPublic |
71                         BindingFlags.Instance | BindingFlags.DeclaredOnly;
72
73
74                 static ArrayList GetMethodsByAttribute (Type type, Type attr)
75                 {
76                         ArrayList list = new ArrayList ();
77
78                         Type t = type;
79                         while (t != typeof (object)) {
80                                 int count = 0;
81
82                                 foreach (MethodInfo mi in t.GetMethods (DefaultBindingFlags)) {
83                                         if (mi.IsDefined (attr, false)) {
84                                                 list.Add (mi);
85                                                 count++;
86                                         }
87                                 }
88
89                                 // FIXME: MS.NET is checking for this with the verifier at assembly load time.
90                                 if (count > 1)
91                                         throw new TypeLoadException (
92                                                 String.Format ("Type '{0}' has more than one method with the following attribute: '{1}'.", type.AssemblyQualifiedName, attr.FullName));
93
94                                 t = t.BaseType;
95                         }
96
97                         // optimize memory usage
98                         return list.Count == 0 ? null : list;
99                 }
100
101                 static void Invoke (ArrayList list, object target, StreamingContext context)
102                 {
103                         if (list == null)
104                                 return;
105
106                         CallbackHandler handler = null;
107
108                         // construct a delegate from the specified list
109                         foreach (MethodInfo mi in list) {
110                                 handler = (CallbackHandler)
111                                         Delegate.Combine (
112                                                 Delegate.CreateDelegate (typeof (CallbackHandler), target, mi),
113                                                 handler);
114                         }
115
116                         handler (context);
117                 }
118
119                 public void RaiseOnSerializing (object target, StreamingContext contex)
120                 {
121                         Invoke (onSerializingList, target, contex);
122                 }
123
124                 public void RaiseOnSerialized (object target, StreamingContext contex)
125                 {
126                         Invoke (onSerializedList, target, contex);
127                 }
128
129                 public void RaiseOnDeserializing (object target, StreamingContext contex)
130                 {
131                         Invoke (onDeserializingList, target, contex);
132                 }
133
134                 public void RaiseOnDeserialized (object target, StreamingContext contex)
135                 {
136                         Invoke (onDeserializedList, target, contex);
137                 }
138
139                 static Hashtable cache = new Hashtable ();
140
141                 public static SerializationCallbacks GetSerializationCallbacks (Type t)
142                 {
143                         lock (cache.SyncRoot) {
144
145                                 SerializationCallbacks sc = (SerializationCallbacks)  cache [t];
146                                 if (sc == null) {
147                                         sc = new SerializationCallbacks (t);
148                                         cache [t] = sc;
149                                 }
150                                 return sc;
151                         }
152                 }
153         }
154 }
155
156 #endif