You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Reflection takes too much time to set or get the properties if the property info is not cached. Even if it's cached it still some imapct or its slower than it should be.
11
+
A few years back I had to write a base view model which is not aware of the model that will be used with it as generic. Only thing that the base view model knows is that every model will definitely have a `Name` property. And I had to write all the logic to set the properties of this Model in the base only as it was common and we used to receive the property name(string) and value(object) from SignalR. I used reflection as I am not aware of the properties of Model's used in child view models. Slowly as the number of child viewmodels increased and the list of object's(Model's) inside each child view model, I started seeing the problem. Then I clearly understood that reflection is the major reason for the performance issue.
13
12
14
-
## Solution:
15
13
16
-
```c#
14
+
Then after some thorough research, I did some benchmarks to see how much does reflection cost me vs using an interface and implementing those methods in every model and making it strongly typed and avoiding reflection.
15
+
16
+
## Version 1:
17
+
18
+
I wrote a new simple interface.
19
+
20
+
```csharp
17
21
publicinterfaceIObject
18
22
{
19
23
boolSetValue(stringpropertyName, objectvalue);
20
24
objectGetValue(stringpropertyName);
25
+
TGetValue<T>(stringpropertyName); // I skipped the implementation of this in this post. Please find that in source code.
The benchmarks have proven that this simple interfacec is able to save me at least 80% of the performance cost.
68
+
When I did the benchmarks for setting a value using reflection, I saw using an interface brought down the time taken to set a property to a min of 70% and max of 91%.
As this worked out very well, and I had too many model's so I built our own source generator using a console app as I was using .NET6 where the source generators are still experimental. And this whole implementation brought down our app launch time from 60+ seconds to less than 20 seconds. Btw, the properties inside the Model used to change very rarely. So when they did, we used to run the generator again and copy the files. And we ensure these generated files should never be changed manually and named them something like Foo.g.cs which helps me review the PR's easily from the team. And ofcourse, I wrote an API to return the properties and their metadata in the way that I need so that my generator can generate the classes for me.
76
+
77
+
78
+
## Version 2: (Update on 16th March 2025)
79
+
80
+
I read in multiple blogs that .NET invested a lot in performance improvement using ReadOnlySpan over the years. I was wondering if we can still make this better. So I tried again with ChatGPT help. Now compared to V1, V2 had at least 40% improvement over V1.
81
+
82
+
I renamed the interface like
83
+
84
+
```csharp
85
+
publicinterfaceINoReflection
86
+
{
87
+
boolSetValue(stringpropertyName, objectvalue);
88
+
objectGetValue(stringpropertyName);
89
+
TGetValue<T>(stringpropertyName); // I skipped the implementation of this in this post. Please find that in source code.
90
+
}
91
+
```
92
+
93
+
Nothing changed in my interface. But the implementation changed a bit.
94
+
95
+
```csharp
96
+
[TypedAccessorAttribute]
97
+
publicpartialclassFoo
98
+
{
99
+
publicintInteger { get; set; } =int.MaxValue;
100
+
publicstringString { get; set; } ="some random string";
101
+
102
+
}
103
+
```
104
+
105
+
Notice the `TypedAccessorAttribute` on top of class. And yes this time I used Incremental Source Generators as they are stable.
As I said, I took ChatGPT help, I am not 100% sure how `MethodImpl` helps. But this code brought down time taken to set a property from V1 to a min of 40% and max of 55%.
These results show that IOBject is at least 80% faster.
158
+
This is one of my best performance improvements I have ever done. This might not be significant in many places but for situations like mine, this saves a lot of time during run time.
0 commit comments