1
1
using System ;
2
- using System . Collections ;
3
2
using System . Collections . Generic ;
4
- using System . Collections . ObjectModel ;
5
3
using System . Diagnostics ;
6
- using System . Dynamic ;
7
4
using System . IO ;
8
5
using System . Linq ;
9
6
using System . Reflection ;
@@ -45,38 +42,140 @@ internal static class NonSerializedTypeBuilder
45
42
internal static HashSet < string > dontReimplementMethods = new ( ) { "Finalize" , "Dispose" , "GetType" , "ReferenceEquals" , "GetHashCode" , "Equals" } ;
46
43
const string notSerializedSuffix = "_NotSerialized" ;
47
44
48
- public static object CreateNewObject ( Type baseType )
45
+ private static Func < Type , TypeAttributes , bool > hasVisibility = ( tp , attr ) => ( tp . Attributes & TypeAttributes . VisibilityMask ) == attr ;
46
+ private static Func < Type , bool > isNestedType = ( tp ) => hasVisibility ( tp , TypeAttributes . NestedPrivate ) || hasVisibility ( tp , TypeAttributes . NestedPublic ) || hasVisibility ( tp , TypeAttributes . NestedFamily ) || hasVisibility ( tp , TypeAttributes . NestedAssembly ) ;
47
+ private static Func < Type , bool > isPrivateType = ( tp ) => hasVisibility ( tp , TypeAttributes . NotPublic ) || hasVisibility ( tp , TypeAttributes . NestedPrivate ) || hasVisibility ( tp , TypeAttributes . NestedFamily ) || hasVisibility ( tp , TypeAttributes . NestedAssembly ) ;
48
+ private static Func < Type , bool > isPublicType = ( tp ) => hasVisibility ( tp , TypeAttributes . Public ) || hasVisibility ( tp , TypeAttributes . NestedPublic ) ;
49
+
50
+ public static object ? CreateNewObject ( Type baseType )
49
51
{
50
52
var myType = CreateType ( baseType ) ;
53
+ if ( myType is null )
54
+ {
55
+ return null ;
56
+ }
51
57
var myObject = Activator . CreateInstance ( myType ) ;
52
58
return myObject ;
53
59
}
54
60
55
- public static Type CreateType ( Type tp )
61
+ static void FillTypeMethods ( TypeBuilder tb )
56
62
{
57
- Type existingType = assemblyForNonSerializedClasses . GetType ( tp . Name + "_NotSerialized" , throwOnError : false ) ;
58
- if ( existingType is not null )
63
+ var constructors = tb . BaseType . GetConstructors ( ) ;
64
+ if ( constructors . Count ( ) == 0 )
59
65
{
60
- return existingType ;
66
+ // no constructors defined, at least declare a default
67
+ ConstructorBuilder constructor = tb . DefineDefaultConstructor ( MethodAttributes . Public | MethodAttributes . SpecialName | MethodAttributes . RTSpecialName ) ;
61
68
}
69
+ else
70
+ {
71
+ foreach ( var ctor in constructors )
72
+ {
73
+ var ctorParams = ( from param in ctor . GetParameters ( ) select param . ParameterType ) . ToArray ( ) ;
74
+ var ctorbuilder = tb . DefineConstructor ( ctor . Attributes , ctor . CallingConvention , ctorParams ) ;
75
+ ctorbuilder . GetILGenerator ( ) . Emit ( OpCodes . Ret ) ;
62
76
63
- TypeBuilder tb = GetTypeBuilder ( tp ) ;
64
- ConstructorBuilder constructor = tb . DefineDefaultConstructor ( MethodAttributes . Public | MethodAttributes . SpecialName | MethodAttributes . RTSpecialName ) ;
65
- var properties = tp . GetProperties ( BindingFlags . Public | BindingFlags . NonPublic | BindingFlags . Instance | BindingFlags . Static ) ;
77
+ }
78
+ var parameterless = tb . DefineConstructor ( MethodAttributes . Public | MethodAttributes . SpecialName | MethodAttributes . RTSpecialName , CallingConventions . Standard | CallingConventions . HasThis , Type . EmptyTypes ) ;
79
+ parameterless . GetILGenerator ( ) . Emit ( OpCodes . Ret ) ;
80
+ }
81
+
82
+ var properties = tb . BaseType . GetProperties ( BindingFlags . Public | BindingFlags . NonPublic | BindingFlags . Instance | BindingFlags . Static ) ;
66
83
foreach ( var prop in properties )
67
84
{
68
85
CreateProperty ( tb , prop ) ;
69
86
}
70
87
71
- var methods = tp . GetMethods ( BindingFlags . Public | BindingFlags . NonPublic | BindingFlags . Instance | BindingFlags . Static ) ;
88
+ var methods = tb . BaseType . GetMethods ( BindingFlags . Public | BindingFlags . NonPublic | BindingFlags . Instance | BindingFlags . Static ) ;
72
89
foreach ( var meth in methods )
73
90
{
74
91
CreateMethod ( tb , meth ) ;
75
92
}
76
93
77
94
ImplementEqualityAndHash ( tb ) ;
95
+ }
78
96
79
- return tb . CreateType ( ) ;
97
+ static string MakeName ( Type tp )
98
+ {
99
+ const string suffix = "_NotSerialized" ;
100
+ string @out = tp . Name + suffix ;
101
+ var parentType = tp . DeclaringType ;
102
+ while ( parentType is not null )
103
+ {
104
+ // If we have a nested class, we need the whole nester/nestee
105
+ // chain with the suffix for each.
106
+ @out = parentType . Name + suffix + "+" + @out ;
107
+ parentType = parentType . DeclaringType ;
108
+ }
109
+ return @out ;
110
+ }
111
+
112
+ public static Type ? CreateType ( Type tp )
113
+ {
114
+ if ( ! isPublicType ( tp ) )
115
+ {
116
+ return null ;
117
+ }
118
+
119
+ Type existingType = assemblyForNonSerializedClasses . GetType ( MakeName ( tp ) , throwOnError : false ) ;
120
+ if ( existingType is not null )
121
+ {
122
+ return existingType ;
123
+ }
124
+ var parentType = tp . DeclaringType ;
125
+ if ( parentType is not null )
126
+ {
127
+ // parent types for nested types must be created first. Climb up the
128
+ // declaring type chain until we find a "top-level" class.
129
+ while ( parentType . DeclaringType is not null )
130
+ {
131
+ parentType = parentType . DeclaringType ;
132
+ }
133
+ CreateTypeInternal ( parentType ) ;
134
+ Type nestedType = assemblyForNonSerializedClasses . GetType ( MakeName ( tp ) , throwOnError : true ) ;
135
+ return nestedType ;
136
+ }
137
+ return CreateTypeInternal ( tp ) ;
138
+ }
139
+
140
+ private static Type ? CreateTypeInternal ( Type baseType )
141
+ {
142
+ if ( ! isPublicType ( baseType ) )
143
+ {
144
+ // we can't derive from non-public types.
145
+ return null ;
146
+ }
147
+ Type existingType = assemblyForNonSerializedClasses . GetType ( MakeName ( baseType ) , throwOnError : false ) ;
148
+ if ( existingType is not null )
149
+ {
150
+ return existingType ;
151
+ }
152
+
153
+ TypeBuilder tb = GetTypeBuilder ( baseType ) ;
154
+ SetNonSerialiedAttr ( tb ) ;
155
+ FillTypeMethods ( tb ) ;
156
+
157
+ var nestedtypes = baseType . GetNestedTypes ( BindingFlags . Public | BindingFlags . NonPublic | BindingFlags . Static ) ;
158
+ List < TypeBuilder > nestedBuilders = new ( ) ;
159
+ foreach ( var nested in nestedtypes )
160
+ {
161
+ if ( isPrivateType ( nested ) )
162
+ {
163
+ continue ;
164
+ }
165
+ var nestedBuilder = tb . DefineNestedType ( nested . Name + notSerializedSuffix ,
166
+ TypeAttributes . NestedPublic ,
167
+ nested
168
+ ) ;
169
+ nestedBuilders . Add ( nestedBuilder ) ;
170
+ }
171
+ var outTp = tb . CreateType ( ) ;
172
+ foreach ( var builder in nestedBuilders )
173
+ {
174
+ FillTypeMethods ( builder ) ;
175
+ SetNonSerialiedAttr ( builder ) ;
176
+ builder . CreateType ( ) ;
177
+ }
178
+ return outTp ;
80
179
}
81
180
82
181
private static void ImplementEqualityAndHash ( TypeBuilder tb )
@@ -91,7 +190,7 @@ private static void ImplementEqualityAndHash(TypeBuilder tb)
91
190
getHashIlGen . Emit ( OpCodes . Ldarg_0 ) ;
92
191
getHashIlGen . EmitCall ( OpCodes . Call , typeof ( object ) . GetMethod ( "GetType" ) , Type . EmptyTypes ) ;
93
192
getHashIlGen . EmitCall ( OpCodes . Call , typeof ( Type ) . GetProperty ( "Name" ) . GetMethod , Type . EmptyTypes ) ;
94
- getHashIlGen . EmitCall ( OpCodes . Call , typeof ( string ) . GetMethod ( "GetHashCode" ) , Type . EmptyTypes ) ;
193
+ getHashIlGen . EmitCall ( OpCodes . Call , typeof ( string ) . GetMethod ( "GetHashCode" , Type . EmptyTypes ) , Type . EmptyTypes ) ;
95
194
getHashIlGen . Emit ( OpCodes . Ret ) ;
96
195
97
196
Type [ ] equalsArgs = new Type [ ] { typeof ( object ) , typeof ( object ) } ;
@@ -108,19 +207,20 @@ private static void ImplementEqualityAndHash(TypeBuilder tb)
108
207
equalsIlGen . Emit ( OpCodes . Ret ) ;
109
208
}
110
209
210
+ private static void SetNonSerialiedAttr ( TypeBuilder tb )
211
+ {
212
+ ConstructorInfo attrCtorInfo = typeof ( PyNet_NotSerializedAttribute ) . GetConstructor ( new Type [ ] { } ) ;
213
+ CustomAttributeBuilder attrBuilder = new CustomAttributeBuilder ( attrCtorInfo , new object [ ] { } ) ;
214
+ tb . SetCustomAttribute ( attrBuilder ) ;
215
+ }
216
+
111
217
private static TypeBuilder GetTypeBuilder ( Type baseType )
112
218
{
113
219
string typeSignature = baseType . Name + notSerializedSuffix ;
114
-
115
220
TypeBuilder tb = moduleBuilder . DefineType ( typeSignature ,
116
221
baseType . Attributes ,
117
222
baseType ,
118
223
baseType . GetInterfaces ( ) ) ;
119
-
120
- ConstructorInfo attrCtorInfo = typeof ( PyNet_NotSerializedAttribute ) . GetConstructor ( new Type [ ] { } ) ;
121
- CustomAttributeBuilder attrBuilder = new CustomAttributeBuilder ( attrCtorInfo , new object [ ] { } ) ;
122
- tb . SetCustomAttribute ( attrBuilder ) ;
123
-
124
224
return tb ;
125
225
}
126
226
@@ -188,7 +288,6 @@ private static void CreateProperty(TypeBuilder tb, PropertyInfo pinfo)
188
288
189
289
private static void CreateMethod ( TypeBuilder tb , MethodInfo minfo )
190
290
{
191
- Console . WriteLine ( $ "overimplementing method for: { minfo } { minfo . IsVirtual } { minfo . IsFinal } ") ;
192
291
string methodName = minfo . Name ;
193
292
194
293
if ( dontReimplementMethods . Contains ( methodName ) )
@@ -226,8 +325,7 @@ public void GetObjectData(object obj, SerializationInfo info, StreamingContext c
226
325
227
326
MaybeType type = obj . GetType ( ) ;
228
327
229
- var hasAttr = ( from attr in obj . GetType ( ) . CustomAttributes select attr . AttributeType == typeof ( PyNet_NotSerializedAttribute ) ) . Count ( ) != 0 ;
230
- if ( hasAttr )
328
+ if ( type . Value . CustomAttributes . Any ( ( attr ) => attr . AttributeType == typeof ( NonSerializedAttribute ) ) )
231
329
{
232
330
// Don't serialize a _NotSerialized. Serialize the base type, and deserialize as a _NotSerialized
233
331
type = type . Value . BaseType ;
@@ -257,7 +355,7 @@ public object SetObjectData(object obj, SerializationInfo info, StreamingContext
257
355
object nameObj = null ! ;
258
356
try
259
357
{
260
- nameObj = info . GetValue ( $ "notSerialized_tp", typeof ( object ) ) ;
358
+ nameObj = info . GetValue ( "notSerialized_tp" , typeof ( object ) ) ;
261
359
}
262
360
catch
263
361
{
@@ -274,7 +372,7 @@ public object SetObjectData(object obj, SerializationInfo info, StreamingContext
274
372
return null ! ;
275
373
}
276
374
277
- obj = NonSerializedTypeBuilder . CreateNewObject ( name . Value ) ;
375
+ obj = NonSerializedTypeBuilder . CreateNewObject ( name . Value ) ! ;
278
376
return obj ;
279
377
}
280
378
}
@@ -287,14 +385,13 @@ class NonSerializableSelector : SurrogateSelector
287
385
{
288
386
throw new ArgumentNullException ( ) ;
289
387
}
388
+ selector = this ;
290
389
if ( type . IsSerializable )
291
390
{
292
- selector = this ;
293
391
return null ; // use whichever default
294
392
}
295
393
else
296
394
{
297
- selector = this ;
298
395
return new NotSerializableSerializer ( ) ;
299
396
}
300
397
}
@@ -597,7 +694,6 @@ internal static IFormatter CreateFormatter()
597
694
: new BinaryFormatter ( )
598
695
{
599
696
SurrogateSelector = new NonSerializableSelector ( ) ,
600
- // Binder = new CustomizedBinder()
601
697
} ;
602
698
}
603
699
}
0 commit comments