A game about forced loneliness, made by TACStudios
1using System; 2using System.Collections; 3using System.Collections.Generic; 4using System.Linq; 5using System.Reflection; 6using UnityEngine; 7using UnityObject = UnityEngine.Object; 8 9namespace Unity.VisualScripting 10{ 11 [SerializationVersion("A")] 12 public sealed class Member : ISerializationCallbackReceiver 13 { 14 public enum Source 15 { 16 Unknown, 17 Field, 18 Property, 19 Method, 20 Constructor 21 } 22 23 [Obsolete(Serialization.ConstructorWarning)] 24 public Member() { } 25 26 public Member(Type targetType, string name, Type[] parameterTypes = null) 27 { 28 Ensure.That(nameof(targetType)).IsNotNull(targetType); 29 Ensure.That(nameof(name)).IsNotNull(name); 30 31 if (parameterTypes != null) 32 { 33 for (int i = 0; i < parameterTypes.Length; i++) 34 { 35 if (parameterTypes[i] == null) 36 { 37 throw new ArgumentNullException(nameof(parameterTypes) + $"[{i}]"); 38 } 39 } 40 } 41 42 this.targetType = targetType; 43 this.name = name; 44 this.parameterTypes = parameterTypes; 45 } 46 47 public Member(Type targetType, FieldInfo fieldInfo) 48 { 49 Ensure.That(nameof(targetType)).IsNotNull(targetType); 50 Ensure.That(nameof(fieldInfo)).IsNotNull(fieldInfo); 51 52 source = Source.Field; 53 this.fieldInfo = fieldInfo; 54 this.targetType = targetType; 55 name = fieldInfo.Name; 56 parameterTypes = null; 57 isReflected = true; 58 } 59 60 public Member(Type targetType, PropertyInfo propertyInfo) 61 { 62 Ensure.That(nameof(targetType)).IsNotNull(targetType); 63 Ensure.That(nameof(propertyInfo)).IsNotNull(propertyInfo); 64 65 source = Source.Property; 66 this.propertyInfo = propertyInfo; 67 this.targetType = targetType; 68 name = propertyInfo.Name; 69 parameterTypes = null; 70 isReflected = true; 71 } 72 73 public Member(Type targetType, MethodInfo methodInfo) 74 { 75 Ensure.That(nameof(targetType)).IsNotNull(targetType); 76 Ensure.That(nameof(methodInfo)).IsNotNull(methodInfo); 77 78 source = Source.Method; 79 this.methodInfo = methodInfo; 80 this.targetType = targetType; 81 name = methodInfo.Name; 82 isExtension = methodInfo.IsExtension(); 83 isInvokedAsExtension = methodInfo.IsInvokedAsExtension(targetType); 84 parameterTypes = methodInfo.GetInvocationParameters(_isInvokedAsExtension).Select(pi => pi.ParameterType).ToArray(); 85 isReflected = true; 86 } 87 88 public Member(Type targetType, ConstructorInfo constructorInfo) 89 { 90 Ensure.That(nameof(targetType)).IsNotNull(targetType); 91 Ensure.That(nameof(constructorInfo)).IsNotNull(constructorInfo); 92 93 source = Source.Constructor; 94 this.constructorInfo = constructorInfo; 95 this.targetType = targetType; 96 name = constructorInfo.Name; 97 parameterTypes = constructorInfo.GetParameters().Select(pi => pi.ParameterType).ToArray(); 98 isReflected = true; 99 } 100 101 [SerializeAs(nameof(name))] 102 private string _name; 103 104 [SerializeAs(nameof(parameterTypes))] 105 private Type[] _parameterTypes; 106 107 [SerializeAs(nameof(targetType))] 108 private Type _targetType; 109 110 [SerializeAs(nameof(targetTypeName))] 111 private string _targetTypeName; 112 113 [DoNotSerialize] 114 private Source _source; 115 116 [DoNotSerialize] 117 private FieldInfo _fieldInfo; 118 119 [DoNotSerialize] 120 private PropertyInfo _propertyInfo; 121 122 [DoNotSerialize] 123 private MethodInfo _methodInfo; 124 125 [DoNotSerialize] 126 private ConstructorInfo _constructorInfo; 127 128 [DoNotSerialize] 129 private bool _isExtension; 130 131 [DoNotSerialize] 132 private bool _isInvokedAsExtension; 133 134 [DoNotSerialize] 135 private IOptimizedAccessor fieldAccessor; 136 137 [DoNotSerialize] 138 private IOptimizedAccessor propertyAccessor; 139 140 [DoNotSerialize] 141 private IOptimizedInvoker methodInvoker; 142 143 [DoNotSerialize] 144 public Type targetType 145 { 146 get 147 { 148 return _targetType; 149 } 150 private set 151 { 152 if (value == targetType) 153 { 154 return; 155 } 156 157 isReflected = false; 158 159 _targetType = value; 160 161 if (value == null) 162 { 163 _targetTypeName = null; 164 } 165 else 166 { 167 _targetTypeName = RuntimeCodebase.SerializeType(value); 168 } 169 } 170 } 171 172 [DoNotSerialize] 173 public string targetTypeName => _targetTypeName; 174 175 [DoNotSerialize] 176 public string name 177 { 178 get 179 { 180 return _name; 181 } 182 private set 183 { 184 if (value != name) 185 { 186 isReflected = false; 187 } 188 189 _name = value; 190 } 191 } 192 193 [DoNotSerialize] 194 public bool isReflected { get; private set; } 195 196 [DoNotSerialize] 197 public Source source 198 { 199 get 200 { 201 EnsureReflected(); 202 return _source; 203 } 204 private set 205 { 206 _source = value; 207 } 208 } 209 210 [DoNotSerialize] 211 public FieldInfo fieldInfo 212 { 213 get 214 { 215 EnsureReflected(); 216 return _fieldInfo; 217 } 218 private set 219 { 220 _fieldInfo = value; 221 } 222 } 223 224 [DoNotSerialize] 225 public PropertyInfo propertyInfo 226 { 227 get 228 { 229 EnsureReflected(); 230 return _propertyInfo; 231 } 232 private set 233 { 234 _propertyInfo = value; 235 } 236 } 237 238 [DoNotSerialize] 239 public MethodInfo methodInfo 240 { 241 get 242 { 243 EnsureReflected(); 244 return _methodInfo; 245 } 246 private set 247 { 248 _methodInfo = value; 249 } 250 } 251 252 [DoNotSerialize] 253 public ConstructorInfo constructorInfo 254 { 255 get 256 { 257 EnsureReflected(); 258 return _constructorInfo; 259 } 260 private set 261 { 262 _constructorInfo = value; 263 } 264 } 265 266 [DoNotSerialize] 267 public bool isExtension 268 { 269 get 270 { 271 EnsureReflected(); 272 return _isExtension; 273 } 274 private set 275 { 276 _isExtension = value; 277 } 278 } 279 280 [DoNotSerialize] 281 public bool isInvokedAsExtension 282 { 283 get 284 { 285 EnsureReflected(); 286 return _isInvokedAsExtension; 287 } 288 private set 289 { 290 _isInvokedAsExtension = value; 291 } 292 } 293 294 [DoNotSerialize] 295 public Type[] parameterTypes 296 { 297 get 298 { 299 return _parameterTypes; 300 } 301 private set 302 { 303 _parameterTypes = value; 304 isReflected = false; 305 } 306 } 307 308 public MethodBase methodBase 309 { 310 get 311 { 312 switch (source) 313 { 314 case Source.Method: 315 return methodInfo; 316 case Source.Constructor: 317 return constructorInfo; 318 default: 319 return null; 320 } 321 } 322 } 323 324 private MemberInfo _info 325 { 326 get 327 { 328 switch (source) 329 { 330 case Source.Field: 331 return _fieldInfo; 332 case Source.Property: 333 return _propertyInfo; 334 case Source.Method: 335 return _methodInfo; 336 case Source.Constructor: 337 return _constructorInfo; 338 default: 339 throw new UnexpectedEnumValueException<Source>(source); 340 } 341 } 342 } 343 344 public MemberInfo info 345 { 346 get 347 { 348 switch (source) 349 { 350 case Source.Field: 351 return fieldInfo; 352 case Source.Property: 353 return propertyInfo; 354 case Source.Method: 355 return methodInfo; 356 case Source.Constructor: 357 return constructorInfo; 358 default: 359 throw new UnexpectedEnumValueException<Source>(source); 360 } 361 } 362 } 363 364 public Type type 365 { 366 get 367 { 368 switch (source) 369 { 370 case Source.Field: 371 return fieldInfo.FieldType; 372 case Source.Property: 373 return propertyInfo.PropertyType; 374 case Source.Method: 375 return methodInfo.ReturnType; 376 case Source.Constructor: 377 return constructorInfo.DeclaringType; 378 default: 379 throw new UnexpectedEnumValueException<Source>(source); 380 } 381 } 382 } 383 384 public bool isCoroutine 385 { 386 get 387 { 388 if (!isGettable) 389 { 390 return false; 391 } 392 393 return type == typeof(IEnumerator); 394 } 395 } 396 397 public bool isYieldInstruction 398 { 399 get 400 { 401 if (!isGettable) 402 { 403 return false; 404 } 405 406 return typeof(YieldInstruction).IsAssignableFrom(type); 407 } 408 } 409 410 public bool isGettable => IsGettable(true); 411 public bool isPubliclyGettable => IsGettable(false); 412 413 public bool isSettable => IsSettable(true); 414 public bool isPubliclySettable => IsSettable(false); 415 416 public bool isInvocable => IsInvocable(true); 417 public bool isPubliclyInvocable => IsInvocable(false); 418 419 public bool isAccessor 420 { 421 get 422 { 423 switch (source) 424 { 425 case Source.Field: 426 return true; 427 case Source.Property: 428 return true; 429 case Source.Method: 430 return false; 431 case Source.Constructor: 432 return false; 433 default: 434 throw new UnexpectedEnumValueException<Source>(source); 435 } 436 } 437 } 438 439 public bool isField => source == Source.Field; 440 441 public bool isProperty => source == Source.Property; 442 443 public bool isMethod => source == Source.Method; 444 445 public bool isConstructor => source == Source.Constructor; 446 447 public bool requiresTarget 448 { 449 get 450 { 451 switch (source) 452 { 453 case Source.Field: 454 return !fieldInfo.IsStatic; 455 case Source.Property: 456 return !(propertyInfo.GetGetMethod(true) ?? propertyInfo.GetSetMethod(true)).IsStatic; 457 case Source.Method: 458 return !methodInfo.IsStatic || isInvokedAsExtension; 459 case Source.Constructor: 460 return false; 461 462 default: 463 throw new UnexpectedEnumValueException<Source>(source); 464 } 465 } 466 } 467 468 public bool isOperator => isMethod && methodInfo.IsOperator(); 469 470 public bool isConversion => isMethod && methodInfo.IsUserDefinedConversion(); 471 472 public int order => info.MetadataToken; 473 474 public Type declaringType => info.ExtendedDeclaringType(isInvokedAsExtension); 475 476 public bool isInherited => targetType != declaringType; 477 478 public Type pseudoDeclaringType 479 { 480 get 481 { 482 // For Unity objects, we'll consider parent types to be only root types, 483 // to allow common objects like BoxCollider to show Collider members as self-defined. 484 // We'll also consider them as absolute roots, and therefore none of their members 485 // should display as inherited. 486 487 var declaringType = this.declaringType; 488 489 if (typeof(UnityObject).IsAssignableFrom(targetType)) 490 { 491 if (targetType == typeof(GameObject) || 492 targetType == typeof(Component) || 493 targetType == typeof(ScriptableObject)) 494 { 495 return targetType; 496 } 497 else 498 { 499 if (declaringType != typeof(UnityObject) && 500 declaringType != typeof(GameObject) && 501 declaringType != typeof(Component) && 502 declaringType != typeof(MonoBehaviour) && 503 declaringType != typeof(ScriptableObject) && 504 declaringType != typeof(object)) 505 { 506 return targetType; 507 } 508 } 509 } 510 511 return declaringType; 512 } 513 } 514 515 public bool isPseudoInherited => targetType != pseudoDeclaringType || (isMethod && methodInfo.IsGenericExtension()); 516 517 public bool isIndexer => isProperty && propertyInfo.GetIndexParameters().Length > 0; 518 519 public bool isPredictable => isField || info.HasAttribute<PredictableAttribute>(); 520 521 public bool allowsNull => isSettable && ((type.IsReferenceType() && info.HasAttribute<AllowsNullAttribute>()) || Nullable.GetUnderlyingType(type) != null); 522 523 void ISerializationCallbackReceiver.OnBeforeSerialize() { } 524 525 void ISerializationCallbackReceiver.OnAfterDeserialize() 526 { 527 // Attempt to preserve and restore the target type even if 528 // it wasn't available during an assembly reload. 529 if (targetType != null) 530 { 531 _targetTypeName = RuntimeCodebase.SerializeType(targetType); 532 } 533 else if (_targetTypeName != null) 534 { 535 try 536 { 537 targetType = RuntimeCodebase.DeserializeType(_targetTypeName); 538 } 539 catch { } 540 } 541 } 542 543 public bool IsGettable(bool nonPublic) 544 { 545 switch (source) 546 { 547 case Source.Field: 548 return nonPublic || fieldInfo.IsPublic; 549 case Source.Property: 550 return propertyInfo.CanRead && (nonPublic || propertyInfo.GetGetMethod(false) != null); 551 case Source.Method: 552 return methodInfo.ReturnType != typeof(void) && (nonPublic || methodInfo.IsPublic); 553 case Source.Constructor: 554 return nonPublic || constructorInfo.IsPublic; 555 default: 556 throw new UnexpectedEnumValueException<Source>(source); 557 } 558 } 559 560 public bool IsSettable(bool nonPublic) 561 { 562 switch (source) 563 { 564 case Source.Field: 565 return !(fieldInfo.IsLiteral || fieldInfo.IsInitOnly) && (nonPublic || fieldInfo.IsPublic); 566 case Source.Property: 567 return propertyInfo.CanWrite && (nonPublic || propertyInfo.GetSetMethod(false) != null); 568 case Source.Method: 569 return false; 570 case Source.Constructor: 571 return false; 572 default: 573 throw new UnexpectedEnumValueException<Source>(source); 574 } 575 } 576 577 public bool IsInvocable(bool nonPublic) 578 { 579 switch (source) 580 { 581 case Source.Field: 582 return false; 583 case Source.Property: 584 return false; 585 case Source.Method: 586 return nonPublic || methodInfo.IsPublic; 587 case Source.Constructor: 588 return nonPublic || constructorInfo.IsPublic; 589 default: 590 throw new UnexpectedEnumValueException<Source>(source); 591 } 592 } 593 594 private void EnsureExplicitParameterTypes() 595 { 596 if (parameterTypes == null) 597 { 598 throw new InvalidOperationException("Missing parameter types."); 599 } 600 } 601 602 public void Reflect() 603 { 604 // Cannot happen from the constructor, but will occur 605 // if the type doesn't exist and fails to be deserialized 606 if (targetType == null) 607 { 608 if (targetTypeName != null) 609 { 610 throw new MissingMemberException(targetTypeName, name); 611 } 612 else 613 { 614 throw new MissingMemberException("Target type not found."); 615 } 616 } 617 618 _source = Source.Unknown; 619 620 _fieldInfo = null; 621 _propertyInfo = null; 622 _methodInfo = null; 623 _constructorInfo = null; 624 625 fieldAccessor = null; 626 propertyAccessor = null; 627 methodInvoker = null; 628 629 MemberInfo[] candidates; 630 try 631 { 632 candidates = targetType.GetExtendedMember(name, SupportedMemberTypes, SupportedBindingFlags); 633 } 634 catch (NotSupportedException e) 635 { 636 throw new InvalidOperationException($"An error occured when trying to reflect the member '{name}' of the type '{targetType.FullName}' in a '{GetType().Name}' unit. Supported member types: {SupportedMemberTypes}, supported binding flags: {SupportedBindingFlags}", e); 637 } 638 639 if (candidates.Length == 0) // Not found, check if it might have been renamed 640 { 641 var renamedMembers = RuntimeCodebase.RenamedMembers(targetType); 642 643 string newName; 644 645 if (renamedMembers.TryGetValue(name, out newName)) 646 { 647 name = newName; 648 649 try 650 { 651 candidates = targetType.GetExtendedMember(name, SupportedMemberTypes, SupportedBindingFlags); 652 } 653 catch (NotSupportedException e) 654 { 655 throw new InvalidOperationException($"An error occured when trying to reflect the renamed member '{name}' of the type '{targetType.FullName}' in a '{GetType().Name}' unit. Supported member types: {SupportedMemberTypes}, supported binding flags: {SupportedBindingFlags}", e); 656 } 657 } 658 } 659 660 if (candidates.Length == 0) // Nope, not even, abort 661 { 662 throw new MissingMemberException($"No matching member found: '{targetType.Name}.{name}'"); 663 } 664 665 MemberTypes? memberType = null; 666 667 foreach (var candidate in candidates) 668 { 669 if (memberType == null) 670 { 671 memberType = candidate.MemberType; 672 } 673 else if (candidate.MemberType != memberType && !candidate.IsExtensionMethod()) 674 { 675 // This theoretically shouldn't happen according to the .NET specification, I believe 676 Debug.LogWarning($"Multiple members with the same name are of a different type: '{targetType.Name}.{name}'"); 677 break; 678 } 679 } 680 681 switch (memberType) 682 { 683 case MemberTypes.Field: 684 ReflectField(candidates); 685 break; 686 687 case MemberTypes.Property: 688 ReflectProperty(candidates); 689 break; 690 691 case MemberTypes.Method: 692 ReflectMethod(candidates); 693 break; 694 695 case MemberTypes.Constructor: 696 ReflectConstructor(candidates); 697 break; 698 699 default: 700 throw new UnexpectedEnumValueException<MemberTypes>(memberType.Value); 701 } 702 703 isReflected = true; 704 } 705 706 private void ReflectField(IEnumerable<MemberInfo> candidates) 707 { 708 _source = Source.Field; 709 710 _fieldInfo = candidates.OfType<FieldInfo>().Disambiguate(targetType); 711 712 if (_fieldInfo == null) 713 { 714 throw new MissingMemberException($"No matching field found: '{targetType.Name}.{name}'"); 715 } 716 } 717 718 private void ReflectProperty(IEnumerable<MemberInfo> candidates) 719 { 720 _source = Source.Property; 721 722 _propertyInfo = candidates.OfType<PropertyInfo>().Disambiguate(targetType); 723 724 if (_propertyInfo == null) 725 { 726 throw new MissingMemberException($"No matching property found: '{targetType.Name}.{name}'"); 727 } 728 } 729 730 private void ReflectConstructor(IEnumerable<MemberInfo> candidates) 731 { 732 _source = Source.Constructor; 733 734 EnsureExplicitParameterTypes(); 735 736 // Exclude static constructors (type initializers) because calling them 737 // is always a violation of types expecting it to be called only once. 738 // http://stackoverflow.com/a/2524938 739 _constructorInfo = candidates.OfType<ConstructorInfo>().Where(c => !c.IsStatic).Disambiguate(targetType, parameterTypes); 740 741 if (_constructorInfo == null) 742 { 743 throw new MissingMemberException($"No matching constructor found: '{targetType.Name} ({parameterTypes.Select(t => t.Name).ToCommaSeparatedString()})'"); 744 } 745 } 746 747 private void ReflectMethod(IEnumerable<MemberInfo> candidates) 748 { 749 _source = Source.Method; 750 751 EnsureExplicitParameterTypes(); 752 753 _methodInfo = candidates.OfType<MethodInfo>().Disambiguate(targetType, parameterTypes); 754 755 if (_methodInfo == null) 756 { 757 throw new MissingMemberException($"No matching method found: '{targetType.Name}.{name} ({parameterTypes.Select(t => t.Name).ToCommaSeparatedString()})'\nCandidates:\n{candidates.ToLineSeparatedString()}"); 758 } 759 760 _isExtension = _methodInfo.IsExtension(); 761 _isInvokedAsExtension = _methodInfo.IsInvokedAsExtension(targetType); 762 } 763 764 public void Prewarm() 765 { 766 if (fieldAccessor == null) 767 { 768 fieldAccessor = fieldInfo?.Prewarm(); 769 } 770 771 if (propertyAccessor == null) 772 { 773 propertyAccessor = propertyInfo?.Prewarm(); 774 } 775 776 if (methodInvoker == null) 777 { 778 methodInvoker = methodInfo?.Prewarm(); 779 } 780 } 781 782 public void EnsureReflected() 783 { 784 if (!isReflected) 785 { 786 Reflect(); 787 } 788 } 789 790 public void EnsureReady(object target) 791 { 792 EnsureReflected(); 793 794 if (target == null && requiresTarget) 795 { 796 throw new InvalidOperationException($"Missing target object for '{targetType}.{name}'."); 797 } 798 else if (target != null && !requiresTarget) 799 { 800 throw new InvalidOperationException($"Superfluous target object for '{targetType}.{name}'."); 801 } 802 } 803 804 public object Get(object target) 805 { 806 EnsureReady(target); 807 808 switch (source) 809 { 810 case Source.Field: 811 if (fieldAccessor == null) 812 { 813 fieldAccessor = fieldInfo.Prewarm(); 814 } 815 816 return fieldAccessor.GetValue(target); 817 818 case Source.Property: 819 if (propertyAccessor == null) 820 { 821 propertyAccessor = propertyInfo.Prewarm(); 822 } 823 824 return propertyAccessor.GetValue(target); 825 826 case Source.Method: 827 throw new NotSupportedException("Member is a method. Consider using 'Invoke' instead."); 828 case Source.Constructor: 829 throw new NotSupportedException("Member is a constructor. Consider using 'Invoke' instead."); 830 default: 831 throw new UnexpectedEnumValueException<Source>(source); 832 } 833 } 834 835 public T Get<T>(object target) 836 { 837 return (T)Get(target); 838 } 839 840 public object Set(object target, object value) 841 { 842 EnsureReady(target); 843 844 // When setting, we return the assigned value, not the updated field or property. 845 // This is consistent with C# language behaviour: https://msdn.microsoft.com/en-us/library/sbkb459w.aspx 846 // "The assignment operator (=) [...] returns the value as its result" 847 // See confirmation here: https://dotnetfiddle.net/n4RZcW 848 849 switch (source) 850 { 851 case Source.Field: 852 if (fieldAccessor == null) 853 { 854 fieldAccessor = fieldInfo.Prewarm(); 855 } 856 857 fieldAccessor.SetValue(target, value); 858 return value; 859 860 case Source.Property: 861 if (propertyAccessor == null) 862 { 863 propertyAccessor = propertyInfo.Prewarm(); 864 } 865 866 propertyAccessor.SetValue(target, value); 867 return value; 868 869 case Source.Method: 870 throw new NotSupportedException("Member is a method."); 871 case Source.Constructor: 872 throw new NotSupportedException("Member is a constructor."); 873 default: 874 throw new UnexpectedEnumValueException<Source>(source); 875 } 876 } 877 878 private void EnsureInvocable(object target) 879 { 880 EnsureReady(target); 881 882 if (source == Source.Field || source == Source.Property) 883 { 884 throw new NotSupportedException("Member is a field or property."); 885 } 886 else if (source == Source.Method) 887 { 888 if (methodInfo.ContainsGenericParameters) 889 { 890 throw new NotSupportedException($"Trying to invoke an open-constructed generic method: '{methodInfo}'."); 891 } 892 893 if (methodInvoker == null) 894 { 895 methodInvoker = methodInfo.Prewarm(); 896 } 897 } 898 else if (source == Source.Constructor) 899 { 900 if (constructorInfo.ContainsGenericParameters) 901 { 902 throw new NotSupportedException($"Trying to invoke an open-constructed generic constructor: '{constructorInfo}'."); 903 } 904 } 905 else 906 { 907 throw new UnexpectedEnumValueException<Source>(source); 908 } 909 } 910 911 public IEnumerable<ParameterInfo> GetParameterInfos() 912 { 913 EnsureReflected(); 914 915 return methodBase.GetInvocationParameters(isInvokedAsExtension); 916 } 917 918 public object Invoke(object target) 919 { 920 EnsureInvocable(target); 921 922 if (source == Source.Method) 923 { 924 if (isInvokedAsExtension) 925 { 926 return methodInvoker.Invoke(null, target); 927 } 928 else 929 { 930 return methodInvoker.Invoke(target); 931 } 932 } 933 else // if (source == Source.Constructor) 934 { 935 return constructorInfo.Invoke(EmptyObjects); 936 } 937 } 938 939 public object Invoke(object target, object arg0) 940 { 941 EnsureInvocable(target); 942 943 if (source == Source.Method) 944 { 945 if (isInvokedAsExtension) 946 { 947 return methodInvoker.Invoke(null, target, arg0); 948 } 949 else 950 { 951 return methodInvoker.Invoke(target, arg0); 952 } 953 } 954 else // if (source == Source.Constructor) 955 { 956 return constructorInfo.Invoke(new[] { arg0 }); 957 } 958 } 959 960 public object Invoke(object target, object arg0, object arg1) 961 { 962 EnsureInvocable(target); 963 964 if (source == Source.Method) 965 { 966 if (isInvokedAsExtension) 967 { 968 return methodInvoker.Invoke(null, target, arg0, arg1); 969 } 970 else 971 { 972 return methodInvoker.Invoke(target, arg0, arg1); 973 } 974 } 975 else // if (source == Source.Constructor) 976 { 977 return constructorInfo.Invoke(new[] { arg0, arg1 }); 978 } 979 } 980 981 public object Invoke(object target, object arg0, object arg1, object arg2) 982 { 983 EnsureInvocable(target); 984 985 if (source == Source.Method) 986 { 987 if (isInvokedAsExtension) 988 { 989 return methodInvoker.Invoke(null, target, arg0, arg1, arg2); 990 } 991 else 992 { 993 return methodInvoker.Invoke(target, arg0, arg1, arg2); 994 } 995 } 996 else // if (source == Source.Constructor) 997 { 998 return constructorInfo.Invoke(new[] { arg0, arg1, arg2 }); 999 } 1000 } 1001 1002 public object Invoke(object target, object arg0, object arg1, object arg2, object arg3) 1003 { 1004 EnsureInvocable(target); 1005 1006 if (source == Source.Method) 1007 { 1008 if (isInvokedAsExtension) 1009 { 1010 return methodInvoker.Invoke(null, target, arg0, arg1, arg2, arg3); 1011 } 1012 else 1013 { 1014 return methodInvoker.Invoke(target, arg0, arg1, arg2, arg3); 1015 } 1016 } 1017 else // if (source == Source.Constructor) 1018 { 1019 return constructorInfo.Invoke(new[] { arg0, arg1, arg2, arg3 }); 1020 } 1021 } 1022 1023 public object Invoke(object target, object arg0, object arg1, object arg2, object arg3, object arg4) 1024 { 1025 EnsureInvocable(target); 1026 1027 if (source == Source.Method) 1028 { 1029 if (isInvokedAsExtension) 1030 { 1031 return methodInvoker.Invoke(null, target, arg0, arg1, arg2, arg3, arg4); 1032 } 1033 else 1034 { 1035 return methodInvoker.Invoke(target, arg0, arg1, arg2, arg3, arg4); 1036 } 1037 } 1038 else // if (source == Source.Constructor) 1039 { 1040 return constructorInfo.Invoke(new[] { arg0, arg1, arg2, arg3, arg4 }); 1041 } 1042 } 1043 1044 public object Invoke(object target, params object[] arguments) 1045 { 1046 EnsureInvocable(target); 1047 1048 if (source == Source.Method) 1049 { 1050 if (isInvokedAsExtension) 1051 { 1052 var argumentsWithThis = new object[arguments.Length + 1]; 1053 argumentsWithThis[0] = target; 1054 Array.Copy(arguments, 0, argumentsWithThis, 1, arguments.Length); 1055 return methodInvoker.Invoke(null, argumentsWithThis); 1056 } 1057 else 1058 { 1059 return methodInvoker.Invoke(target, arguments); 1060 } 1061 } 1062 else // if (source == Source.Constructor) 1063 { 1064 return constructorInfo.Invoke(arguments); 1065 } 1066 } 1067 1068 public T Invoke<T>(object target) 1069 { 1070 return (T)Invoke(target); 1071 } 1072 1073 public T Invoke<T>(object target, object arg0) 1074 { 1075 return (T)Invoke(target, arg0); 1076 } 1077 1078 public T Invoke<T>(object target, object arg0, object arg1) 1079 { 1080 return (T)Invoke(target, arg0, arg1); 1081 } 1082 1083 public T Invoke<T>(object target, object arg0, object arg1, object arg2) 1084 { 1085 return (T)Invoke(target, arg0, arg1, arg2); 1086 } 1087 1088 public T Invoke<T>(object target, object arg0, object arg1, object arg2, object arg3) 1089 { 1090 return (T)Invoke(target, arg0, arg1, arg2, arg3); 1091 } 1092 1093 public T Invoke<T>(object target, object arg0, object arg1, object arg2, object arg3, object arg4) 1094 { 1095 return (T)Invoke(target, arg0, arg1, arg2, arg3, arg4); 1096 } 1097 1098 public T Invoke<T>(object target, params object[] arguments) 1099 { 1100 return (T)Invoke(target, arguments); 1101 } 1102 1103 public override bool Equals(object obj) 1104 { 1105 var other = obj as Member; 1106 1107 var equals = other != null && 1108 targetType == other.targetType && 1109 name == other.name; 1110 1111 if (!equals) 1112 { 1113 return false; 1114 } 1115 1116 var selfHasParameters = parameterTypes != null; 1117 var otherHasParameters = other.parameterTypes != null; 1118 1119 if (selfHasParameters != otherHasParameters) 1120 { 1121 return false; 1122 } 1123 1124 if (selfHasParameters /* && otherHasParameters */) 1125 { 1126 var selfCount = parameterTypes.Length; 1127 var otherCount = other.parameterTypes.Length; 1128 1129 if (selfCount != otherCount) 1130 { 1131 return false; 1132 } 1133 1134 for (var i = 0; i < selfCount; i++) 1135 { 1136 if (parameterTypes[i] != other.parameterTypes[i]) 1137 { 1138 return false; 1139 } 1140 } 1141 } 1142 1143 return true; 1144 } 1145 1146 public override int GetHashCode() 1147 { 1148 unchecked 1149 { 1150 var hash = 17; 1151 1152 hash = hash * 23 + (targetType?.GetHashCode() ?? 0); 1153 hash = hash * 23 + (name?.GetHashCode() ?? 0); 1154 1155 if (parameterTypes != null) 1156 { 1157 foreach (var parameterType in parameterTypes) 1158 { 1159 hash = hash * 23 + parameterType.GetHashCode(); 1160 } 1161 } 1162 else 1163 { 1164 hash = hash * 23 + 0; 1165 } 1166 1167 return hash; 1168 } 1169 } 1170 1171 public static bool operator ==(Member a, Member b) 1172 { 1173 if (ReferenceEquals(a, b)) 1174 { 1175 return true; 1176 } 1177 1178 if (ReferenceEquals(a, null) || ReferenceEquals(b, null)) 1179 { 1180 return false; 1181 } 1182 1183 return a.Equals(b); 1184 } 1185 1186 public static bool operator !=(Member a, Member b) 1187 { 1188 return !(a == b); 1189 } 1190 1191 public string ToUniqueString() 1192 { 1193 var s = targetType.FullName + "." + this.name; 1194 1195 if (parameterTypes != null) 1196 { 1197 s += "("; 1198 1199 foreach (var parameterType in parameterTypes) 1200 { 1201 s += parameterType.FullName; 1202 } 1203 1204 s += ")"; 1205 } 1206 1207 return s; 1208 } 1209 1210 public override string ToString() 1211 { 1212 return $"{targetType.CSharpName()}.{name}"; 1213 } 1214 1215 public Member ToDeclarer() 1216 { 1217 return new Member(declaringType, name, parameterTypes); 1218 } 1219 1220 public Member ToPseudoDeclarer() 1221 { 1222 return new Member(pseudoDeclaringType, name, parameterTypes); 1223 } 1224 1225 public const MemberTypes SupportedMemberTypes = MemberTypes.Property | MemberTypes.Field | MemberTypes.Method | MemberTypes.Constructor; 1226 1227 public const BindingFlags SupportedBindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.FlattenHierarchy; 1228 1229 private static readonly object[] EmptyObjects = new object[0]; 1230 } 1231}