@@ -64,18 +64,7 @@ protected override void OnParametersSet()
64
64
65
65
if ( ! string . IsNullOrEmpty ( Format ) )
66
66
{
67
- // TODO: Consider using reflection to avoid having to box every value just to call IFormattable.ToString
68
- // For example, define a method "string Type<U>(Func<TGridItem, U> property) where U: IFormattable", and
69
- // then construct the closed type here with U=TProp when we know TProp implements IFormattable
70
-
71
- // If the type is nullable, we're interested in formatting the underlying type
72
- var nullableUnderlyingTypeOrNull = Nullable . GetUnderlyingType ( typeof ( TProp ) ) ;
73
- if ( ! typeof ( IFormattable ) . IsAssignableFrom ( nullableUnderlyingTypeOrNull ?? typeof ( TProp ) ) )
74
- {
75
- throw new InvalidOperationException ( $ "A '{ nameof ( Format ) } ' parameter was supplied, but the type '{ typeof ( TProp ) } ' does not implement '{ typeof ( IFormattable ) } '.") ;
76
- }
77
-
78
- _cellTextFunc = item => ( ( IFormattable ? ) compiledPropertyExpression ! ( item ) ) ? . ToString ( Format , null ) ;
67
+ _cellTextFunc = CreateFormatter ( compiledPropertyExpression , Format ) ;
79
68
}
80
69
else
81
70
{
@@ -87,10 +76,8 @@ protected override void OnParametersSet()
87
76
{
88
77
return ( value as Enum ) ? . GetDisplayName ( ) ;
89
78
}
90
- else
91
- {
92
- return value ? . ToString ( ) ;
93
- }
79
+
80
+ return value ? . ToString ( ) ;
94
81
} ;
95
82
}
96
83
if ( Sortable . HasValue )
@@ -118,6 +105,62 @@ protected override void OnParametersSet()
118
105
}
119
106
}
120
107
108
+ private static Func < TGridItem , string ? > CreateFormatter (
109
+ Func < TGridItem , TProp > getter , string format )
110
+ {
111
+ var closedType = typeof ( PropertyColumn < , > ) . MakeGenericType ( typeof ( TGridItem ) , typeof ( TProp ) ) ;
112
+
113
+ //Nullable struct
114
+ if ( Nullable . GetUnderlyingType ( typeof ( TProp ) ) is Type underlying &&
115
+ typeof ( IFormattable ) . IsAssignableFrom ( underlying ) )
116
+ {
117
+ var method = closedType
118
+ . GetMethod ( nameof ( CreateNullableValueTypeFormatter ) , BindingFlags . NonPublic | BindingFlags . Static ) !
119
+ . MakeGenericMethod ( underlying ) ;
120
+ return ( Func < TGridItem , string ? > ) method . Invoke ( null , [ getter , format ] ) ! ;
121
+ }
122
+
123
+
124
+ if ( typeof ( IFormattable ) . IsAssignableFrom ( typeof ( TProp ) ) )
125
+ {
126
+ //Struct
127
+ if ( typeof ( TProp ) . IsValueType )
128
+ {
129
+ var method = closedType
130
+ . GetMethod ( nameof ( CreateValueTypeFormatter ) , BindingFlags . NonPublic | BindingFlags . Static ) !
131
+ . MakeGenericMethod ( typeof ( TProp ) ) ;
132
+ return ( Func < TGridItem , string ? > ) method . Invoke ( null , [ getter , format ] ) ! ;
133
+ }
134
+ else
135
+ {
136
+ return CreateReferenceTypeFormatter ( ( Func < TGridItem , IFormattable ? > ) ( object ) getter , format ) ;
137
+ }
138
+ }
139
+
140
+ throw new InvalidOperationException ( $ "A '{ nameof ( Format ) } ' parameter was supplied, but the type '{ typeof ( TProp ) } ' does not implement '{ typeof ( IFormattable ) } '.") ;
141
+ }
142
+
143
+ private static Func < TGridItem , string ? > CreateReferenceTypeFormatter < T > (
144
+ Func < TGridItem , T ? > getter , string format )
145
+ where T : class , IFormattable
146
+ {
147
+ return item => getter ( item ) ? . ToString ( format , null ) ;
148
+ }
149
+
150
+ private static Func < TGridItem , string ? > CreateValueTypeFormatter < T > (
151
+ Func < TGridItem , T > getter , string format )
152
+ where T : struct , IFormattable
153
+ {
154
+ return item => getter ( item ) . ToString ( format , null ) ;
155
+ }
156
+
157
+ private static Func < TGridItem , string ? > CreateNullableValueTypeFormatter < T > (
158
+ Func < TGridItem , T ? > getter , string format )
159
+ where T : struct , IFormattable
160
+ {
161
+ return item => getter ( item ) ? . ToString ( format , null ) ;
162
+ }
163
+
121
164
/// <inheritdoc />
122
165
protected internal override void CellContent ( RenderTreeBuilder builder , TGridItem item )
123
166
=> builder . AddContent ( 0 , _cellTextFunc ? . Invoke ( item ) ) ;
0 commit comments