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}