@@ -60,6 +60,8 @@ public sealed class ViewModelInjector
60
60
private readonly TypeReference propertyChangingEventHandlerType ;
61
61
private readonly TypeReference propertyChangedEventHandlerType ;
62
62
63
+ private readonly TypeDefinition ? wellExtensionType ;
64
+
63
65
private readonly MethodDefinition addPropertyChanging ;
64
66
private readonly MethodDefinition removePropertyChanging ;
65
67
private readonly MethodDefinition addPropertyChanged ;
@@ -81,6 +83,9 @@ public sealed class ViewModelInjector
81
83
private readonly MethodDefinition itAddPropertyChanged ;
82
84
private readonly MethodDefinition itRemovePropertyChanged ;
83
85
86
+ private readonly MethodDefinition ? wellAddMethod ;
87
+ private readonly MethodDefinition ? wellAddTEventArgsMethod ;
88
+
84
89
public ViewModelInjector ( string [ ] referencesBasePath , Action < LogLevels , string > message )
85
90
{
86
91
this . message = message ;
@@ -102,6 +107,18 @@ public ViewModelInjector(string[] referencesBasePath, Action<LogLevels, string>
102
107
}
103
108
) ;
104
109
110
+ var epoxyPath = referencesBasePath .
111
+ Select ( basePath => Path . Combine ( basePath , "Epoxy.dll" ) ) .
112
+ First ( File . Exists ) ;
113
+
114
+ var epoxyAssembly = AssemblyDefinition . ReadAssembly (
115
+ epoxyPath ,
116
+ new ReaderParameters
117
+ {
118
+ AssemblyResolver = assemblyResolver ,
119
+ }
120
+ ) ;
121
+
105
122
var fsharpEpoxyPath = referencesBasePath .
106
123
Select ( basePath => Path . Combine ( basePath , "FSharp.Epoxy.dll" ) ) .
107
124
FirstOrDefault ( File . Exists ) ;
@@ -118,6 +135,12 @@ public ViewModelInjector(string[] referencesBasePath, Action<LogLevels, string>
118
135
this . message (
119
136
LogLevels . Trace ,
120
137
$ "Epoxy.Core.dll is loaded: Path={ epoxyCorePath } ") ;
138
+ if ( epoxyAssembly != null )
139
+ {
140
+ this . message (
141
+ LogLevels . Trace ,
142
+ $ "Epoxy.dll is loaded: Path={ epoxyPath } ") ;
143
+ }
121
144
if ( fsharpEpoxyAssembly != null )
122
145
{
123
146
this . message (
@@ -150,6 +173,9 @@ public ViewModelInjector(string[] referencesBasePath, Action<LogLevels, string>
150
173
this . propertyChangedFSharpAsyncDelegateTypeT = fsharpEpoxyAssembly ? . MainModule . GetType (
151
174
"Epoxy.Internal.PropertyChangedFSharpAsyncDelegate`1" ) ! ;
152
175
176
+ this . wellExtensionType = epoxyAssembly ? . MainModule . GetType (
177
+ "Epoxy.WellExtension" ) ! ;
178
+
153
179
this . propertyChangingEventHandlerType = internalPropertyBagType . Fields .
154
180
First ( f => f . Name == "propertyChanging" ) . FieldType ;
155
181
this . propertyChangedEventHandlerType = internalPropertyBagType . Fields .
@@ -196,6 +222,11 @@ public ViewModelInjector(string[] referencesBasePath, Action<LogLevels, string>
196
222
First ( ) . AddMethod ;
197
223
this . itRemovePropertyChanged = itPropertyChangedType . Events .
198
224
First ( ) . RemoveMethod ;
225
+
226
+ this . wellAddMethod = this . wellExtensionType ? . Methods .
227
+ First ( m => m . IsStatic && m . GenericParameters . Count == 1 && m . Name == "Add" && m . Parameters . Count == 5 ) ;
228
+ this . wellAddTEventArgsMethod = this . wellExtensionType ? . Methods .
229
+ First ( m => m . IsStatic && m . GenericParameters . Count == 2 && m . Name == "Add" && m . Parameters . Count == 5 ) ;
199
230
}
200
231
201
232
private void InjectPropertyChangeEvents (
@@ -715,6 +746,104 @@ private static void ReplaceFieldToAccessor(
715
746
}
716
747
}
717
748
749
+ private static void ForEach < T > (
750
+ IEnumerable < T > enumerable ,
751
+ Action < T > action )
752
+ {
753
+ foreach ( var item in enumerable )
754
+ {
755
+ action ( item ) ;
756
+ }
757
+ }
758
+
759
+ private static bool ReplaceAddWell (
760
+ ModuleDefinition module )
761
+ {
762
+ var updatingActions = new Queue < Stack < Action > > ( ) ;
763
+
764
+ // Enabled parallel processing with delayed updating
765
+ // when processes all CIL body streams.
766
+ //Parallel.ForEach(
767
+ ForEach (
768
+ module . GetTypes ( ) .
769
+ Where ( td => td . IsClass ) ,
770
+ td =>
771
+ {
772
+ foreach ( var md in td . Methods .
773
+ Where ( md => ! md . IsAbstract && md . HasBody ) )
774
+ {
775
+ // (Have to make reverse order)
776
+ var actions = new Stack < Action > ( ) ;
777
+
778
+ var instructions = md . Body . Instructions ;
779
+ for ( var index = 0 ; index < instructions . Count ; index ++ )
780
+ {
781
+ // public static void Add<TEventArgs>(this Well well, string eventName, Func<TEventArgs, ValueTask> action)
782
+ // public static void Add(this Well well, string eventName, Func<ValueTask> action)
783
+ var inst = instructions [ index ] ;
784
+ if ( inst . OpCode == OpCodes . Call &&
785
+ inst . Operand is MethodReference tmr &&
786
+ ! tmr . HasThis &&
787
+ tmr . DeclaringType . FullName == "Epoxy.WellExtension" &&
788
+ tmr . Name == "Add" &&
789
+ tmr . Parameters . Count == 3 &&
790
+ tmr . Parameters [ 0 ] . ParameterType . FullName == "Epoxy.Well" &&
791
+ tmr . Parameters [ 1 ] . ParameterType . FullName == "System.String" &&
792
+ tmr . Parameters [ 2 ] . ParameterType . Name . StartsWith ( "Func" ) )
793
+ {
794
+ // Makes delayed processing for application.
795
+ var capturedIndex = index ;
796
+ actions . Push ( ( ) =>
797
+ {
798
+ var tmd = tmr . Resolve ( ) ;
799
+ if ( tmd . IsPublic && tmd . IsStatic &&
800
+ tmd . CustomAttributes . Any ( ca => ca . AttributeType . FullName == "System.Runtime.CompilerServices.ExtensionAttribute" ) )
801
+ {
802
+ switch ( tmd . GenericParameters . Count )
803
+ {
804
+ case 0 :
805
+ case 1 :
806
+ //md.Body.Instructions.Insert(capturedIndex++,
807
+ // Instruction.Create(OpCodes.Call,
808
+ // module.ImportReference(accessor.Getter)));
809
+ break ;
810
+ }
811
+ }
812
+ } ) ;
813
+ }
814
+ }
815
+
816
+ if ( actions . Count >= 1 )
817
+ {
818
+ lock ( updatingActions )
819
+ {
820
+ updatingActions . Enqueue ( actions ) ;
821
+ }
822
+ }
823
+ }
824
+ } ) ;
825
+
826
+ if ( updatingActions . Count >= 1 )
827
+ {
828
+ // Updates sequentially (on this thread).
829
+ do
830
+ {
831
+ var actions = updatingActions . Dequeue ( ) ;
832
+ while ( actions . Count >= 1 )
833
+ {
834
+ var action = actions . Pop ( ) ;
835
+ action ( ) ;
836
+ }
837
+ }
838
+ while ( updatingActions . Count >= 1 ) ;
839
+ return true ;
840
+ }
841
+ else
842
+ {
843
+ return false ;
844
+ }
845
+ }
846
+
718
847
public bool Inject ( string targetAssemblyPath , string ? injectedAssemblyPath = null )
719
848
{
720
849
this . assemblyResolver . AddSearchDirectory (
@@ -749,11 +878,10 @@ public bool Inject(string targetAssemblyPath, string? injectedAssemblyPath = nul
749
878
! td . Interfaces . Any ( ii => ii . InterfaceType . FullName == this . iViewModelImplementerType . FullName ) ) .
750
879
ToArray ( ) ;
751
880
881
+ var injected = false ;
882
+ var removedAccessor = new Dictionary < FieldDefinition , AccessorInformation > ( ) ;
752
883
if ( targetTypes . Length >= 1 )
753
884
{
754
- var injected = false ;
755
- var removedAccessor = new Dictionary < FieldDefinition , AccessorInformation > ( ) ;
756
-
757
885
foreach ( var targetType in targetTypes )
758
886
{
759
887
if ( this . InjectIntoType ( targetAssembly . MainModule , targetType , out var rfs ) )
@@ -776,23 +904,28 @@ public bool Inject(string targetAssemblyPath, string? injectedAssemblyPath = nul
776
904
$ "InjectProperties: Ignored a type: Assembly={ targetAssemblyName } , Type={ targetType . FullName } ") ;
777
905
}
778
906
}
907
+ }
779
908
780
- if ( injected )
781
- {
782
- var module = targetAssembly . MainModule ;
783
- ReplaceFieldToAccessor ( module , removedAccessor ) ;
909
+ var module = targetAssembly . MainModule ;
910
+ if ( ReplaceAddWell ( module ) )
911
+ {
912
+ injected = true ;
913
+ }
914
+
915
+ if ( injected )
916
+ {
917
+ ReplaceFieldToAccessor ( module , removedAccessor ) ;
784
918
785
- injectedAssemblyPath = injectedAssemblyPath ?? targetAssemblyPath ;
919
+ injectedAssemblyPath = injectedAssemblyPath ?? targetAssemblyPath ;
786
920
787
- targetAssembly . Write (
788
- injectedAssemblyPath ,
789
- new WriterParameters
790
- {
791
- WriteSymbols = true ,
792
- DeterministicMvid = true ,
793
- } ) ;
794
- return true ;
795
- }
921
+ targetAssembly . Write (
922
+ injectedAssemblyPath ,
923
+ new WriterParameters
924
+ {
925
+ WriteSymbols = true ,
926
+ DeterministicMvid = true ,
927
+ } ) ;
928
+ return true ;
796
929
}
797
930
}
798
931
0 commit comments