1- using System ;
2- using System . Collections . Generic ;
31using System . Diagnostics . CodeAnalysis ;
2+ using System . Text ;
43
54using EntityFrameworkCore . Generator . Metadata . Generation ;
65
7- using static System . Net . Mime . MediaTypeNames ;
8-
96namespace EntityFrameworkCore . Generator . Extensions ;
107
118public static class GenerationExtensions
@@ -24,52 +21,30 @@ public static class GenerationExtensions
2421 "__refvalue" , "stackalloc"
2522 } ;
2623
27- private static readonly HashSet < string > _visualBasicKeywords = new ( StringComparer . OrdinalIgnoreCase )
28- {
29- "as" , "do" , "if" , "in" , "is" , "me" , "of" , "on" , "or" , "to" ,
30- "and" , "dim" , "end" , "for" , "get" , "let" , "lib" , "mod" , "new" , "not" , "rem" , "set" , "sub" , "try" , "xor" ,
31- "ansi" , "auto" , "byte" , "call" , "case" , "cdbl" , "cdec" , "char" , "cint" , "clng" , "cobj" , "csng" , "cstr" , "date" , "each" , "else" ,
32- "enum" , "exit" , "goto" , "like" , "long" , "loop" , "next" , "step" , "stop" , "then" , "true" , "wend" , "when" , "with" ,
33- "alias" , "byref" , "byval" , "catch" , "cbool" , "cbyte" , "cchar" , "cdate" , "class" , "const" , "ctype" , "cuint" , "culng" , "endif" , "erase" , "error" ,
34- "event" , "false" , "gosub" , "isnot" , "redim" , "sbyte" , "short" , "throw" , "ulong" , "until" , "using" , "while" ,
35- "csbyte" , "cshort" , "double" , "elseif" , "friend" , "global" , "module" , "mybase" , "object" , "option" , "orelse" , "public" , "resume" , "return" , "select" , "shared" ,
36- "single" , "static" , "string" , "typeof" , "ushort" ,
37- "andalso" , "boolean" , "cushort" , "decimal" , "declare" , "default" , "finally" , "gettype" , "handles" , "imports" , "integer" , "myclass" , "nothing" , "partial" , "private" , "shadows" ,
38- "trycast" , "unicode" , "variant" ,
39- "assembly" , "continue" , "delegate" , "function" , "inherits" , "operator" , "optional" , "preserve" , "property" , "readonly" , "synclock" , "uinteger" , "widening" ,
40- "addressof" , "interface" , "namespace" , "narrowing" , "overloads" , "overrides" , "protected" , "structure" , "writeonly" ,
41- "addhandler" , "directcast" , "implements" , "paramarray" , "raiseevent" , "withevents" ,
42- "mustinherit" , "overridable" ,
43- "mustoverride" ,
44- "removehandler" ,
45- "class_finalize" , "notinheritable" , "notoverridable" ,
46- "class_initialize"
47- } ;
48-
49- private static readonly List < string > _defaultUsings = new List < string > ( )
50- {
24+ private static readonly HashSet < string > _defaultNamespaces =
25+ [
26+ "System" ,
5127 "System.Collections.Generic" ,
52- "System"
53- } ;
28+ ] ;
5429
55- private static readonly Dictionary < string , string > _csharpTypeAlias = new ( 16 )
30+ private static readonly Dictionary < Type , string > _csharpTypeAlias = new ( 16 )
5631 {
57- { "System.Int16" , "short" } ,
58- { "System.Int32" , "int" } ,
59- { "System.Int64" , "long" } ,
60- { "System.String" , "string" } ,
61- { "System.Object" , "object" } ,
62- { "System.Boolean" , "bool" } ,
63- { "System.Void" , "void" } ,
64- { "System.Char" , "char" } ,
65- { "System.Byte" , "byte" } ,
66- { "System.UInt16" , "ushort" } ,
67- { "System.UInt32" , "uint" } ,
68- { "System.UInt64" , "ulong" } ,
69- { "System.SByte" , "sbyte" } ,
70- { "System.Single" , "float" } ,
71- { "System.Double" , "double" } ,
72- { "System.Decimal" , "decimal" }
32+ { typeof ( bool ) , "bool" } ,
33+ { typeof ( byte ) , "byte" } ,
34+ { typeof ( char ) , "char" } ,
35+ { typeof ( decimal ) , "decimal" } ,
36+ { typeof ( double ) , "double" } ,
37+ { typeof ( float ) , "float" } ,
38+ { typeof ( int ) , "int" } ,
39+ { typeof ( long ) , "long" } ,
40+ { typeof ( object ) , "object" } ,
41+ { typeof ( sbyte ) , "sbyte" } ,
42+ { typeof ( short ) , "short" } ,
43+ { typeof ( string ) , "string" } ,
44+ { typeof ( uint ) , "uint" } ,
45+ { typeof ( ulong ) , "ulong" } ,
46+ { typeof ( ushort ) , "ushort" } ,
47+ { typeof ( void ) , "void" }
7348 } ;
7449 #endregion
7550
@@ -94,79 +69,44 @@ public static string MakeUnique(this string name, Func<string, bool> exists)
9469 return uniqueName ;
9570 }
9671
97- public static bool IsKeyword ( this string text , CodeLanguage language = CodeLanguage . CSharp )
72+ public static bool IsKeyword ( this string text )
9873 {
9974 ArgumentException . ThrowIfNullOrEmpty ( text ) ;
10075
101- return language == CodeLanguage . VisualBasic
102- ? _visualBasicKeywords . Contains ( text )
103- : _csharpKeywords . Contains ( text ) ;
76+ return _csharpKeywords . Contains ( text ) ;
10477 }
10578
10679 [ return : NotNullIfNotNull ( nameof ( name ) ) ]
107- public static string ? ToSafeName ( this string ? name , CodeLanguage language = CodeLanguage . CSharp )
80+ public static string ? ToSafeName ( this string ? name )
10881 {
10982 if ( string . IsNullOrEmpty ( name ) )
11083 return name ;
11184
112- if ( ! name . IsKeyword ( language ) )
85+ if ( ! name . IsKeyword ( ) )
11386 return name ;
11487
115- return language == CodeLanguage . VisualBasic
116- ? string . Format ( "[{0}]" , name )
117- : "@" + name ;
88+ return "@" + name ;
11889 }
11990
120- public static string ToType ( this Type type , CodeLanguage language = CodeLanguage . CSharp )
91+ public static string ToType ( this Type type )
12192 {
12293 ArgumentNullException . ThrowIfNull ( type ) ;
12394
124- if ( type . IsGenericType )
125- {
126- var genericType = type . GetGenericTypeDefinition ( ) . FullName !
127- . Split ( '`' ) [ 0 ] ; // trim the `1 bit
128-
129- genericType = ToType ( genericType , language ) ;
130-
131- var elementType = ToType ( type . GetGenericArguments ( ) [ 0 ] . FullName ! , language ) ;
132- return language == CodeLanguage . VisualBasic
133- ? $ "{ genericType } (Of { elementType } )"
134- : $ "{ genericType } <{ elementType } >";
135- }
136-
137- return ToType ( type . FullName ?? type . Name , language ) ;
95+ var stringBuilder = new StringBuilder ( ) ;
96+ ProcessType ( stringBuilder , type ) ;
97+ return stringBuilder . ToString ( ) ;
13898 }
13999
140- public static string ToType ( this string type , CodeLanguage language = CodeLanguage . CSharp )
141- {
142- ArgumentException . ThrowIfNullOrEmpty ( type ) ;
143-
144- if ( type == "System.Xml.XmlDocument" )
145- type = "System.String" ;
146-
147- if ( language == CodeLanguage . CSharp && _csharpTypeAlias . TryGetValue ( type , out var t ) )
148- return t ;
149-
150- // drop common namespaces
151- foreach ( var defaultUsing in _defaultUsings )
152- if ( type . StartsWith ( defaultUsing ) )
153- return type . Remove ( 0 , defaultUsing . Length + 1 ) ;
154-
155- return type ;
156- }
157-
158- public static string ? ToNullableType ( this Type type , bool isNullable = false , CodeLanguage language = CodeLanguage . CSharp )
100+ public static string ? ToNullableType ( this Type type , bool isNullable = false )
159101 {
160102 bool isValueType = type . IsValueType ;
161103
162- var typeString = type . ToType ( language ) ;
104+ var typeString = type . ToType ( ) ;
163105
164106 if ( ! isValueType || ! isNullable )
165107 return typeString ;
166108
167- return language == CodeLanguage . VisualBasic
168- ? $ "Nullable(Of { type } )"
169- : typeString + "?" ;
109+ return typeString . EndsWith ( '?' ) ? typeString : typeString + "?" ;
170110 }
171111
172112 public static bool IsValueType ( this string ? type )
@@ -189,4 +129,89 @@ public static string ToLiteral(this string value)
189129 ? "@\" " + value . Replace ( "\" " , "\" \" " ) + "\" "
190130 : "\" " + value . Replace ( "\\ " , "\\ \\ " ) . Replace ( "\" " , "\\ \" " ) + "\" " ;
191131 }
132+
133+
134+
135+ private static void ProcessType ( StringBuilder builder , Type type )
136+ {
137+ if ( type . IsGenericType )
138+ {
139+ var genericArguments = type . GetGenericArguments ( ) ;
140+ ProcessGenericType ( builder , type , genericArguments , genericArguments . Length ) ;
141+ }
142+ else if ( type . IsArray )
143+ {
144+ ProcessArrayType ( builder , type ) ;
145+ }
146+ else if ( _csharpTypeAlias . TryGetValue ( type , out var builtInName ) )
147+ {
148+ builder . Append ( builtInName ) ;
149+ }
150+ else if ( type . Namespace . HasValue ( ) && _defaultNamespaces . Contains ( type . Namespace ) )
151+ {
152+ builder . Append ( type . Name ) ;
153+ }
154+ else
155+ {
156+ builder . Append ( type . FullName ?? type . Name ) ;
157+ }
158+ }
159+
160+ private static void ProcessArrayType ( StringBuilder builder , Type type )
161+ {
162+ var innerType = type ;
163+ while ( innerType . IsArray )
164+ {
165+ innerType = innerType . GetElementType ( ) ! ;
166+ }
167+
168+ ProcessType ( builder , innerType ) ;
169+
170+ while ( type . IsArray )
171+ {
172+ builder . Append ( '[' ) ;
173+ builder . Append ( ',' , type . GetArrayRank ( ) - 1 ) ;
174+ builder . Append ( ']' ) ;
175+ type = type . GetElementType ( ) ! ;
176+ }
177+ }
178+
179+ private static void ProcessGenericType ( StringBuilder builder , Type type , Type [ ] genericArguments , int length )
180+ {
181+ if ( type . IsConstructedGenericType
182+ && type . GetGenericTypeDefinition ( ) == typeof ( Nullable < > ) )
183+ {
184+ ProcessType ( builder , type . GetUnderlyingType ( ) ) ;
185+ builder . Append ( '?' ) ;
186+ return ;
187+ }
188+
189+ var offset = type . DeclaringType != null ? type . DeclaringType . GetGenericArguments ( ) . Length : 0 ;
190+ var genericPartIndex = type . Name . IndexOf ( '`' ) ;
191+ if ( genericPartIndex <= 0 )
192+ {
193+ builder . Append ( type . Name ) ;
194+ return ;
195+ }
196+
197+ builder . Append ( type . Name , 0 , genericPartIndex ) ;
198+ builder . Append ( '<' ) ;
199+
200+ for ( var i = offset ; i < length ; i ++ )
201+ {
202+ ProcessType ( builder , genericArguments [ i ] ) ;
203+ if ( i + 1 == length )
204+ {
205+ continue ;
206+ }
207+
208+ builder . Append ( ',' ) ;
209+ if ( ! genericArguments [ i + 1 ] . IsGenericParameter )
210+ {
211+ builder . Append ( ' ' ) ;
212+ }
213+ }
214+
215+ builder . Append ( '>' ) ;
216+ }
192217}
0 commit comments