Mercurial > pub > bltoolkit
comparison Source/TypeBuilder/Builders/AbstractClassBuilder.cs @ 0:f990fcb411a9
Копия текущей версии из github
| author | cin |
|---|---|
| date | Thu, 27 Mar 2014 21:46:09 +0400 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| -1:000000000000 | 0:f990fcb411a9 |
|---|---|
| 1 using System; | |
| 2 using System.Collections.Generic; | |
| 3 using System.Linq; | |
| 4 using System.Reflection; | |
| 5 using System.Diagnostics.CodeAnalysis; | |
| 6 | |
| 7 namespace BLToolkit.TypeBuilder.Builders | |
| 8 { | |
| 9 using Properties; | |
| 10 using Reflection; | |
| 11 using Reflection.Emit; | |
| 12 | |
| 13 internal class AbstractClassBuilder : ITypeBuilder | |
| 14 { | |
| 15 public AbstractClassBuilder(Type sourceType) | |
| 16 { | |
| 17 _sourceType = sourceType; | |
| 18 } | |
| 19 | |
| 20 readonly Type _sourceType; | |
| 21 | |
| 22 public string AssemblyNameSuffix | |
| 23 { | |
| 24 get { return TypeBuilderConsts.AssemblyNameSuffix; } | |
| 25 } | |
| 26 | |
| 27 public Type Build(AssemblyBuilderHelper assemblyBuilder) | |
| 28 { | |
| 29 _context = new BuildContext(_sourceType); | |
| 30 _builders = new AbstractTypeBuilderList(); | |
| 31 | |
| 32 _context.TypeBuilders = GetBuilderList(_context.Type); | |
| 33 _context.AssemblyBuilder = assemblyBuilder; | |
| 34 | |
| 35 _builders.AddRange(_context.TypeBuilders); | |
| 36 _builders.Add(_defaultTypeBuilder); | |
| 37 | |
| 38 return Build(); | |
| 39 } | |
| 40 | |
| 41 internal static string GetTypeFullName(Type type) | |
| 42 { | |
| 43 var name = type.FullName; | |
| 44 | |
| 45 if (type.IsGenericType) | |
| 46 { | |
| 47 name = name.Split('`')[0]; | |
| 48 | |
| 49 foreach (var t in type.GetGenericArguments()) | |
| 50 name += "_" + GetTypeFullName(t).Replace('+', '_').Replace('.', '_'); | |
| 51 } | |
| 52 | |
| 53 return name; | |
| 54 } | |
| 55 | |
| 56 internal static string GetTypeShortName(Type type) | |
| 57 { | |
| 58 var name = type.Name; | |
| 59 | |
| 60 if (type.IsGenericType) | |
| 61 { | |
| 62 name = name.Split('`')[0]; | |
| 63 | |
| 64 foreach (var t in type.GetGenericArguments()) | |
| 65 name += "_" + GetTypeFullName(t).Replace('+', '_').Replace('.', '_'); | |
| 66 } | |
| 67 | |
| 68 return name; | |
| 69 } | |
| 70 | |
| 71 public string GetTypeName() | |
| 72 { | |
| 73 var typeFullName = _sourceType.FullName; | |
| 74 var typeShortName = _sourceType.Name; | |
| 75 | |
| 76 if (_sourceType.IsGenericType) | |
| 77 { | |
| 78 typeFullName = GetTypeFullName (_sourceType); | |
| 79 typeShortName = GetTypeShortName(_sourceType); | |
| 80 } | |
| 81 | |
| 82 typeFullName = typeFullName. Replace('+', '.'); | |
| 83 typeShortName = typeShortName.Replace('+', '.'); | |
| 84 | |
| 85 typeFullName = typeFullName.Substring(0, typeFullName.Length - typeShortName.Length); | |
| 86 typeFullName = typeFullName + "BLToolkitExtension." + typeShortName; | |
| 87 | |
| 88 return typeFullName; | |
| 89 } | |
| 90 | |
| 91 public Type GetBuildingType() | |
| 92 { | |
| 93 return _sourceType; | |
| 94 } | |
| 95 | |
| 96 private static AbstractTypeBuilderList GetBuilderList(TypeHelper type) | |
| 97 { | |
| 98 var attrs = type.GetAttributes(typeof(AbstractTypeBuilderAttribute)); | |
| 99 var builders = new AbstractTypeBuilderList(attrs.Length); | |
| 100 | |
| 101 foreach (AbstractTypeBuilderAttribute attr in attrs) | |
| 102 { | |
| 103 var builder = attr.TypeBuilder; | |
| 104 | |
| 105 if (builder != null) | |
| 106 { | |
| 107 builder.TargetElement = type; | |
| 108 builders.Add(builder); | |
| 109 } | |
| 110 } | |
| 111 | |
| 112 return builders; | |
| 113 } | |
| 114 | |
| 115 private static readonly DefaultTypeBuilder _defaultTypeBuilder = new DefaultTypeBuilder(); | |
| 116 | |
| 117 private BuildContext _context; | |
| 118 private AbstractTypeBuilderList _builders; | |
| 119 | |
| 120 private Type Build() | |
| 121 { | |
| 122 DefineNonAbstractType(); | |
| 123 | |
| 124 SetID(_builders); | |
| 125 | |
| 126 _context.BuildElement = BuildElement.Type; | |
| 127 | |
| 128 Build(BuildStep.Before, _builders); | |
| 129 Build(BuildStep.Build, _builders); | |
| 130 | |
| 131 var ids = _builders.ToDictionary(builder => builder, builder => builder.ID); | |
| 132 | |
| 133 DefineAbstractProperties(); | |
| 134 DefineAbstractMethods(); | |
| 135 OverrideVirtualProperties(); | |
| 136 OverrideVirtualMethods(); | |
| 137 DefineInterfaces(); | |
| 138 | |
| 139 foreach (var builder in ids.Keys) | |
| 140 builder.ID = ids[builder]; | |
| 141 | |
| 142 _context.BuildElement = BuildElement.Type; | |
| 143 | |
| 144 Build(BuildStep.After, _builders); | |
| 145 | |
| 146 var initMethod = _context.Type.GetMethod("InitInstance", typeof(InitContext)); | |
| 147 | |
| 148 // Finalize constructors. | |
| 149 // | |
| 150 if (_context.TypeBuilder.IsDefaultConstructorDefined) | |
| 151 { | |
| 152 if (initMethod != null) | |
| 153 _context.TypeBuilder.DefaultConstructor.Emitter | |
| 154 .ldarg_0 | |
| 155 .ldnull | |
| 156 .callvirt (initMethod) | |
| 157 ; | |
| 158 | |
| 159 _context.TypeBuilder.DefaultConstructor.Emitter.ret(); | |
| 160 } | |
| 161 | |
| 162 if (_context.TypeBuilder.IsInitConstructorDefined) | |
| 163 { | |
| 164 if (initMethod != null) | |
| 165 _context.TypeBuilder.InitConstructor.Emitter | |
| 166 .ldarg_0 | |
| 167 .ldarg_1 | |
| 168 .callvirt (initMethod) | |
| 169 ; | |
| 170 | |
| 171 _context.TypeBuilder.InitConstructor.Emitter.ret(); | |
| 172 } | |
| 173 | |
| 174 if (_context.TypeBuilder.IsTypeInitializerDefined) | |
| 175 _context.TypeBuilder.TypeInitializer.Emitter.ret(); | |
| 176 | |
| 177 // Create the type. | |
| 178 // | |
| 179 return _context.TypeBuilder.Create(); | |
| 180 } | |
| 181 | |
| 182 private static int _idCounter; | |
| 183 | |
| 184 private static void SetID(AbstractTypeBuilderList builders) | |
| 185 { | |
| 186 foreach (var builder in builders) | |
| 187 builder.ID = ++_idCounter; | |
| 188 } | |
| 189 | |
| 190 private static void CheckCompatibility(BuildContext context, AbstractTypeBuilderList builders) | |
| 191 { | |
| 192 for (var i = 0; i < builders.Count; i++) | |
| 193 { | |
| 194 var cur = builders[i]; | |
| 195 | |
| 196 if (cur == null) | |
| 197 continue; | |
| 198 | |
| 199 for (var j = 0; j < builders.Count; j++) | |
| 200 { | |
| 201 var test = builders[j]; | |
| 202 | |
| 203 if (i == j || test == null) | |
| 204 continue; | |
| 205 | |
| 206 if (cur.IsCompatible(context, test) == false) | |
| 207 builders[j] = null; | |
| 208 } | |
| 209 } | |
| 210 | |
| 211 for (var i = 0; i < builders.Count; i++) | |
| 212 if (builders[i] == null) | |
| 213 builders.RemoveAt(i--); | |
| 214 } | |
| 215 | |
| 216 private void DefineNonAbstractType() | |
| 217 { | |
| 218 var interfaces = new List<Type>(); | |
| 219 | |
| 220 if (_context.Type.IsInterface) | |
| 221 { | |
| 222 interfaces.Add(_context.Type); | |
| 223 _context.InterfaceMap.Add(_context.Type, null); | |
| 224 } | |
| 225 | |
| 226 foreach (var tb in _builders) | |
| 227 { | |
| 228 var types = tb.GetInterfaces(); | |
| 229 | |
| 230 if (types != null) | |
| 231 { | |
| 232 foreach (var t in types) | |
| 233 { | |
| 234 if (t == null) | |
| 235 continue; | |
| 236 | |
| 237 if (!t.IsInterface) | |
| 238 { | |
| 239 throw new InvalidOperationException( | |
| 240 string.Format(Resources.AbstractClassBuilder_TypeIsNotAnInterface, t.FullName)); | |
| 241 } | |
| 242 | |
| 243 if (interfaces.Contains(t) == false) | |
| 244 { | |
| 245 interfaces.Add(t); | |
| 246 _context.InterfaceMap.Add(t, tb); | |
| 247 } | |
| 248 } | |
| 249 } | |
| 250 } | |
| 251 | |
| 252 var typeName = GetTypeName(); | |
| 253 | |
| 254 _context.TypeBuilder = _context.AssemblyBuilder.DefineType( | |
| 255 typeName, | |
| 256 TypeAttributes.Public | TypeAttributes.BeforeFieldInit | (TypeFactory.SealTypes? TypeAttributes.Sealed: 0), | |
| 257 _context.Type.IsInterface? typeof(object): (Type)_context.Type, | |
| 258 interfaces.ToArray()); | |
| 259 | |
| 260 if (_context.Type.IsSerializable) | |
| 261 _context.TypeBuilder.SetCustomAttribute(typeof(SerializableAttribute)); | |
| 262 } | |
| 263 | |
| 264 class BuilderComparer : IComparer<IAbstractTypeBuilder> | |
| 265 { | |
| 266 public BuilderComparer(BuildContext context) | |
| 267 { | |
| 268 _context = context; | |
| 269 } | |
| 270 | |
| 271 readonly BuildContext _context; | |
| 272 | |
| 273 [SuppressMessage("Microsoft.Design", "CA1062:ValidateArgumentsOfPublicMethods")] | |
| 274 public int Compare(IAbstractTypeBuilder x, IAbstractTypeBuilder y) | |
| 275 { | |
| 276 return y.GetPriority(_context) - x.GetPriority(_context); | |
| 277 } | |
| 278 } | |
| 279 | |
| 280 private void Build(BuildStep step, AbstractTypeBuilderList builders) | |
| 281 { | |
| 282 _context.Step = step; | |
| 283 _context.TypeBuilders.Clear(); | |
| 284 | |
| 285 foreach (var builder in builders) | |
| 286 if (builder.IsApplied(_context, builders)) | |
| 287 _context.TypeBuilders.Add(builder); | |
| 288 | |
| 289 if (_context.IsVirtualMethod || _context.IsVirtualProperty) | |
| 290 _context.TypeBuilders.Add(_defaultTypeBuilder); | |
| 291 | |
| 292 if (_context.TypeBuilders.Count == 0) | |
| 293 return; | |
| 294 | |
| 295 CheckCompatibility(_context, _context.TypeBuilders); | |
| 296 | |
| 297 _context.TypeBuilders.Sort(new BuilderComparer(_context)); | |
| 298 | |
| 299 for (var i = 0; i < _context.TypeBuilders.Count; i++) | |
| 300 { | |
| 301 var builder = _context.TypeBuilders[i]; | |
| 302 | |
| 303 builder.Build(_context); | |
| 304 } | |
| 305 } | |
| 306 | |
| 307 private void BeginEmitMethod(MethodInfo method) | |
| 308 { | |
| 309 _context.CurrentMethod = method; | |
| 310 _context.MethodBuilder = _context.TypeBuilder.DefineMethod(method); | |
| 311 | |
| 312 var emit = _context.MethodBuilder.Emitter; | |
| 313 | |
| 314 // Label right before return and catch block. | |
| 315 // | |
| 316 _context.ReturnLabel = emit.DefineLabel(); | |
| 317 | |
| 318 // Create return value. | |
| 319 // | |
| 320 if (method.ReturnType != typeof(void)) | |
| 321 { | |
| 322 _context.ReturnValue = _context.MethodBuilder.Emitter.DeclareLocal(method.ReturnType); | |
| 323 emit.Init(_context.ReturnValue); | |
| 324 } | |
| 325 | |
| 326 // Initialize out parameters. | |
| 327 // | |
| 328 var parameters = method.GetParameters(); | |
| 329 | |
| 330 if (parameters != null) | |
| 331 emit.InitOutParameters(parameters); | |
| 332 } | |
| 333 | |
| 334 private void EmitMethod( | |
| 335 AbstractTypeBuilderList builders, MethodInfo methdoInfo, BuildElement buildElement) | |
| 336 { | |
| 337 SetID(builders); | |
| 338 | |
| 339 _context.BuildElement = buildElement; | |
| 340 | |
| 341 var isCatchBlockRequired = false; | |
| 342 var isFinallyBlockRequired = false; | |
| 343 | |
| 344 foreach (var builder in builders) | |
| 345 { | |
| 346 isCatchBlockRequired = isCatchBlockRequired || IsApplied(builder, builders, BuildStep.Catch); | |
| 347 isFinallyBlockRequired = isFinallyBlockRequired || IsApplied(builder, builders, BuildStep.Finally); | |
| 348 } | |
| 349 | |
| 350 BeginEmitMethod(methdoInfo); | |
| 351 | |
| 352 Build(BuildStep.Begin, builders); | |
| 353 | |
| 354 var emit = _context.MethodBuilder.Emitter; | |
| 355 var returnLabel = _context.ReturnLabel; | |
| 356 | |
| 357 // Begin catch block. | |
| 358 // | |
| 359 | |
| 360 if (isCatchBlockRequired || isFinallyBlockRequired) | |
| 361 { | |
| 362 _context.ReturnLabel = emit.DefineLabel(); | |
| 363 emit.BeginExceptionBlock(); | |
| 364 } | |
| 365 | |
| 366 Build(BuildStep.Before, builders); | |
| 367 Build(BuildStep.Build, builders); | |
| 368 Build(BuildStep.After, builders); | |
| 369 | |
| 370 if (isCatchBlockRequired || isFinallyBlockRequired) | |
| 371 { | |
| 372 emit.MarkLabel(_context.ReturnLabel); | |
| 373 _context.ReturnLabel = returnLabel; | |
| 374 } | |
| 375 | |
| 376 // End catch block. | |
| 377 // | |
| 378 if (isCatchBlockRequired) | |
| 379 { | |
| 380 emit | |
| 381 .BeginCatchBlock(typeof(Exception)); | |
| 382 | |
| 383 _context.ReturnLabel = emit.DefineLabel(); | |
| 384 _context.Exception = emit.DeclareLocal(typeof(Exception)); | |
| 385 | |
| 386 emit | |
| 387 .stloc (_context.Exception); | |
| 388 | |
| 389 Build(BuildStep.Catch, builders); | |
| 390 | |
| 391 emit | |
| 392 .rethrow | |
| 393 .end(); | |
| 394 | |
| 395 emit.MarkLabel(_context.ReturnLabel); | |
| 396 _context.ReturnLabel = returnLabel; | |
| 397 _context.Exception = null; | |
| 398 } | |
| 399 | |
| 400 if (isFinallyBlockRequired) | |
| 401 { | |
| 402 emit.BeginFinallyBlock(); | |
| 403 _context.ReturnLabel = emit.DefineLabel(); | |
| 404 | |
| 405 Build(BuildStep.Finally, builders); | |
| 406 | |
| 407 emit.MarkLabel(_context.ReturnLabel); | |
| 408 _context.ReturnLabel = returnLabel; | |
| 409 } | |
| 410 | |
| 411 if (isCatchBlockRequired || isFinallyBlockRequired) | |
| 412 emit.EndExceptionBlock(); | |
| 413 | |
| 414 Build(BuildStep.End, builders); | |
| 415 | |
| 416 EndEmitMethod(); | |
| 417 } | |
| 418 | |
| 419 private void EndEmitMethod() | |
| 420 { | |
| 421 var emit = _context.MethodBuilder.Emitter; | |
| 422 | |
| 423 // Prepare return. | |
| 424 // | |
| 425 emit.MarkLabel(_context.ReturnLabel); | |
| 426 | |
| 427 if (_context.ReturnValue != null) | |
| 428 emit.ldloc(_context.ReturnValue); | |
| 429 | |
| 430 emit.ret(); | |
| 431 | |
| 432 // Cleanup the context. | |
| 433 // | |
| 434 _context.ReturnValue = null; | |
| 435 _context.CurrentMethod = null; | |
| 436 _context.MethodBuilder = null; | |
| 437 } | |
| 438 | |
| 439 private static AbstractTypeBuilderList GetBuilders(object[] attributes, object target) | |
| 440 { | |
| 441 var builders = new AbstractTypeBuilderList(attributes.Length); | |
| 442 | |
| 443 foreach (AbstractTypeBuilderAttribute attr in attributes) | |
| 444 { | |
| 445 var builder = attr.TypeBuilder; | |
| 446 | |
| 447 builder.TargetElement = target; | |
| 448 builders.Add(builder); | |
| 449 } | |
| 450 | |
| 451 return builders; | |
| 452 } | |
| 453 | |
| 454 private static AbstractTypeBuilderList GetBuilders(MemberInfo memberInfo) | |
| 455 { | |
| 456 return GetBuilders( | |
| 457 memberInfo.GetCustomAttributes(typeof(AbstractTypeBuilderAttribute), true), memberInfo); | |
| 458 } | |
| 459 | |
| 460 private static AbstractTypeBuilderList GetBuilders(ParameterInfo parameterInfo) | |
| 461 { | |
| 462 return GetBuilders( | |
| 463 parameterInfo.GetCustomAttributes(typeof(AbstractTypeBuilderAttribute), true), parameterInfo); | |
| 464 } | |
| 465 | |
| 466 private static AbstractTypeBuilderList GetBuilders(ParameterInfo[] parameters) | |
| 467 { | |
| 468 var builders = new AbstractTypeBuilderList(); | |
| 469 | |
| 470 foreach (var pi in parameters) | |
| 471 { | |
| 472 var attributes = pi.GetCustomAttributes(typeof(AbstractTypeBuilderAttribute), true); | |
| 473 | |
| 474 foreach (AbstractTypeBuilderAttribute attr in attributes) | |
| 475 { | |
| 476 var builder = attr.TypeBuilder; | |
| 477 | |
| 478 builder.TargetElement = pi; | |
| 479 builders.Add(builder); | |
| 480 } | |
| 481 } | |
| 482 | |
| 483 return builders; | |
| 484 } | |
| 485 | |
| 486 private static AbstractTypeBuilderList Combine(params AbstractTypeBuilderList[] builders) | |
| 487 { | |
| 488 var list = new AbstractTypeBuilderList(); | |
| 489 | |
| 490 foreach (var l in builders) | |
| 491 list.AddRange(l); | |
| 492 | |
| 493 return list; | |
| 494 } | |
| 495 | |
| 496 private bool IsApplied(IAbstractTypeBuilder builder, AbstractTypeBuilderList builders, BuildStep buildStep) | |
| 497 { | |
| 498 _context.Step = buildStep; | |
| 499 return builder.IsApplied(_context, builders); | |
| 500 } | |
| 501 | |
| 502 private bool IsApplied(BuildElement element, AbstractTypeBuilderList builders) | |
| 503 { | |
| 504 _context.BuildElement = element; | |
| 505 | |
| 506 foreach (var builder in builders) | |
| 507 { | |
| 508 if (IsApplied(builder, builders, BuildStep.Before)) return true; | |
| 509 if (IsApplied(builder, builders, BuildStep.Build)) return true; | |
| 510 if (IsApplied(builder, builders, BuildStep.After)) return true; | |
| 511 if (IsApplied(builder, builders, BuildStep.Catch)) return true; | |
| 512 if (IsApplied(builder, builders, BuildStep.Finally)) return true; | |
| 513 } | |
| 514 | |
| 515 return false; | |
| 516 } | |
| 517 | |
| 518 private static void GetAbstractProperties(Type type, List<PropertyInfo> props) | |
| 519 { | |
| 520 if (props.FirstOrDefault(mi => mi.DeclaringType == type) == null) | |
| 521 { | |
| 522 props.AddRange( | |
| 523 type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)); | |
| 524 | |
| 525 if (type.IsInterface) | |
| 526 foreach (var t in type.GetInterfaces()) | |
| 527 GetAbstractProperties(t, props); | |
| 528 } | |
| 529 } | |
| 530 | |
| 531 private void DefineAbstractProperties() | |
| 532 { | |
| 533 var props = new List<PropertyInfo>(); | |
| 534 | |
| 535 GetAbstractProperties(_context.Type, props); | |
| 536 | |
| 537 foreach (var pi in props) | |
| 538 { | |
| 539 _context.CurrentProperty = pi; | |
| 540 | |
| 541 var propertyBuilders = GetBuilders(pi); | |
| 542 | |
| 543 var getter = pi.GetGetMethod(true); | |
| 544 var setter = pi.GetSetMethod(true); | |
| 545 | |
| 546 if (getter != null && getter.IsAbstract || | |
| 547 setter != null && setter.IsAbstract) | |
| 548 { | |
| 549 DefineAbstractGetter(pi, getter, propertyBuilders); | |
| 550 DefineAbstractSetter(pi, setter, propertyBuilders); | |
| 551 } | |
| 552 } | |
| 553 | |
| 554 _context.CurrentProperty = null; | |
| 555 } | |
| 556 | |
| 557 private void DefineAbstractGetter( | |
| 558 PropertyInfo propertyInfo, MethodInfo getter, AbstractTypeBuilderList propertyBuilders) | |
| 559 { | |
| 560 // Getter can be not defined. We will generate it anyway. | |
| 561 // | |
| 562 if (getter == null) | |
| 563 #if SILVERLIGHT | |
| 564 return; | |
| 565 #else | |
| 566 getter = new FakeGetter(propertyInfo); | |
| 567 #endif | |
| 568 | |
| 569 var builders = Combine( | |
| 570 GetBuilders(getter.GetParameters()), | |
| 571 GetBuilders(getter.ReturnParameter), | |
| 572 GetBuilders(getter), | |
| 573 propertyBuilders, | |
| 574 _builders); | |
| 575 | |
| 576 EmitMethod(builders, getter, BuildElement.AbstractGetter); | |
| 577 } | |
| 578 | |
| 579 private void DefineAbstractSetter( | |
| 580 PropertyInfo propertyInfo, | |
| 581 MethodInfo setter, | |
| 582 AbstractTypeBuilderList propertyBuilders) | |
| 583 { | |
| 584 // Setter can be not defined. We will generate it anyway. | |
| 585 // | |
| 586 if (setter == null) | |
| 587 #if SILVERLIGHT | |
| 588 return; | |
| 589 #else | |
| 590 setter = new FakeSetter(propertyInfo); | |
| 591 #endif | |
| 592 | |
| 593 var builders = Combine( | |
| 594 GetBuilders(setter.GetParameters()), | |
| 595 GetBuilders(setter.ReturnParameter), | |
| 596 GetBuilders(setter), | |
| 597 propertyBuilders, | |
| 598 _builders); | |
| 599 | |
| 600 EmitMethod(builders, setter, BuildElement.AbstractSetter); | |
| 601 } | |
| 602 | |
| 603 private static void GetAbstractMethods(Type type, List<MethodInfo> methods) | |
| 604 { | |
| 605 if (!methods.Exists(mi => mi.DeclaringType == type)) | |
| 606 { | |
| 607 methods.AddRange( | |
| 608 type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)); | |
| 609 | |
| 610 if (type.IsInterface) | |
| 611 foreach (var t in type.GetInterfaces()) | |
| 612 GetAbstractMethods(t, methods); | |
| 613 } | |
| 614 } | |
| 615 | |
| 616 private void DefineAbstractMethods() | |
| 617 { | |
| 618 var methods = new List<MethodInfo>(); | |
| 619 | |
| 620 GetAbstractMethods(_context.Type, methods); | |
| 621 | |
| 622 foreach (var method in methods) | |
| 623 { | |
| 624 if (method.IsAbstract && (method.Attributes & MethodAttributes.SpecialName) == 0) | |
| 625 { | |
| 626 var builders = Combine( | |
| 627 GetBuilders(method.GetParameters()), | |
| 628 GetBuilders(method.ReturnParameter), | |
| 629 GetBuilders(method), | |
| 630 _builders); | |
| 631 | |
| 632 EmitMethod(builders, method, BuildElement.AbstractMethod); | |
| 633 } | |
| 634 } | |
| 635 } | |
| 636 | |
| 637 private void OverrideVirtualProperties() | |
| 638 { | |
| 639 var props = _context.Type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); | |
| 640 | |
| 641 foreach (var pi in props) | |
| 642 { | |
| 643 _context.CurrentProperty = pi; | |
| 644 | |
| 645 var propertyBuilders = GetBuilders(pi); | |
| 646 | |
| 647 var getter = pi.GetGetMethod(true); | |
| 648 | |
| 649 if (getter != null && getter.IsVirtual && !getter.IsAbstract && !getter.IsFinal) | |
| 650 OverrideGetter(getter, propertyBuilders); | |
| 651 | |
| 652 var setter = pi.GetSetMethod(true); | |
| 653 | |
| 654 if (setter != null && setter.IsVirtual && !setter.IsAbstract && !setter.IsFinal) | |
| 655 OverrideSetter(setter, propertyBuilders); | |
| 656 } | |
| 657 | |
| 658 _context.CurrentProperty = null; | |
| 659 } | |
| 660 | |
| 661 private void OverrideGetter(MethodInfo getter, AbstractTypeBuilderList propertyBuilders) | |
| 662 { | |
| 663 var builders = Combine( | |
| 664 GetBuilders(getter.GetParameters()), | |
| 665 GetBuilders(getter.ReturnParameter), | |
| 666 GetBuilders(getter), | |
| 667 propertyBuilders, | |
| 668 _builders); | |
| 669 | |
| 670 if (IsApplied(BuildElement.VirtualGetter, builders)) | |
| 671 EmitMethod(builders, getter, BuildElement.VirtualGetter); | |
| 672 } | |
| 673 | |
| 674 private void OverrideSetter(MethodInfo setter, AbstractTypeBuilderList propertyBuilders) | |
| 675 { | |
| 676 var builders = Combine( | |
| 677 GetBuilders(setter.GetParameters()), | |
| 678 GetBuilders(setter.ReturnParameter), | |
| 679 GetBuilders(setter), | |
| 680 propertyBuilders, | |
| 681 _builders); | |
| 682 | |
| 683 if (IsApplied(BuildElement.VirtualSetter, builders)) | |
| 684 EmitMethod(builders, setter, BuildElement.VirtualSetter); | |
| 685 } | |
| 686 | |
| 687 private void OverrideVirtualMethods() | |
| 688 { | |
| 689 var methods = _context.Type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); | |
| 690 | |
| 691 foreach (var method in methods) | |
| 692 { | |
| 693 if (method.IsVirtual && | |
| 694 method.IsAbstract == false && | |
| 695 method.IsFinal == false && | |
| 696 (method.Attributes & MethodAttributes.SpecialName) == 0 && | |
| 697 method.DeclaringType != typeof(object)) | |
| 698 { | |
| 699 var builders = Combine( | |
| 700 GetBuilders(method.GetParameters()), | |
| 701 GetBuilders(method.ReturnParameter), | |
| 702 GetBuilders(method), | |
| 703 _builders); | |
| 704 | |
| 705 if (IsApplied(BuildElement.VirtualMethod, builders)) | |
| 706 EmitMethod(builders, method, BuildElement.VirtualMethod); | |
| 707 } | |
| 708 } | |
| 709 } | |
| 710 | |
| 711 private void DefineInterfaces() | |
| 712 { | |
| 713 foreach (var de in _context.InterfaceMap) | |
| 714 { | |
| 715 _context.CurrentInterface = de.Key; | |
| 716 | |
| 717 var interfaceMethods = _context.CurrentInterface.GetMethods(); | |
| 718 | |
| 719 foreach (var m in interfaceMethods) | |
| 720 { | |
| 721 if (_context.TypeBuilder.OverriddenMethods.ContainsKey(m)) | |
| 722 continue; | |
| 723 | |
| 724 BeginEmitMethod(m); | |
| 725 | |
| 726 // Call builder to build the method. | |
| 727 // | |
| 728 var builder = de.Value; | |
| 729 | |
| 730 if (builder != null) | |
| 731 { | |
| 732 builder.ID = ++_idCounter; | |
| 733 | |
| 734 _context.BuildElement = BuildElement.InterfaceMethod; | |
| 735 _context.Step = BuildStep.Build; | |
| 736 builder.Build(_context); | |
| 737 } | |
| 738 | |
| 739 EndEmitMethod(); | |
| 740 } | |
| 741 | |
| 742 _context.CurrentInterface = null; | |
| 743 } | |
| 744 } | |
| 745 } | |
| 746 } |
