├── .gitignore ├── LICENSE ├── README.md ├── TypeSupport ├── .editorconfig ├── TypeSupport.Tests │ ├── Assembly │ │ ├── DynamicAssemblyCacheTests.cs │ │ └── ExtendedTypeCacheTests.cs │ ├── AttributeInspectionTests.cs │ ├── ExtendedFieldTests.cs │ ├── ExtendedMethodTests.cs │ ├── ExtendedPropertyTests.cs │ ├── ExtensionTests.cs │ ├── ObjectFactoryTests.cs │ ├── ObjectHashcodeMapTests.cs │ ├── TestObjects │ │ ├── BasicObject.cs │ │ ├── BasicObjectWithAttributes.cs │ │ ├── BasicObjectWithConstructor.cs │ │ ├── BasicObjectWithParamAttributes.cs │ │ ├── DifferentBasicObject.cs │ │ ├── IInterfaceWithImplementations.cs │ │ ├── IInterfaceWithoutImplementations.cs │ │ ├── InheritedObject.cs │ │ ├── NonGenericDictionary.cs │ │ ├── ObjectWithExplicitlyImplementedInterfaceDeclaredGenericProperty.cs │ │ ├── ObjectWithGetProperty.cs │ │ ├── ObjectWithNamedTuple.cs │ │ ├── OperatorOverloadObject.cs │ │ ├── PrivateConstructorObject.cs │ │ ├── ReadOnlyObject.cs │ │ ├── StaticTypeImplementation.cs │ │ ├── StructObject.cs │ │ ├── TestDecoratedAttribute.cs │ │ └── VisibilityObject.cs │ ├── TypeRegistryTests.cs │ ├── TypeSupport.Tests.csproj │ ├── TypeSupportOptionsTests.cs │ └── TypeSupportTests.cs ├── TypeSupport.sln ├── TypeSupport │ ├── Assembly │ │ ├── AssemblyManager.cs │ │ ├── CacheKey.cs │ │ ├── DynamicAssemblyCache.cs │ │ └── ExtendedTypeCache.cs │ ├── ExtendedField.cs │ ├── ExtendedMethod.cs │ ├── ExtendedProperty.cs │ ├── ExtendedType.cs │ ├── Extensions │ │ ├── BitConverterExtensions.cs │ │ ├── ConstructorOptions.cs │ │ ├── EnumExtensions.cs │ │ ├── EnumerableExtensions.cs │ │ ├── FieldOptions.cs │ │ ├── MethodOptions.cs │ │ ├── ObjectExtensions.cs │ │ ├── PropertyOptions.cs │ │ ├── ReflectionExtensions.cs │ │ ├── StringExtensions.cs │ │ ├── TupleExtensions.cs │ │ └── TypeExtensions.cs │ ├── IAttributeInspection.cs │ ├── ObjectFactory.cs │ ├── ObjectHashcode.cs │ ├── ObjectHashcodeMap.cs │ ├── TypeConfiguration.cs │ ├── TypeFactory.cs │ ├── TypeInspector.cs │ ├── TypeMap.cs │ ├── TypeRegistry.cs │ ├── TypeSupport.csproj │ ├── TypeSupportException.cs │ ├── TypeSupportOptions.cs │ └── typesupport.png ├── TypeSupportStrongNameKey.snk └── runtests.ps1 ├── appveyor.yml └── scripts ├── build.ps1 ├── run-tests.ps1 └── send-coverage.ps1 /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.suo 8 | *.user 9 | *.userosscache 10 | *.sln.docstates 11 | 12 | # User-specific files (MonoDevelop/Xamarin Studio) 13 | *.userprefs 14 | 15 | # Build results 16 | [Dd]ebug/ 17 | [Dd]ebugPublic/ 18 | [Rr]elease/ 19 | [Rr]eleases/ 20 | x64/ 21 | x86/ 22 | bld/ 23 | [Bb]in/ 24 | [Oo]bj/ 25 | [Ll]og/ 26 | 27 | # Visual Studio 2015/2017 cache/options directory 28 | .vs/ 29 | # Uncomment if you have tasks that create the project's static files in wwwroot 30 | #wwwroot/ 31 | 32 | # Visual Studio 2017 auto generated files 33 | Generated\ Files/ 34 | 35 | # MSTest test Results 36 | [Tt]est[Rr]esult*/ 37 | [Bb]uild[Ll]og.* 38 | 39 | # NUNIT 40 | *.VisualState.xml 41 | TestResult.xml 42 | 43 | # Build Results of an ATL Project 44 | [Dd]ebugPS/ 45 | [Rr]eleasePS/ 46 | dlldata.c 47 | 48 | # Benchmark Results 49 | BenchmarkDotNet.Artifacts/ 50 | 51 | # .NET Core 52 | project.lock.json 53 | project.fragment.lock.json 54 | artifacts/ 55 | **/Properties/launchSettings.json 56 | 57 | # StyleCop 58 | StyleCopReport.xml 59 | 60 | # Files built by Visual Studio 61 | *_i.c 62 | *_p.c 63 | *_i.h 64 | *.ilk 65 | *.meta 66 | *.obj 67 | *.iobj 68 | *.pch 69 | *.pdb 70 | *.ipdb 71 | *.pgc 72 | *.pgd 73 | *.rsp 74 | *.sbr 75 | *.tlb 76 | *.tli 77 | *.tlh 78 | *.tmp 79 | *.tmp_proj 80 | *.log 81 | *.vspscc 82 | *.vssscc 83 | .builds 84 | *.pidb 85 | *.svclog 86 | *.scc 87 | 88 | # Chutzpah Test files 89 | _Chutzpah* 90 | 91 | # Visual C++ cache files 92 | ipch/ 93 | *.aps 94 | *.ncb 95 | *.opendb 96 | *.opensdf 97 | *.sdf 98 | *.cachefile 99 | *.VC.db 100 | *.VC.VC.opendb 101 | 102 | # Visual Studio profiler 103 | *.psess 104 | *.vsp 105 | *.vspx 106 | *.sap 107 | 108 | # Visual Studio Trace Files 109 | *.e2e 110 | 111 | # TFS 2012 Local Workspace 112 | $tf/ 113 | 114 | # Guidance Automation Toolkit 115 | *.gpState 116 | 117 | # ReSharper is a .NET coding add-in 118 | _ReSharper*/ 119 | *.[Rr]e[Ss]harper 120 | *.DotSettings.user 121 | 122 | # JustCode is a .NET coding add-in 123 | .JustCode 124 | 125 | # TeamCity is a build add-in 126 | _TeamCity* 127 | 128 | # DotCover is a Code Coverage Tool 129 | *.dotCover 130 | 131 | # AxoCover is a Code Coverage Tool 132 | .axoCover/* 133 | !.axoCover/settings.json 134 | 135 | # Visual Studio code coverage results 136 | *.coverage 137 | *.coveragexml 138 | 139 | # NCrunch 140 | _NCrunch_* 141 | .*crunch*.local.xml 142 | nCrunchTemp_* 143 | 144 | # MightyMoose 145 | *.mm.* 146 | AutoTest.Net/ 147 | 148 | # Web workbench (sass) 149 | .sass-cache/ 150 | 151 | # Installshield output folder 152 | [Ee]xpress/ 153 | 154 | # DocProject is a documentation generator add-in 155 | DocProject/buildhelp/ 156 | DocProject/Help/*.HxT 157 | DocProject/Help/*.HxC 158 | DocProject/Help/*.hhc 159 | DocProject/Help/*.hhk 160 | DocProject/Help/*.hhp 161 | DocProject/Help/Html2 162 | DocProject/Help/html 163 | 164 | # Click-Once directory 165 | publish/ 166 | 167 | # Publish Web Output 168 | *.[Pp]ublish.xml 169 | *.azurePubxml 170 | # Note: Comment the next line if you want to checkin your web deploy settings, 171 | # but database connection strings (with potential passwords) will be unencrypted 172 | *.pubxml 173 | *.publishproj 174 | 175 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 176 | # checkin your Azure Web App publish settings, but sensitive information contained 177 | # in these scripts will be unencrypted 178 | PublishScripts/ 179 | 180 | # NuGet Packages 181 | *.nupkg 182 | # The packages folder can be ignored because of Package Restore 183 | **/[Pp]ackages/* 184 | # except build/, which is used as an MSBuild target. 185 | !**/[Pp]ackages/build/ 186 | # Uncomment if necessary however generally it will be regenerated when needed 187 | #!**/[Pp]ackages/repositories.config 188 | # NuGet v3's project.json files produces more ignorable files 189 | *.nuget.props 190 | *.nuget.targets 191 | 192 | # Microsoft Azure Build Output 193 | csx/ 194 | *.build.csdef 195 | 196 | # Microsoft Azure Emulator 197 | ecf/ 198 | rcf/ 199 | 200 | # Windows Store app package directories and files 201 | AppPackages/ 202 | BundleArtifacts/ 203 | Package.StoreAssociation.xml 204 | _pkginfo.txt 205 | *.appx 206 | 207 | # Visual Studio cache files 208 | # files ending in .cache can be ignored 209 | *.[Cc]ache 210 | # but keep track of directories ending in .cache 211 | !*.[Cc]ache/ 212 | 213 | # Others 214 | ClientBin/ 215 | ~$* 216 | *~ 217 | *.dbmdl 218 | *.dbproj.schemaview 219 | *.jfm 220 | *.pfx 221 | *.publishsettings 222 | orleans.codegen.cs 223 | 224 | # Including strong name files can present a security risk 225 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 226 | #*.snk 227 | 228 | # Since there are multiple workflows, uncomment next line to ignore bower_components 229 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 230 | #bower_components/ 231 | 232 | # RIA/Silverlight projects 233 | Generated_Code/ 234 | 235 | # Backup & report files from converting an old project file 236 | # to a newer Visual Studio version. Backup files are not needed, 237 | # because we have git ;-) 238 | _UpgradeReport_Files/ 239 | Backup*/ 240 | UpgradeLog*.XML 241 | UpgradeLog*.htm 242 | ServiceFabricBackup/ 243 | *.rptproj.bak 244 | 245 | # SQL Server files 246 | *.mdf 247 | *.ldf 248 | *.ndf 249 | 250 | # Business Intelligence projects 251 | *.rdl.data 252 | *.bim.layout 253 | *.bim_*.settings 254 | *.rptproj.rsuser 255 | 256 | # Microsoft Fakes 257 | FakesAssemblies/ 258 | 259 | # GhostDoc plugin setting file 260 | *.GhostDoc.xml 261 | 262 | # Node.js Tools for Visual Studio 263 | .ntvs_analysis.dat 264 | node_modules/ 265 | 266 | # Visual Studio 6 build log 267 | *.plg 268 | 269 | # Visual Studio 6 workspace options file 270 | *.opt 271 | 272 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 273 | *.vbw 274 | 275 | # Visual Studio LightSwitch build output 276 | **/*.HTMLClient/GeneratedArtifacts 277 | **/*.DesktopClient/GeneratedArtifacts 278 | **/*.DesktopClient/ModelManifest.xml 279 | **/*.Server/GeneratedArtifacts 280 | **/*.Server/ModelManifest.xml 281 | _Pvt_Extensions 282 | 283 | # Paket dependency manager 284 | .paket/paket.exe 285 | paket-files/ 286 | 287 | # FAKE - F# Make 288 | .fake/ 289 | 290 | # JetBrains Rider 291 | .idea/ 292 | *.sln.iml 293 | 294 | # CodeRush 295 | .cr/ 296 | 297 | # Python Tools for Visual Studio (PTVS) 298 | __pycache__/ 299 | *.pyc 300 | 301 | # Cake - Uncomment if you are using it 302 | # tools/** 303 | # !tools/packages.config 304 | 305 | # Tabs Studio 306 | *.tss 307 | 308 | # Telerik's JustMock configuration file 309 | *.jmconfig 310 | 311 | # BizTalk build output 312 | *.btp.cs 313 | *.btm.cs 314 | *.odx.cs 315 | *.xsd.cs 316 | 317 | # OpenCover UI analysis results 318 | OpenCover/ 319 | 320 | # Azure Stream Analytics local run output 321 | ASALocalRun/ 322 | 323 | # MSBuild Binary and Structured Log 324 | *.binlog 325 | 326 | # NVidia Nsight GPU debugger configuration file 327 | *.nvuser 328 | 329 | # MFractors (Xamarin productivity tool) working folder 330 | .mfractor/ 331 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TypeSupport 2 | [![nuget](https://img.shields.io/nuget/v/TypeSupport.svg)](https://www.nuget.org/packages/TypeSupport/) 3 | [![nuget](https://img.shields.io/nuget/dt/TypeSupport.svg)](https://www.nuget.org/packages/TypeSupport/) 4 | [![Build status](https://ci.appveyor.com/api/projects/status/swv5vcad12nrwohk?svg=true)](https://ci.appveyor.com/project/MichaelBrown/typesupport) 5 | [![Codacy Badge](https://api.codacy.com/project/badge/Grade/5ddab4815a2a49b3babac9af232f9f04)](https://www.codacy.com/app/replaysMike/TypeSupport?utm_source=github.com&utm_medium=referral&utm_content=replaysMike/TypeSupport&utm_campaign=Badge_Grade) 6 | [![Codacy Badge](https://api.codacy.com/project/badge/Coverage/5ddab4815a2a49b3babac9af232f9f04)](https://www.codacy.com/app/replaysMike/TypeSupport?utm_source=github.com&utm_medium=referral&utm_content=replaysMike/TypeSupport&utm_campaign=Badge_Coverage) 7 | 8 | A CSharp library that makes it easier to work with Types dynamically. TypeSupport includes a flexible Object factory for creating and initializing all kinds of types. 9 | 10 | ## Description 11 | 12 | The best way to understand what TypeSupport can do is to see it in action! It is used as the foundation for many other packages. 13 | 14 | ## Installation 15 | Install TypeSupport from the Package Manager Console: 16 | ```PowerShell 17 | PM> Install-Package TypeSupport 18 | ``` 19 | 20 | ## Usage 21 | 22 | ### Type Support 23 | 24 | Getting started - create a TypeSupport from a type 25 | ```csharp 26 | using TypeSupport; 27 | 28 | var type = typeof(MyObject); 29 | var typeSupport = new ExtendedType(type); 30 | ``` 31 | 32 | or do it using the extensions (we will use this syntax going forward): 33 | ```csharp 34 | using TypeSupport; 35 | 36 | var type = typeof(MyObject); 37 | var typeSupport = type.GetExtendedType(); 38 | ``` 39 | 40 | get information about an array: 41 | ```csharp 42 | var type = typeof(int[]); 43 | var typeSupport = type.GetExtendedType(); 44 | 45 | var isArray = typeSupport.IsArray; // true 46 | var elementType = typeSupport.ElementType; // int 47 | ``` 48 | 49 | get information about a Dictionary: 50 | ```csharp 51 | var type = typeof(Dictionary); 52 | var typeSupport = type.GetExtendedType(); 53 | 54 | var isArray = typeSupport.IsDictionary; // true 55 | var elementTypes = typeSupport.GenericArgumentTypes; // System.Int32, System.String 56 | ``` 57 | 58 | get info about an interface: 59 | ```csharp 60 | var type = typeof(IVehicle); 61 | var typeSupport = type.GetExtendedType(); 62 | 63 | var isArray = typeSupport.IsInterface; // true 64 | var classesThatImplementICustomInterface = typeSupport.KnownConcreteTypes; 65 | // [] = Car, Truck, Van, Motorcycle 66 | ``` 67 | 68 | get info about a class: 69 | ```csharp 70 | [Description("A car object")] 71 | public class Car : IVehicle 72 | { 73 | public string Name { get; set; } 74 | public Car() { } 75 | } 76 | var type = typeof(Car); 77 | var typeSupport = type.GetExtendedType(); 78 | 79 | var isArray = typeSupport.HasEmptyConstructor; // true 80 | var attributes = typeSupport.Attributes; 81 | // [] = DescriptionAttribute 82 | ``` 83 | 84 | working with enums: 85 | ```csharp 86 | public enum Colors : byte 87 | { 88 | Red = 1, 89 | Green = 2, 90 | Blue = 3 91 | } 92 | var type = typeof(Colors); 93 | var typeSupport = type.GetExtendedType(); 94 | 95 | var isEnum = typeSupport.IsEnum; // true 96 | var enumValues = typeSupport.EnumValues; 97 | // [] = <1, Red>, <2, Green>, <3, blue> 98 | var enumType = typeSupport.EnumType; // System.Byte 99 | ``` 100 | 101 | working with Tuples: 102 | ```csharp 103 | var tupleType = typeof(Tuple); 104 | var valueTupleType = typeof((IVehicle, string)); 105 | var tupleTypeSupport = type.GetExtendedType(); 106 | var valueTupleTypeSupport = valueTupleType.GetExtendedType(); 107 | 108 | var isTuple = tupleTypeSupport.IsTuple; // true 109 | var isValueTuple = valueTupleTypeSupport.IsValueTuple; // true 110 | var tupleGenericArguments = tupleTypeSupport.GenericArgumentTypes; // System.Int32, System.String, System.Double 111 | var valueTupleGenericArguments = valueTupleTypeSupport.GenericArgumentTypes; // IVehicle, System.String 112 | // there's lots more you can do, such as getting the value from a Tuple instance: 113 | 114 | var car = new Car(); 115 | var description = "My cool car"; 116 | var myTuple = (car, description); 117 | var items = myTuple.GetValueTupleItemObjects(); 118 | // [] = Car, "My cool car" 119 | ``` 120 | 121 | ### Object factory 122 | 123 | Create new objects of any type: 124 | 125 | ```csharp 126 | var factory = new ObjectFactory(); 127 | var listInstance = factory.CreateEmptyObject>(); // List() 0 elements 128 | var dictionaryInstance = factory.CreateEmptyObject>(); // Dictionary() 0 elements 129 | var emptyByteArray = factory.CreateEmptyObject(); // byte[0] empty byte array 130 | var byteArray = factory.CreateEmptyObject(length: 64); // byte[64] 131 | var tupleInstance = factory.CreateEmptyObject<(int, string)>(); // tupleInstance.Item1 = 0, tupleInstance.item2 = null 132 | var myComplexObject = factory.CreateEmptyObject(); 133 | ``` 134 | 135 | Create objects without parameterless constructors: 136 | ```csharp 137 | public class CustomObject 138 | { 139 | public int Id { get; } 140 | public CustomObject(int id) 141 | { 142 | Id = id; 143 | } 144 | } 145 | var factory = new ObjectFactory(); 146 | var myObj = factory.CreateEmptyObject(); // myObj.GetType() == typeof(CustomObject) 147 | ``` 148 | 149 | You can instruct the Object factory on how to map abstract interfaces when creating instances: 150 | ```csharp 151 | var typeRegistry = TypeRegistry.Configure((config) => { 152 | config.AddMapping(); 153 | }); 154 | 155 | var factory = new ObjectFactory(typeRegistry); 156 | var car = factory.CreateEmptyObject(); // car.GetType() == typeof(Car) 157 | ``` 158 | 159 | You can also register custom factories: 160 | ```csharp 161 | var typeRegistry = TypeRegistry.Configure((config) => { 162 | config.AddFactory(() => new Car(Color.Red)); 163 | }); 164 | 165 | var factory = new ObjectFactory(typeRegistry); 166 | var car = factory.CreateEmptyObject(); // car.GetType() == typeof(Car) 167 | ``` 168 | 169 | ### Capabilities 170 | 171 | - [x] All basic types, enums, generics, collections and enumerables 172 | - [x] Internal caching of type examination 173 | - [x] Constructor analysis (empty constructors, parameterized constructors) 174 | - [x] Easy listing of valid Enum values 175 | - [x] Easy listing of concrete types implementing an interface 176 | - [x] Easy listing of attributes 177 | - [x] Easy listing of generic arguments 178 | - [x] Easy listing of properties/fields 179 | - [x] Easy listing of implemented interfaces 180 | - [x] Easy listing of Tuple/ValueTuple types 181 | - [x] Nullable type detection 182 | - [x] Custom collection information detection 183 | - [x] Primitive / Struct detection 184 | - [x] Anonymous type detection 185 | - [x] High performance testing and optimization 186 | -------------------------------------------------------------------------------- /TypeSupport/.editorconfig: -------------------------------------------------------------------------------- 1 | # top-most EditorConfig file 2 | root = true 3 | 4 | # Unix-style newlines with a newline ending every file 5 | [*] 6 | end_of_line = crlf 7 | trim_trailing_whitespace = true 8 | insert_final_newline = true 9 | 10 | # CSharp code style settings: 11 | 12 | # 4 space indentation 13 | [*.cs] 14 | indent_style = space 15 | indent_size = 4 16 | 17 | # Prefer all non-static fields called from within non-static methods to NOT be prefaced with this. 18 | dotnet_style_qualification_for_field = false : error 19 | # Prefer all non-static properties called from within non-static methods to NOT be prefaced with this. 20 | dotnet_style_qualification_for_property = false : error 21 | # Prefer all non-static methods called from within non-static methods to NOT be prefaced with this. 22 | dotnet_style_qualification_for_method = false : error 23 | # Prefer all non-static events referenced from within non-static methods to NOT be prefaced with this. 24 | dotnet_style_qualification_for_event = false : error 25 | 26 | # For locals, parameters and type members, prefer types that have a language keyword to represent them (int, double, float, short, long, decimal, string) to use the keyword instead of the type name (Int32, Int64, etc.). 27 | dotnet_style_predefined_type_for_locals_parameters_members = true : suggestion 28 | # Prefer the keyword whenever a member-access expression is used on a type with a keyword representation (int, double, float, short, long, decimal, string). 29 | dotnet_style_predefined_type_for_member_access = true : suggestion 30 | 31 | # Prefer objects to be initialized using object initializers when possible. 32 | dotnet_style_object_initializer = true : suggestion 33 | 34 | # Prefer collections to be initialized using collection initializers when possible. 35 | dotnet_style_collection_initializer = true : suggestion 36 | 37 | 38 | # Prefer tuple names to ItemX properties. 39 | # C# 7.0+ Feature 40 | # dotnet_style_explicit_tuple_names = true:suggestion 41 | 42 | # Prefer null coalescing expression to ternary operator checking. 43 | dotnet_style_coalesce_expression = true : error 44 | 45 | # Prefer to use null-conditional operator where possible. 46 | dotnet_style_null_propagation = true : suggestion 47 | 48 | dotnet_sort_system_directives_first = true 49 | 50 | # Prefer var is used for built-in system types such as int. 51 | csharp_style_var_for_built_in_types = true : suggestion 52 | # Prefer var when the type is already mentioned on the right-hand side of a declaration expression. 53 | csharp_style_var_when_type_is_apparent = true : error 54 | # Prefer to not use var in all cases unless overridden by another code style rule. 55 | csharp_style_var_elsewhere = true : suggestion 56 | 57 | # Prefer expression-bodied members for methods. 58 | csharp_style_expression_bodied_methods = true : suggestion 59 | 60 | # Prefer expression-bodied members for properties. 61 | # C# 7.0+ Feature 62 | # csharp_style_expression_bodied_properties = true:suggestion 63 | 64 | # FORMATTING 65 | csharp_new_line_before_open_brace = methods, properties, control_blocks, types 66 | csharp_new_line_before_else = true 67 | csharp_new_line_before_catch = true 68 | csharp_new_line_before_finally = true 69 | csharp_new_line_before_members_in_object_initializers = true 70 | csharp_new_line_before_members_in_anonymous_types = true 71 | 72 | csharp_indent_case_contents = true 73 | csharp_indent_switch_labels = true 74 | 75 | # (int)i 76 | csharp_space_after_cast = false 77 | # for (int i;i()); 33 | Assert.IsTrue(ef.HasAttribute(typeof(TestDecoratedAttribute))); 34 | Assert.AreEqual(789, ef.GetAttribute().Value); 35 | Assert.AreEqual(789, (ef.GetAttribute(typeof(TestDecoratedAttribute)) as TestDecoratedAttribute).Value); 36 | } 37 | 38 | [Test] 39 | public void Should_DiscoverAllFieldAttributes() 40 | { 41 | var fields = typeof(BasicObject).GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); 42 | var ef = new ExtendedField(fields.First()); 43 | var allAttributes = ef.GetAttributes(); 44 | Assert.AreEqual(1, allAttributes.Count()); 45 | } 46 | 47 | [Test] 48 | public void Should_DiscoverAllFieldGenericAttributes() 49 | { 50 | var fields = typeof(BasicObject).GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); 51 | var ef = new ExtendedField(fields.First()); 52 | var allAttributes = ef.GetAttributes(); 53 | Assert.AreEqual(1, allAttributes.Count()); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /TypeSupport/TypeSupport.Tests/ExtendedMethodTests.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using System.Reflection; 3 | using NUnit.Framework; 4 | using TypeSupport.Extensions; 5 | using TypeSupport.Tests.TestObjects; 6 | 7 | namespace TypeSupport.Tests 8 | { 9 | [TestFixture] 10 | public class ExtendedMethodTests 11 | { 12 | [Test] 13 | public void Should_CreateExtendedMethod() 14 | { 15 | var methods = typeof(BasicObject).GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); 16 | var em = new ExtendedMethod(methods.First()); 17 | Assert.NotNull(em); 18 | Assert.IsNotEmpty(em.Name); 19 | Assert.IsTrue(em.IsGetter); 20 | Assert.IsTrue(em.IsAutoPropertyAccessor); 21 | Assert.NotNull(em.MethodInfo); 22 | Assert.AreEqual(typeof(BasicObject), em.MethodInfo.ReflectedType); 23 | } 24 | 25 | [Test] 26 | public void Should_DiscoverMethodAttributes() 27 | { 28 | var methods = typeof(BasicObject).GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); 29 | var em = new ExtendedMethod(methods.First(x => x.Name.Equals("TestMethod"))); 30 | Assert.IsTrue(em.HasAttribute()); 31 | Assert.IsTrue(em.HasAttribute(typeof(TestDecoratedAttribute))); 32 | Assert.AreEqual(456, em.GetAttribute().Value); 33 | Assert.AreEqual(456, (em.GetAttribute(typeof(TestDecoratedAttribute)) as TestDecoratedAttribute).Value); 34 | } 35 | 36 | [Test] 37 | public void Should_DiscoverAllMethodAttributes() 38 | { 39 | var methods = typeof(BasicObject).GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); 40 | var em = new ExtendedMethod(methods.First(x => x.Name.Equals("TestMethod"))); 41 | var allAttributes = em.GetAttributes(); 42 | Assert.AreEqual(1, allAttributes.Count()); 43 | } 44 | 45 | [Test] 46 | public void Should_DiscoverAllMethodGenericAttributes() 47 | { 48 | var methods = typeof(BasicObject).GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); 49 | var em = new ExtendedMethod(methods.First(x => x.Name.Equals("TestMethod"))); 50 | var allAttributes = em.GetAttributes(); 51 | Assert.AreEqual(1, allAttributes.Count()); 52 | } 53 | 54 | [Test] 55 | public void Should_DiscoverGetter() 56 | { 57 | var methods = typeof(BasicObject).GetMethods(MethodOptions.All); 58 | var method = methods.FirstOrDefault(x => x.Name == "get_Id"); 59 | Assert.NotNull(method); 60 | Assert.IsTrue(method.IsGetter); 61 | Assert.IsTrue(method.IsAutoPropertyAccessor); 62 | } 63 | 64 | [Test] 65 | public void Should_DiscoverSetter() 66 | { 67 | var methods = typeof(BasicObject).GetMethods(MethodOptions.All); 68 | var method = methods.FirstOrDefault(x => x.Name == "set_Id"); 69 | Assert.NotNull(method); 70 | Assert.IsTrue(method.IsSetter); 71 | Assert.IsTrue(method.IsAutoPropertyAccessor); 72 | } 73 | 74 | [Test] 75 | public void Should_DiscoverOverriddenMethods() 76 | { 77 | var methods = typeof(BasicObject).GetMethods(MethodOptions.All); 78 | var method = methods.FirstOrDefault(x => x.Name == "ToString" && x.DeclaringType == typeof(BasicObject)); 79 | Assert.NotNull(method); 80 | Assert.IsTrue(method.IsOverride); 81 | } 82 | 83 | [Test] 84 | public void Should_DiscoverBaseMethods() 85 | { 86 | var methods = typeof(BasicObject).GetMethods(MethodOptions.All); 87 | var method = methods.FirstOrDefault(x => x.Name == "ToString" && x.DeclaringType == typeof(object)); 88 | Assert.NotNull(method); 89 | Assert.IsFalse(method.IsOverride); 90 | Assert.IsTrue(method.IsOverridden); 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /TypeSupport/TypeSupport.Tests/ExtendedPropertyTests.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using System.Linq; 3 | using System.Reflection; 4 | using TypeSupport.Tests.TestObjects; 5 | 6 | namespace TypeSupport.Tests 7 | { 8 | [TestFixture] 9 | public class ExtendedPropertyTests 10 | { 11 | [Test] 12 | public void Should_CreateExtendedProperty() 13 | { 14 | var properties = typeof(BasicObject).GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); 15 | var ef = new ExtendedProperty(properties.First()); 16 | Assert.NotNull(ef); 17 | Assert.IsNotEmpty(ef.Name); 18 | Assert.AreEqual(1, ef.CustomAttributes.Count()); 19 | Assert.AreEqual("k__BackingField", ef.BackingFieldName); 20 | Assert.IsTrue(ef.HasGetMethod); 21 | Assert.NotNull(ef.GetMethod); 22 | Assert.IsTrue(ef.HasSetMethod); 23 | Assert.NotNull(ef.SetMethod); 24 | Assert.IsTrue(ef.IsAutoProperty); 25 | Assert.NotNull(ef.PropertyInfo); 26 | Assert.AreEqual(typeof(BasicObject), ef.ReflectedType); 27 | Assert.AreEqual(typeof(int), ef.Type); 28 | ; 29 | } 30 | 31 | [Test] 32 | public void Should_DiscoverPropertyAttributes() 33 | { 34 | var properties = typeof(BasicObject).GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); 35 | var ef = new ExtendedProperty(properties.First()); 36 | Assert.IsTrue(ef.HasAttribute()); 37 | Assert.IsTrue(ef.HasAttribute(typeof(TestDecoratedAttribute))); 38 | Assert.AreEqual(123, ef.GetAttribute().Value); 39 | Assert.AreEqual(123, (ef.GetAttribute(typeof(TestDecoratedAttribute)) as TestDecoratedAttribute).Value); 40 | } 41 | 42 | [Test] 43 | public void Should_DiscoverAllPropertyAttributes() 44 | { 45 | var fields = typeof(BasicObject).GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); 46 | var ef = new ExtendedProperty(fields.First()); 47 | var allAttributes = ef.GetAttributes(); 48 | Assert.AreEqual(1, allAttributes.Count()); 49 | } 50 | 51 | [Test] 52 | public void Should_DiscoverAllPropertyGenericAttributes() 53 | { 54 | var fields = typeof(BasicObject).GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); 55 | var ef = new ExtendedProperty(fields.First()); 56 | var allAttributes = ef.GetAttributes(); 57 | Assert.AreEqual(1, allAttributes.Count()); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /TypeSupport/TypeSupport.Tests/ExtensionTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using NUnit.Framework; 3 | using TypeSupport.Extensions; 4 | using TypeSupport.Tests.TestObjects; 5 | 6 | namespace TypeSupport.Tests 7 | { 8 | [TestFixture] 9 | public class ExtensionTests 10 | { 11 | [Test] 12 | public void GetExtendedType_ShouldNot_WorkOnExtendedType() 13 | { 14 | var type = typeof(int).GetExtendedType(TypeSupportOptions.AllExceptCaching); 15 | Assert.Throws(() => type.GetExtendedType(TypeSupportOptions.Enums)); 16 | } 17 | 18 | [Test] 19 | public void GetExtendedType_Should_WorkOnType() 20 | { 21 | var type = typeof(int).GetExtendedType(TypeSupportOptions.AllExceptCaching); 22 | var newExtendedType = typeof(int).GetExtendedType(TypeSupportOptions.Enums); 23 | 24 | // the two types should be different 25 | Assert.AreEqual(type, newExtendedType.Type); 26 | // one should have fields, the other should not 27 | Assert.Greater(type.Fields.Count, 0); 28 | Assert.AreEqual(0, newExtendedType.Fields.Count); 29 | } 30 | 31 | [Test] 32 | public void GetField_Should_FindFromBaseType() 33 | { 34 | var field = new DifferentBasicObject(1).GetField("_test", true); 35 | Assert.IsNotNull(field); 36 | } 37 | 38 | [Test] 39 | public void GetField_ShouldNot_FindFromBaseType() 40 | { 41 | var field = new DifferentBasicObject(1).GetField("_test"); 42 | Assert.IsNull(field); 43 | } 44 | 45 | [Test] 46 | public void GetProperty_Should_FindFromBaseType() 47 | { 48 | var property = new DifferentBasicObject(1).GetProperty("Test", true); 49 | Assert.IsNotNull(property); 50 | } 51 | 52 | [Test] 53 | public void GetFieldValue_Should_Succeed() 54 | { 55 | var fieldValue = new BasicObject(1).GetFieldValue("FieldValue"); 56 | Assert.AreEqual(1, fieldValue); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /TypeSupport/TypeSupport.Tests/ObjectFactoryTests.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using System; 3 | using System.Collections; 4 | using System.Collections.Generic; 5 | using TypeSupport.Tests.TestObjects; 6 | using System.Runtime.CompilerServices; 7 | using TypeSupport.Extensions; 8 | 9 | namespace TypeSupport.Tests 10 | { 11 | [TestFixture] 12 | public class ObjectFactoryTests 13 | { 14 | [Test] 15 | public void Should_CreateBasicObject() 16 | { 17 | var factory = new ObjectFactory(); 18 | var instance = factory.CreateEmptyObject(); 19 | 20 | Assert.NotNull(instance); 21 | Assert.AreEqual(typeof(BasicObject), instance.GetType()); 22 | } 23 | 24 | [Test] 25 | public void Should_CreateGenericList() 26 | { 27 | var factory = new ObjectFactory(); 28 | var instance = factory.CreateEmptyObject(); 29 | // .Net Core 3+ no longer guarantees this list to be a object[], its now an internal unaccessible type of EmptyPartition 30 | var isEnumerable = instance is IEnumerable; 31 | Assert.NotNull(instance); 32 | Assert.IsTrue(isEnumerable); 33 | } 34 | 35 | [Test] 36 | public void Should_CreateIEnumerable() 37 | { 38 | var factory = new ObjectFactory(); 39 | var instance = factory.CreateEmptyObject>(); 40 | 41 | Assert.NotNull(instance); 42 | Assert.AreEqual(0, instance.Count); 43 | Assert.AreEqual(typeof(List), instance.GetType()); 44 | } 45 | 46 | [Test] 47 | public void Should_CreateGenericIList() 48 | { 49 | var factory = new ObjectFactory(); 50 | var instance = factory.CreateEmptyObject>(); 51 | 52 | Assert.NotNull(instance); 53 | Assert.AreEqual(0, instance.Count); 54 | Assert.AreEqual(typeof(List), instance.GetType()); 55 | } 56 | 57 | [Test] 58 | public void Should_CreateGenericDictionary() 59 | { 60 | var factory = new ObjectFactory(); 61 | var instance = factory.CreateEmptyObject>(); 62 | 63 | Assert.NotNull(instance); 64 | Assert.AreEqual(0, instance.Count); 65 | Assert.AreEqual(typeof(Dictionary), instance.GetType()); 66 | } 67 | 68 | [Test] 69 | public void Should_CreateGenericIDictionary() 70 | { 71 | var factory = new ObjectFactory(); 72 | var instance = factory.CreateEmptyObject>(); 73 | 74 | Assert.NotNull(instance); 75 | Assert.AreEqual(0, instance.Count); 76 | Assert.AreEqual(typeof(Dictionary), instance.GetType()); 77 | } 78 | 79 | [Test] 80 | public void Should_CreateNonGenericIDictionary() 81 | { 82 | var factory = new ObjectFactory(); 83 | var instance = factory.CreateEmptyObject(); 84 | 85 | Assert.NotNull(instance); 86 | Assert.AreEqual(0, instance.Count); 87 | Assert.IsTrue(instance is IDictionary); 88 | } 89 | 90 | [Test] 91 | public void Should_CreateNonGenericCustomDictionary() 92 | { 93 | var factory = new ObjectFactory(); 94 | var instance = factory.CreateEmptyObject(); 95 | 96 | Assert.NotNull(instance); 97 | Assert.AreEqual(0, instance.Count); 98 | Assert.IsTrue(instance is NonGenericDictionary); 99 | Assert.IsTrue(instance is IDictionary); 100 | } 101 | 102 | [Test] 103 | public void Should_CreateEmptyByteArray() 104 | { 105 | var factory = new ObjectFactory(); 106 | var instance = factory.CreateEmptyObject(); 107 | 108 | Assert.NotNull(instance); 109 | Assert.AreEqual(0, instance.Length); 110 | Assert.AreEqual(typeof(byte[]), instance.GetType()); 111 | } 112 | 113 | [Test] 114 | public void Should_CreatePopulatedByteArray() 115 | { 116 | var factory = new ObjectFactory(); 117 | var instance = factory.CreateEmptyObject(10); 118 | 119 | Assert.NotNull(instance); 120 | Assert.AreEqual(10, instance.Length); 121 | Assert.AreEqual(typeof(byte[]), instance.GetType()); 122 | } 123 | 124 | [Test] 125 | public void Should_CreatePopulatedMultidimensionalByteArray() 126 | { 127 | var factory = new ObjectFactory(); 128 | var testArray = new byte[2, 3] { { 1, 2, 3 }, { 4, 5, 6 } }; 129 | var instance = factory.CreateEmptyObject(new object[] { 2, 3 }); 130 | 131 | Assert.NotNull(instance); 132 | Assert.AreEqual(typeof(byte[,]), instance.GetType()); 133 | Assert.AreEqual(testArray.Rank, instance.Rank); 134 | Assert.AreEqual(testArray.GetLength(0), instance.GetLength(0)); 135 | Assert.AreEqual(testArray.GetLength(1), instance.GetLength(1)); 136 | } 137 | 138 | [Test] 139 | public void Should_CreatePopulatedMultidimensionalByteArrayViaIntArrayDimensions() 140 | { 141 | var factory = new ObjectFactory(); 142 | var testArray = new byte[2, 3] { { 1, 2, 3 }, { 4, 5, 6 } }; 143 | var instance = factory.CreateEmptyObject(new int[] { 2, 3 }); 144 | 145 | Assert.NotNull(instance); 146 | Assert.AreEqual(typeof(byte[,]), instance.GetType()); 147 | Assert.AreEqual(testArray.Rank, instance.Rank); 148 | Assert.AreEqual(testArray.GetLength(0), instance.GetLength(0)); 149 | Assert.AreEqual(testArray.GetLength(1), instance.GetLength(1)); 150 | } 151 | 152 | [Test] 153 | public void Should_CreatePopulatedMultidimensionalByteArrayViaIntDimensions() 154 | { 155 | var factory = new ObjectFactory(); 156 | var testArray = new byte[2, 3] { { 1, 2, 3 }, { 4, 5, 6 } }; 157 | var instance = factory.CreateEmptyObject(2, 3); 158 | 159 | Assert.NotNull(instance); 160 | Assert.AreEqual(typeof(byte[,]), instance.GetType()); 161 | Assert.AreEqual(testArray.Rank, instance.Rank); 162 | Assert.AreEqual(testArray.GetLength(0), instance.GetLength(0)); 163 | Assert.AreEqual(testArray.GetLength(1), instance.GetLength(1)); 164 | } 165 | 166 | [Test] 167 | public void Should_CreatePopulatedMultidimensionalByteArrayViaList() 168 | { 169 | var factory = new ObjectFactory(); 170 | var testArray = new byte[2, 3] { { 1, 2, 3 }, { 4, 5, 6 } }; 171 | var instance = factory.CreateEmptyObject(new List { 2, 3 }); 172 | 173 | Assert.NotNull(instance); 174 | Assert.AreEqual(typeof(byte[,]), instance.GetType()); 175 | Assert.AreEqual(testArray.Rank, instance.Rank); 176 | Assert.AreEqual(testArray.GetLength(0), instance.GetLength(0)); 177 | Assert.AreEqual(testArray.GetLength(1), instance.GetLength(1)); 178 | } 179 | 180 | [Test] 181 | public void Should_CreateByteArrayOfLength() 182 | { 183 | var factory = new ObjectFactory(); 184 | var instance = factory.CreateEmptyObject(32); 185 | 186 | Assert.NotNull(instance); 187 | Assert.AreEqual(32, instance.Length); 188 | Assert.AreEqual(typeof(byte[]), instance.GetType()); 189 | } 190 | 191 | [Test] 192 | public void Should_CreateEmptyHashtable() 193 | { 194 | var factory = new ObjectFactory(); 195 | var instance = factory.CreateEmptyObject(); 196 | 197 | Assert.NotNull(instance); 198 | Assert.AreEqual(0, instance.Count); 199 | Assert.AreEqual(typeof(Hashtable), instance.GetType()); 200 | } 201 | 202 | #if FEATURE_CUSTOM_VALUETUPLE 203 | [Test] 204 | public void Should_CreateValueTuple() 205 | { 206 | var factory = new ObjectFactory(); 207 | var instance = factory.CreateEmptyObject<(int,string)>(); 208 | 209 | Assert.NotNull(instance); 210 | Assert.AreEqual(typeof((int,string)), instance.GetType()); 211 | } 212 | #endif 213 | 214 | [Test] 215 | public void Should_CreateGenericSingularTuple() 216 | { 217 | var factory = new ObjectFactory(); 218 | var instance = factory.CreateEmptyObject>(); 219 | 220 | Assert.NotNull(instance); 221 | Assert.AreEqual(typeof(Tuple), instance.GetType()); 222 | } 223 | 224 | [Test] 225 | public void Should_CreateSingularTuple() 226 | { 227 | var factory = new ObjectFactory(); 228 | var instance = factory.CreateEmptyObject(typeof(Tuple)); 229 | 230 | Assert.NotNull(instance); 231 | Assert.AreEqual(typeof(Tuple), instance.GetType()); 232 | } 233 | 234 | [Test] 235 | public void Should_CreateGenericTuple() 236 | { 237 | var factory = new ObjectFactory(); 238 | var instance = factory.CreateEmptyObject>(); 239 | 240 | Assert.NotNull(instance); 241 | Assert.AreEqual(typeof(Tuple), instance.GetType()); 242 | } 243 | 244 | [Test] 245 | public void Should_CreateNonGenericTuple() 246 | { 247 | var factory = new ObjectFactory(); 248 | var instance = factory.CreateEmptyObject(typeof(Tuple)); 249 | 250 | Assert.NotNull(instance); 251 | Assert.AreEqual(typeof(Tuple), instance.GetType()); 252 | } 253 | 254 | [Test] 255 | public void Should_CreateNullString() 256 | { 257 | var factory = new ObjectFactory(); 258 | var instance = factory.CreateEmptyObject(); 259 | 260 | Assert.IsNull(instance); 261 | } 262 | 263 | [Test] 264 | public void Should_CreateInt() 265 | { 266 | var factory = new ObjectFactory(); 267 | var instance = factory.CreateEmptyObject(); 268 | 269 | Assert.NotNull(instance); 270 | Assert.AreEqual(typeof(int), instance.GetType()); 271 | Assert.AreEqual(0, instance); 272 | } 273 | 274 | [Test] 275 | public void Should_CreateNewStringUsingInitializer() 276 | { 277 | var factory = new ObjectFactory(); 278 | var instance = factory.CreateEmptyObject(() => string.Empty); 279 | Assert.AreEqual(instance.GetType(), typeof(string)); 280 | Assert.AreEqual(instance, string.Empty); 281 | } 282 | 283 | [Test] 284 | public void Should_CreateNullableInt() 285 | { 286 | var factory = new ObjectFactory(); 287 | var instance = factory.CreateEmptyObject(); 288 | 289 | Assert.IsNull(instance); 290 | } 291 | 292 | [Test] 293 | public void Should_CreateNullableIntUsingInitializer() 294 | { 295 | var factory = new ObjectFactory(); 296 | var instance = factory.CreateEmptyObject(() => 0); 297 | 298 | Assert.NotNull(instance); 299 | Assert.AreEqual(typeof(int), instance.GetType()); 300 | } 301 | 302 | [Test] 303 | public void Should_CreateObjectWithExplicitlyImplementedInterfaceDeclaredGenericProperty() 304 | { 305 | var factory = new ObjectFactory(); 306 | var instance = factory.CreateEmptyObject(typeof(ObjectWithExplicitlyImplementedInterfaceDeclaredGenericProperty)); 307 | 308 | Assert.NotNull(instance); 309 | Assert.AreEqual( 310 | typeof(ObjectWithExplicitlyImplementedInterfaceDeclaredGenericProperty), 311 | instance.GetType()); 312 | } 313 | 314 | [Test] 315 | public void Should_CreateReadOnlyCollection() 316 | { 317 | var factory = new ObjectFactory(); 318 | var collection = new List { 1, 2, 3, 4, 5 }.AsReadOnly(); 319 | var instance = factory.CreateEmptyObject(collection.GetExtendedType()); 320 | Assert.NotNull(instance); 321 | Assert.AreEqual( 322 | collection.GetExtendedType(), 323 | instance.GetType()); 324 | } 325 | 326 | [Test] 327 | public void Should_CreateTypeWithPrivateConstructor() 328 | { 329 | var factory = new ObjectFactory(); 330 | var instance = factory.CreateEmptyObject(typeof(PrivateConstructorObject)); 331 | Assert.NotNull(instance); 332 | Assert.AreEqual( 333 | typeof(PrivateConstructorObject), 334 | instance.GetType()); 335 | } 336 | } 337 | } 338 | -------------------------------------------------------------------------------- /TypeSupport/TypeSupport.Tests/ObjectHashcodeMapTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using NUnit.Framework; 3 | using TypeSupport.Extensions; 4 | using TypeSupport.Tests.TestObjects; 5 | 6 | namespace TypeSupport.Tests 7 | { 8 | [TestFixture] 9 | public class ObjectHashcodeMapTests 10 | { 11 | [SetUp] 12 | public void Setup() 13 | { 14 | 15 | } 16 | 17 | [Test] 18 | public void Should_Add_Hashcode() 19 | { 20 | var map = new ObjectHashcodeMap(); 21 | var obj = new BasicObject(1); 22 | map.Add(obj); 23 | 24 | Assert.AreEqual(1, map.Count); 25 | map.Contains(obj); 26 | } 27 | 28 | [Test] 29 | public void Should_Add_Hashcode_ByHashcodeType() 30 | { 31 | var map = new ObjectHashcodeMap(); 32 | var obj = new BasicObject(1); 33 | map.Add(obj.GetHashCode(), obj.GetType()); 34 | 35 | Assert.AreEqual(1, map.Count); 36 | map.Contains(obj); 37 | } 38 | 39 | [Test] 40 | public void Should_Add_Hashcode_ByHashcodeExtendedType() 41 | { 42 | var map = new ObjectHashcodeMap(); 43 | var obj = new BasicObject(1); 44 | map.Add(obj.GetHashCode(), obj.GetExtendedType()); 45 | 46 | Assert.AreEqual(1, map.Count); 47 | map.Contains(obj); 48 | } 49 | 50 | [Test] 51 | public void ShouldNot_Add_Duplicate_Hashcode() 52 | { 53 | var map = new ObjectHashcodeMap(); 54 | var obj = new BasicObject(1); 55 | map.Add(obj); 56 | map.Add(obj); 57 | 58 | Assert.AreEqual(1, map.Count); 59 | map.Contains(obj); 60 | } 61 | 62 | [Test] 63 | public void Should_Add_MultipleHashcodes() 64 | { 65 | var map = new ObjectHashcodeMap(); 66 | var obj = new BasicObject(1); 67 | var obj2 = new BasicObject(2); 68 | var obj3 = new BasicObject(3); 69 | map.Add(obj); 70 | map.Add(obj2); 71 | map.Add(obj3); 72 | 73 | Assert.AreEqual(3, map.Count); 74 | map.Contains(obj); 75 | map.Contains(obj2); 76 | map.Contains(obj3); 77 | } 78 | 79 | [Test] 80 | public void Should_Contain_AllOverloads() 81 | { 82 | var map = new ObjectHashcodeMap(); 83 | var obj = new BasicObject(1); 84 | map.Add(obj); 85 | 86 | Assert.AreEqual(1, map.Count); 87 | map.Contains(obj); 88 | map.Contains(obj.GetHashCode(), obj.GetType()); 89 | map.Contains(new ObjectHashcode(obj.GetHashCode(), obj.GetType())); 90 | } 91 | 92 | [Test] 93 | public void Should_Throw_AddNullObject() 94 | { 95 | var map = new ObjectHashcodeMap(); 96 | Assert.Throws(() => map.Add(null)); 97 | } 98 | 99 | [Test] 100 | public void Should_Throw_AddNullType() 101 | { 102 | var map = new ObjectHashcodeMap(); 103 | Assert.Throws(() => map.Add(1, (Type)null)); 104 | } 105 | 106 | [Test] 107 | public void Should_Throw_AddNullExtendedType() 108 | { 109 | var map = new ObjectHashcodeMap(); 110 | Assert.Throws(() => map.Add(1, (ExtendedType)null)); 111 | } 112 | 113 | [Test] 114 | public void Should_Throw_ContainsNullType() 115 | { 116 | var map = new ObjectHashcodeMap(); 117 | Assert.Throws(() => map.Contains(1, (Type)null)); 118 | } 119 | 120 | [Test] 121 | public void Should_Throw_ContainsNullExtendedType() 122 | { 123 | var map = new ObjectHashcodeMap(); 124 | Assert.Throws(() => map.Contains(1, (ExtendedType)null)); 125 | } 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /TypeSupport/TypeSupport.Tests/TestObjects/BasicObject.cs: -------------------------------------------------------------------------------- 1 | #pragma warning disable 0649,0169 2 | namespace TypeSupport.Tests.TestObjects 3 | { 4 | [TestDecorated(1000)] 5 | public class BasicObject 6 | { 7 | [TestDecorated(789)] 8 | private readonly int _test; 9 | 10 | [TestDecorated(123)] 11 | public int Id { get; set; } 12 | 13 | public int Test => _test; 14 | 15 | public int FieldValue; 16 | 17 | public BasicObject(int id) 18 | { 19 | Id = id; 20 | FieldValue = id; 21 | _test = 0; 22 | } 23 | 24 | [TestDecorated(456)] 25 | public bool TestMethod() => true; 26 | 27 | // do not remove 28 | public override string ToString() => base.ToString(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /TypeSupport/TypeSupport.Tests/TestObjects/BasicObjectWithAttributes.cs: -------------------------------------------------------------------------------- 1 | #pragma warning disable 0649,0169 2 | using System.ComponentModel; 3 | using System.Runtime.Serialization; 4 | 5 | namespace TypeSupport.Tests.TestObjects 6 | { 7 | [Category("CategoryName")] 8 | [Description("Description value")] 9 | public class BasicObjectWithAttributes 10 | { 11 | [IgnoreDataMember] 12 | public int Id { get; set; } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /TypeSupport/TypeSupport.Tests/TestObjects/BasicObjectWithConstructor.cs: -------------------------------------------------------------------------------- 1 | #pragma warning disable 0649,0169 2 | namespace TypeSupport.Tests.TestObjects 3 | { 4 | public class BasicObjectWithConstructor 5 | { 6 | public int Id { get; set; } 7 | public BasicObjectWithConstructor() { } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /TypeSupport/TypeSupport.Tests/TestObjects/BasicObjectWithParamAttributes.cs: -------------------------------------------------------------------------------- 1 | #pragma warning disable 0649,0169 2 | using System; 3 | using System.ComponentModel; 4 | using System.Linq.Expressions; 5 | using System.Runtime.Serialization; 6 | 7 | namespace TypeSupport.Tests.TestObjects 8 | { 9 | [Category("CategoryName")] 10 | [Description("Description value")] 11 | public class BasicObjectWithParamAttributes 12 | { 13 | [IgnoreDataMember] 14 | public int Id { get; set; } 15 | 16 | [AttributeWithParams("Value1 / (Value2 / {0})", SortKeyInputType.UniversePerK)] 17 | public decimal Number => 3.1415m; 18 | } 19 | 20 | public class AttributeWithParamsAttribute : Attribute 21 | { 22 | private string _dynamicClause; 23 | private SortKeyInputType[] _inputTypes; 24 | 25 | public LambdaExpression SortExpression { get; set; } 26 | public AttributeWithParamsAttribute(string dynamicClause, params SortKeyInputType[] inputTypes) 27 | { 28 | _dynamicClause = dynamicClause; 29 | _inputTypes = inputTypes; 30 | } 31 | 32 | public static T CallNotSupported() => throw new NotSupportedException(); 33 | } 34 | 35 | public enum SortKeyInputType 36 | { 37 | None, 38 | UniversePerK, 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /TypeSupport/TypeSupport.Tests/TestObjects/DifferentBasicObject.cs: -------------------------------------------------------------------------------- 1 | namespace TypeSupport.Tests.TestObjects 2 | { 3 | public class DifferentBasicObject : BasicObject 4 | { 5 | public DifferentBasicObject(int id) : base(id) { } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /TypeSupport/TypeSupport.Tests/TestObjects/IInterfaceWithImplementations.cs: -------------------------------------------------------------------------------- 1 | #pragma warning disable 0649,0169 2 | namespace TypeSupport.Tests.TestObjects 3 | { 4 | public interface IInterfaceWithImplementations 5 | { 6 | } 7 | 8 | public interface IInterfaceWithGenericImplementations 9 | { 10 | } 11 | 12 | public interface IInterfaceWithGenericImplementations 13 | { 14 | } 15 | 16 | public class InterfaceWithImplementations1 : IInterfaceWithImplementations { } 17 | public class InterfaceWithImplementations2 : IInterfaceWithImplementations { } 18 | public class InterfaceWithImplementations3 : IInterfaceWithImplementations { } 19 | public class InterfaceWithImplementations4 : IInterfaceWithImplementations { } 20 | public class InterfaceWithImplementations5 : IInterfaceWithImplementations 21 | { 22 | public int Value { get; } 23 | public InterfaceWithImplementations5(int value) 24 | { 25 | Value = value; 26 | } 27 | } 28 | 29 | public class InterfaceWithGenericImplementations : IInterfaceWithGenericImplementations 30 | { 31 | 32 | } 33 | 34 | public class InterfaceWithMultiGenericImplementations : IInterfaceWithGenericImplementations 35 | { 36 | 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /TypeSupport/TypeSupport.Tests/TestObjects/IInterfaceWithoutImplementations.cs: -------------------------------------------------------------------------------- 1 | #pragma warning disable 0649,0169 2 | namespace TypeSupport.Tests.TestObjects 3 | { 4 | public interface IInterfaceWithoutImplementations 5 | { 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /TypeSupport/TypeSupport.Tests/TestObjects/InheritedObject.cs: -------------------------------------------------------------------------------- 1 | #pragma warning disable 0649,0169 2 | namespace TypeSupport.Tests.TestObjects 3 | { 4 | public class InheritedObject : BaseInheritedObject 5 | { 6 | private readonly string _name; 7 | public new int Id { get; } 8 | } 9 | 10 | public class BaseInheritedObject 11 | { 12 | private readonly string _baseName; 13 | public int BaseId { get; set; } 14 | public int? Id { get; set; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /TypeSupport/TypeSupport.Tests/TestObjects/NonGenericDictionary.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | 5 | namespace TypeSupport.Tests.TestObjects 6 | { 7 | public class NonGenericDictionary : IDictionary 8 | { 9 | private readonly Dictionary _internal = new Dictionary(); 10 | 11 | public object this[object key] 12 | { 13 | get => _internal[key]; 14 | set => _internal[key] = value; 15 | } 16 | 17 | public bool IsFixedSize { get; } 18 | 19 | public bool IsReadOnly { get; } 20 | 21 | public ICollection Keys => _internal.Keys; 22 | 23 | public ICollection Values => _internal.Values; 24 | 25 | public int Count => _internal.Count; 26 | 27 | public bool IsSynchronized { get; } 28 | 29 | public object SyncRoot => new object(); 30 | 31 | public void Add(object key, object value) => _internal.Add(key, value); 32 | 33 | public void Clear() => _internal.Clear(); 34 | 35 | public bool Contains(object key) => _internal.ContainsKey(key); 36 | 37 | public void CopyTo(Array array, int index) 38 | { 39 | // no implementation required 40 | } 41 | 42 | public IDictionaryEnumerator GetEnumerator() => _internal.GetEnumerator(); 43 | 44 | public void Remove(object key) 45 | { 46 | _internal.Remove(key); 47 | } 48 | 49 | IEnumerator IEnumerable.GetEnumerator() => _internal.GetEnumerator(); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /TypeSupport/TypeSupport.Tests/TestObjects/ObjectWithExplicitlyImplementedInterfaceDeclaredGenericProperty.cs: -------------------------------------------------------------------------------- 1 | namespace TypeSupport.Tests.TestObjects 2 | { 3 | 4 | public interface IValue 5 | { 6 | T Value { get; } 7 | } 8 | 9 | public class ObjectWithExplicitlyImplementedInterfaceDeclaredGenericProperty : IValue 10 | { 11 | T IValue.Value { get; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /TypeSupport/TypeSupport.Tests/TestObjects/ObjectWithGetProperty.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace TypeSupport.Tests.TestObjects 6 | { 7 | public class ObjectWithGetProperty 8 | { 9 | public string Name { get; } = "Sarah"; 10 | public int Age { get; set; } = 6; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /TypeSupport/TypeSupport.Tests/TestObjects/ObjectWithNamedTuple.cs: -------------------------------------------------------------------------------- 1 | namespace TypeSupport.Tests.TestObjects 2 | { 3 | #if FEATURE_CUSTOM_VALUETUPLE 4 | public class ObjectWithNamedTuple 5 | { 6 | public (int id, string value) TupleValue { get; } 7 | 8 | public ObjectWithNamedTuple() 9 | { 10 | TupleValue = (1, "test"); 11 | } 12 | public ObjectWithNamedTuple((int id, string value) tuple) 13 | { 14 | TupleValue = tuple; 15 | } 16 | } 17 | #endif 18 | } 19 | -------------------------------------------------------------------------------- /TypeSupport/TypeSupport.Tests/TestObjects/OperatorOverloadObject.cs: -------------------------------------------------------------------------------- 1 | namespace TypeSupport.Tests.TestObjects 2 | { 3 | public class OperatorOverloadObject 4 | { 5 | public int Id { get; set; } 6 | 7 | public override int GetHashCode() => Id; 8 | 9 | public override bool Equals(object obj) 10 | { 11 | if (obj == null) 12 | return false; 13 | if (obj.GetType() != typeof(OperatorOverloadObject)) 14 | return false; 15 | var typedObj = (OperatorOverloadObject)obj; 16 | return Id.Equals(typedObj.Id); 17 | } 18 | 19 | public static bool operator ==(OperatorOverloadObject a, OperatorOverloadObject b) 20 | { 21 | if (ReferenceEquals(a, b)) 22 | return true; 23 | if (ReferenceEquals(a, null)) 24 | return false; 25 | if (ReferenceEquals(b, null)) 26 | return false; 27 | return a.Id.Equals(b.Id); 28 | } 29 | 30 | public static bool operator !=(OperatorOverloadObject a, OperatorOverloadObject b) => !a.Equals(b); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /TypeSupport/TypeSupport.Tests/TestObjects/PrivateConstructorObject.cs: -------------------------------------------------------------------------------- 1 | namespace TypeSupport.Tests.TestObjects 2 | { 3 | public class PrivateConstructorObject 4 | { 5 | private T _value; 6 | private PrivateConstructorObject(T value) { _value = value; } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /TypeSupport/TypeSupport.Tests/TestObjects/ReadOnlyObject.cs: -------------------------------------------------------------------------------- 1 | #pragma warning disable 0649,0169 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | 5 | namespace TypeSupport.Tests.TestObjects 6 | { 7 | public class ReadOnlyObject 8 | { 9 | private readonly Dictionary _inner = new Dictionary(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /TypeSupport/TypeSupport.Tests/TestObjects/StaticTypeImplementation.cs: -------------------------------------------------------------------------------- 1 | namespace TypeSupport.Tests.TestObjects 2 | { 3 | public class StaticTypeImplementation : IStaticTypeInterface 4 | { 5 | public static IStaticTypeInterface Instance { get; } = new StaticTypeImplementation(); 6 | } 7 | 8 | public interface IStaticTypeInterface { } 9 | } 10 | -------------------------------------------------------------------------------- /TypeSupport/TypeSupport.Tests/TestObjects/StructObject.cs: -------------------------------------------------------------------------------- 1 | #pragma warning disable 0649,0169 2 | using System; 3 | 4 | namespace TypeSupport.Tests.TestObjects 5 | { 6 | public struct StructObject : IEquatable 7 | { 8 | public int A { get; } 9 | public int B { get; } 10 | public string C { get; } 11 | public StructObject(int a, int b, string c) 12 | { 13 | A = a; 14 | B = b; 15 | C = c; 16 | } 17 | 18 | public override int GetHashCode() 19 | { 20 | return base.GetHashCode(); 21 | } 22 | 23 | public override bool Equals(object obj) 24 | { 25 | if (obj.GetType() != typeof(StructObject)) 26 | return false; 27 | return base.Equals((StructObject)obj); 28 | } 29 | 30 | public bool Equals(StructObject other) 31 | { 32 | return A == other.A && B == other.B && C == other.C; 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /TypeSupport/TypeSupport.Tests/TestObjects/TestDecoratedAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace TypeSupport.Tests.TestObjects 4 | { 5 | public class TestDecoratedAttribute : Attribute 6 | { 7 | public int Value { get; } 8 | 9 | public TestDecoratedAttribute(int value) 10 | { 11 | Value = value; 12 | } 13 | 14 | public TestDecoratedAttribute() 15 | { 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /TypeSupport/TypeSupport.Tests/TestObjects/VisibilityObject.cs: -------------------------------------------------------------------------------- 1 | namespace TypeSupport.Tests.TestObjects 2 | { 3 | public class VisibilityObject 4 | { 5 | public bool PublicProperty { get; set; } 6 | private bool PrivateProperty { get; set; } 7 | protected bool ProtectedProperty { get; set; } 8 | internal bool InternalProperty { get; set; } 9 | 10 | public bool PublicField = false; 11 | private bool _privateField = false; 12 | protected bool ProtectedField = false; 13 | internal bool _internalField = false; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /TypeSupport/TypeSupport.Tests/TypeRegistryTests.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using System; 3 | using TypeSupport.Tests.TestObjects; 4 | 5 | namespace TypeSupport.Tests 6 | { 7 | [TestFixture] 8 | public class TypeRegistryTests 9 | { 10 | [Test] 11 | public void Should_CreateRegistryMapping() 12 | { 13 | var registry = TypeRegistry.Configure(config => { 14 | config.AddMapping(); 15 | }); 16 | 17 | Assert.AreEqual(0, registry.Factories.Count); 18 | Assert.AreEqual(1, registry.Mappings.Count); 19 | Assert.IsTrue(registry.ContainsType(typeof(IInterfaceWithImplementations))); 20 | } 21 | 22 | [Test] 23 | public void Should_CreateTypeMap() 24 | { 25 | var typeMap = new TypeConfiguration().Create(); 26 | 27 | Assert.AreEqual(typeof(int), typeMap.Source); 28 | Assert.AreEqual(typeof(string), typeMap.Destination); 29 | } 30 | 31 | [Test] 32 | public void Should_CreateTypeFactory() 33 | { 34 | var typeFactory = new TypeConfiguration().CreateUsing(() => "value"); 35 | 36 | Assert.AreEqual(typeof(int), typeFactory.Source); 37 | Assert.NotNull(typeFactory.Factory); 38 | Assert.AreEqual(typeof(Func), typeFactory.Factory.GetType()); 39 | } 40 | 41 | [Test] 42 | public void Should_CreateRegistryFactory() 43 | { 44 | var registry = TypeRegistry.Configure(config => { 45 | config.AddFactory(() => new InterfaceWithImplementations1()); 46 | }); 47 | 48 | Assert.AreEqual(0, registry.Mappings.Count); 49 | Assert.AreEqual(1, registry.Factories.Count); 50 | Assert.IsTrue(registry.ContainsFactoryType(typeof(IInterfaceWithImplementations))); 51 | } 52 | 53 | [Test] 54 | public void Should_CreateObjectFromFactory() 55 | { 56 | var testValue = 123; 57 | var registry = TypeRegistry.Configure(config => { 58 | config.AddFactory(() => new InterfaceWithImplementations5(testValue)); 59 | }); 60 | 61 | Assert.AreEqual(1, registry.Factories.Count); 62 | var factory = new ObjectFactory(registry); 63 | var emptyObject = factory.CreateEmptyObject(); 64 | Assert.NotNull(emptyObject); 65 | Assert.AreEqual(typeof(InterfaceWithImplementations5), emptyObject.GetType()); 66 | // ensure our factory created the correct class with a value we defined 67 | Assert.AreEqual(testValue, ((InterfaceWithImplementations5)emptyObject).Value); 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /TypeSupport/TypeSupport.Tests/TypeSupport.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netcoreapp3.1;netcoreapp2.1;net40;net45;net46;net461;net462;net47;net471;net472;net48;net5;net6;net7 5 | true 6 | true 7 | ..\TypeSupportStrongNameKey.snk 8 | 9 | 10 | 11 | FEATURE_CUSTOM_ATTRIBUTES;FEATURE_CUSTOM_TYPEINFO;FEATURE_GETMETHOD;FEATURE_SETVALUE;FEATURE_TASK;FEATURE_ASSEMBLYBUILDER 12 | 13 | 14 | 15 | FEATURE_CUSTOM_VALUETUPLE;FEATURE_CUSTOM_ATTRIBUTES;FEATURE_CUSTOM_TYPEINFO;FEATURE_GETMETHOD;FEATURE_SETVALUE;FEATURE_TASK;FEATURE_ASSEMBLYBUILDER 16 | 17 | 18 | 19 | 1701;1702;0169;0649;0414;0169 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | all 36 | runtime; build; native; contentfiles; analyzers 37 | 38 | 39 | 40 | all 41 | runtime; build; native; contentfiles; analyzers; buildtransitive 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /TypeSupport/TypeSupport.Tests/TypeSupportOptionsTests.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using System; 3 | 4 | namespace TypeSupport.Tests 5 | { 6 | [TestFixture] 7 | public class TypeSupportOptionsTests 8 | { 9 | [Test] 10 | public void Should_TypeSupportOptions_AllBeCorrect() 11 | { 12 | var allOptions = TypeSupportOptions.Attributes 13 | | TypeSupportOptions.Caching 14 | | TypeSupportOptions.Collections 15 | | TypeSupportOptions.ConcreteTypes 16 | | TypeSupportOptions.Constructors 17 | | TypeSupportOptions.Enums 18 | | TypeSupportOptions.Fields 19 | | TypeSupportOptions.Generics 20 | | TypeSupportOptions.Indexers 21 | | TypeSupportOptions.Properties 22 | | TypeSupportOptions.Methods; 23 | Assert.AreEqual(allOptions, TypeSupportOptions.All); 24 | } 25 | 26 | [Test] 27 | public void Should_TypeSupportOptions_AllExceptCachingBeCorrect() 28 | { 29 | var allOptions = TypeSupportOptions.Attributes 30 | | TypeSupportOptions.Collections 31 | | TypeSupportOptions.ConcreteTypes 32 | | TypeSupportOptions.Constructors 33 | | TypeSupportOptions.Enums 34 | | TypeSupportOptions.Fields 35 | | TypeSupportOptions.Generics 36 | | TypeSupportOptions.Indexers 37 | | TypeSupportOptions.Properties 38 | | TypeSupportOptions.Methods; 39 | Assert.AreEqual(allOptions, TypeSupportOptions.AllExceptCaching); 40 | } 41 | 42 | [Test] 43 | public void Should_TypeSupportOptions_PowerOfTwos() 44 | { 45 | var values = Enum.GetValues(typeof(TypeSupportOptions)); 46 | foreach(int value in values) 47 | { 48 | if ((TypeSupportOptions)value != TypeSupportOptions.All && (TypeSupportOptions)value != TypeSupportOptions.AllExceptCaching && value > 1) 49 | Assert.AreEqual(0, value % 2, $"Value is invalid enum flags value {value} ({(TypeSupportOptions)value})"); 50 | } 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /TypeSupport/TypeSupport.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27703.2042 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TypeSupport", "TypeSupport\TypeSupport.csproj", "{0BE478AA-74EA-42DE-87A6-D46CE8B44733}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TypeSupport.Tests", "TypeSupport.Tests\TypeSupport.Tests.csproj", "{BD05BC04-4883-4001-A4F2-32E544EB4C2C}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {0BE478AA-74EA-42DE-87A6-D46CE8B44733}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {0BE478AA-74EA-42DE-87A6-D46CE8B44733}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {0BE478AA-74EA-42DE-87A6-D46CE8B44733}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {0BE478AA-74EA-42DE-87A6-D46CE8B44733}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {BD05BC04-4883-4001-A4F2-32E544EB4C2C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {BD05BC04-4883-4001-A4F2-32E544EB4C2C}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {BD05BC04-4883-4001-A4F2-32E544EB4C2C}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {BD05BC04-4883-4001-A4F2-32E544EB4C2C}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {CA8D556C-910B-429F-A835-27673C920E77} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /TypeSupport/TypeSupport/Assembly/AssemblyManager.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | using System.Reflection.Emit; 4 | 5 | namespace TypeSupport.Assembly 6 | { 7 | /// 8 | /// A holding object for all of the objects required for creating a new assembly 9 | /// 10 | public class AssemblyManager 11 | { 12 | public AssemblyName Name { get; set; } 13 | public AssemblyBuilder Assembly { get; set; } 14 | public ModuleBuilder Module { get; set; } 15 | public AppDomain Domain { get; set; } 16 | public AssemblyManager(AssemblyName name, AssemblyBuilder assembly, ModuleBuilder module, AppDomain domain) 17 | { 18 | Name = name; 19 | Assembly = assembly; 20 | Module = module; 21 | Domain = domain; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /TypeSupport/TypeSupport/Assembly/CacheKey.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace TypeSupport.Assembly 4 | { 5 | /// 6 | /// A composite cache key 7 | /// 8 | public struct CacheKey 9 | { 10 | public Type Type; 11 | public TypeSupportOptions Options; 12 | public CacheKey(Type type, TypeSupportOptions options) 13 | { 14 | Type = type; 15 | Options = options; 16 | } 17 | 18 | public override int GetHashCode() 19 | { 20 | var hashCode = 23; 21 | hashCode = hashCode * 31 + (int)Options; 22 | hashCode = hashCode * 31 + Type.GetHashCode(); 23 | return hashCode; 24 | } 25 | 26 | public override bool Equals(object obj) 27 | { 28 | if (obj == null || obj.GetType() != typeof(CacheKey)) 29 | return false; 30 | var objTyped = (CacheKey)obj; 31 | return objTyped.Options == Options && objTyped.Type.Equals(Type); 32 | } 33 | 34 | public override string ToString() => $"{(int)Options}-({Options}) {Type.FullName}"; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /TypeSupport/TypeSupport/Assembly/DynamicAssemblyCache.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Concurrent; 3 | using System.Reflection; 4 | using System.Reflection.Emit; 5 | 6 | namespace TypeSupport.Assembly 7 | { 8 | /// 9 | /// Cache for storing dynamically build assemblies 10 | /// 11 | public static class DynamicAssemblyCache 12 | { 13 | private static readonly ConcurrentDictionary _assemblies = new(); 14 | 15 | /// 16 | /// Get the cached assembly managers 17 | /// 18 | public static ConcurrentDictionary Assemblies => _assemblies; 19 | 20 | /// 21 | /// Get an assembly from the assembly cache. If it does not exist, a new one will be created for you. 22 | /// 23 | /// 24 | /// 25 | public static ModuleBuilder Get(string assemblyName) 26 | { 27 | AssemblyManager manager = null; 28 | 29 | if (_assemblies.ContainsKey(assemblyName)) 30 | { 31 | // grab the assembly from the cache 32 | manager = _assemblies[assemblyName]; 33 | } 34 | else 35 | { 36 | // Create the new assembly 37 | // Create the assembly and cache it 38 | var name = new AssemblyName(assemblyName); 39 | var domain = System.Threading.Thread.GetDomain(); 40 | #if FEATURE_ASSEMBLYBUILDER 41 | var assembly = AssemblyBuilder.DefineDynamicAssembly(name, AssemblyBuilderAccess.Run); 42 | #else 43 | var assembly = domain.DefineDynamicAssembly(name, AssemblyBuilderAccess.Run); 44 | #endif 45 | var module = assembly.DefineDynamicModule(name.Name); 46 | var assemblyManager = new AssemblyManager(name, assembly, module, domain); 47 | 48 | // add the assembly to the cache 49 | _assemblies.TryAdd(assemblyName, assemblyManager); 50 | manager = assemblyManager; 51 | } 52 | return manager.Module; 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /TypeSupport/TypeSupport/Assembly/ExtendedTypeCache.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Threading; 4 | using TypeSupport.Extensions; 5 | using TypeSupport.Assembly; 6 | 7 | namespace TypeSupport 8 | { 9 | /// 10 | /// Caches extended types 11 | /// 12 | public sealed class ExtendedTypeCache 13 | { 14 | private static readonly SemaphoreSlim _cacheLock = new (1); 15 | private static readonly ExtendedTypeCache _instance = new (); 16 | 17 | /// 18 | /// Get an instance of the type cache 19 | /// 20 | public static ExtendedTypeCache Instance => _instance; 21 | 22 | /// 23 | /// Get the cached types registry 24 | /// 25 | public IDictionary CachedTypes { get; set; } 26 | 27 | static ExtendedTypeCache() 28 | { 29 | _instance.CachedTypes = new Dictionary(); 30 | } 31 | 32 | private ExtendedTypeCache() 33 | { 34 | } 35 | 36 | /// 37 | /// Clear the cache 38 | /// 39 | public static void Clear() 40 | { 41 | _cacheLock.Wait(); 42 | try 43 | { 44 | Instance.CachedTypes.Clear(); 45 | } 46 | finally 47 | { 48 | _cacheLock.Release(); 49 | } 50 | } 51 | 52 | /// 53 | /// Returns true if the extended type is cached 54 | /// 55 | /// The type to lookup 56 | /// The options for the extended type 57 | /// 58 | public static bool Contains(Type type, TypeSupportOptions options) 59 | { 60 | _cacheLock.Wait(); 61 | try 62 | { 63 | return ContainsInternal(type, options); 64 | } 65 | finally 66 | { 67 | _cacheLock.Release(); 68 | } 69 | } 70 | 71 | /// 72 | /// Get an extended type from the cache 73 | /// 74 | /// The type to lookup 75 | /// The options for the extended type 76 | /// 77 | public static ExtendedType Get(Type type, TypeSupportOptions options) 78 | { 79 | var isCachingSupported = options.BitwiseHasFlag(TypeSupportOptions.Caching); 80 | if (!isCachingSupported) 81 | return null; 82 | 83 | _cacheLock.Wait(); 84 | try 85 | { 86 | if (!ContainsInternal(type, options)) 87 | return null; 88 | var key = GenerateKey(type, options); 89 | return Instance.CachedTypes[key]; 90 | } 91 | finally 92 | { 93 | _cacheLock.Release(); 94 | } 95 | } 96 | 97 | /// 98 | /// Get an extended type from the cache, or create it if it does not exist 99 | /// 100 | /// The type to lookup 101 | /// The options for the extended type 102 | /// 103 | public static ExtendedType GetOrCreate(Type type) 104 | => GetOrCreate(type, TypeSupportOptions.All); 105 | 106 | /// 107 | /// Get an extended type from the cache, or create it if it does not exist 108 | /// 109 | /// The type to lookup 110 | /// The options for the extended type 111 | /// 112 | public static ExtendedType GetOrCreate(Type type, TypeSupportOptions options) 113 | { 114 | var isCachingSupported = options.BitwiseHasFlag(TypeSupportOptions.Caching); 115 | if (!isCachingSupported) 116 | return new ExtendedType(type, options); 117 | 118 | if (type == null) 119 | throw new ArgumentNullException(nameof(type)); 120 | _cacheLock.Wait(); 121 | try 122 | { 123 | if (!ContainsInternal(type, options)) 124 | { 125 | var newExtendedType = new ExtendedType(type, options); 126 | // cache the type 127 | CacheTypeInternal(newExtendedType, options); 128 | return newExtendedType; 129 | } 130 | var key = GenerateKey(type, options); 131 | return Instance.CachedTypes[key]; 132 | } 133 | finally 134 | { 135 | _cacheLock.Release(); 136 | } 137 | } 138 | 139 | /// 140 | /// Cache an extended type 141 | /// 142 | /// The extended type to cache 143 | /// The options for the extended type 144 | public static void CacheType(ExtendedType type, TypeSupportOptions options) 145 | { 146 | var isCachingSupported = options.BitwiseHasFlag(TypeSupportOptions.Caching); 147 | if (!isCachingSupported) 148 | return; 149 | _cacheLock.Wait(); 150 | try 151 | { 152 | CacheTypeInternal(type, options); 153 | } 154 | finally 155 | { 156 | _cacheLock.Release(); 157 | } 158 | } 159 | 160 | /// 161 | /// Cache an extended type 162 | /// 163 | /// The extended type to cache 164 | /// The options for the extended type 165 | private static void CacheTypeInternal(ExtendedType type, TypeSupportOptions options) 166 | { 167 | var key = GenerateKey(type.Type, options); 168 | if (!Instance.CachedTypes.ContainsKey(key)) 169 | { 170 | Instance.CachedTypes.Add(key, type); 171 | if (key.Options == TypeSupportOptions.All) 172 | { 173 | // remove any types with options less than all 174 | RemoveLowerOptions(type.Type); 175 | } 176 | } 177 | } 178 | 179 | /// 180 | /// Returns true if the extended type is cached 181 | /// 182 | /// The type to lookup 183 | /// The options for the extended type 184 | /// 185 | private static bool ContainsInternal(Type type, TypeSupportOptions options) 186 | { 187 | var isCachingSupported = options.BitwiseHasFlag(TypeSupportOptions.Caching); 188 | if (!isCachingSupported) 189 | return false; 190 | if (options != TypeSupportOptions.All) 191 | { 192 | // does it exist with all options available? 193 | var allKey = new CacheKey(type, TypeSupportOptions.All); 194 | var containsAllKey = Instance.CachedTypes.ContainsKey(allKey); 195 | if (containsAllKey) return true; 196 | } 197 | // use the key as-is 198 | var key = new CacheKey(type, options); 199 | var containsKey = Instance.CachedTypes.ContainsKey(key); 200 | return containsKey; 201 | } 202 | 203 | /// 204 | /// Generates the type of key to use for the type cache 205 | /// 206 | /// The type to lookup 207 | /// The options for the extended type 208 | /// 209 | private static CacheKey GenerateKey(Type type, TypeSupportOptions options) 210 | { 211 | if (options != TypeSupportOptions.All) 212 | { 213 | // does it exist with all options available? 214 | var allKey = new CacheKey(type, TypeSupportOptions.All); 215 | var containsAllKey = Instance.CachedTypes.ContainsKey(allKey); 216 | if (containsAllKey) 217 | return allKey; 218 | } 219 | // use the key as-is 220 | var key = new CacheKey(type, options); 221 | return key; 222 | } 223 | 224 | /// 225 | /// Remove any cached types with options less than TypeSupportOptions.All 226 | /// 227 | /// The type to filter by 228 | private static void RemoveLowerOptions(Type type) 229 | { 230 | var typesToRemove = new List(); 231 | foreach (var cachedType in Instance.CachedTypes) 232 | { 233 | if (cachedType.Key.Type.Equals(type) && cachedType.Key.Options != TypeSupportOptions.All) 234 | typesToRemove.Add(cachedType.Key); 235 | } 236 | // remove types 237 | foreach (var typeToRemove in typesToRemove) 238 | Instance.CachedTypes.Remove(typeToRemove); 239 | } 240 | } 241 | } 242 | -------------------------------------------------------------------------------- /TypeSupport/TypeSupport/ExtendedField.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using TypeSupport.Extensions; 6 | 7 | namespace TypeSupport 8 | { 9 | /// 10 | /// Discovers the attributes of a field and provides access to field metadata 11 | /// 12 | public class ExtendedField : IAttributeInspection 13 | { 14 | private readonly FieldInfo _fieldInfo; 15 | private readonly TypeSupportOptions _typeSupportOptions; 16 | private readonly Lazy> _customAttributesCached; 17 | 18 | /// 19 | /// Original FieldInfo of the field 20 | /// 21 | public FieldInfo FieldInfo => _fieldInfo; 22 | 23 | /// 24 | /// Gets the name of the current member 25 | /// 26 | public string Name => _fieldInfo.Name; 27 | 28 | /// 29 | /// Gets the type of this field object 30 | /// 31 | public ExtendedType Type => _fieldInfo.FieldType?.GetExtendedType(_typeSupportOptions); 32 | 33 | /// 34 | /// Gets the base type of this field object 35 | /// 36 | public ExtendedType BaseType => _fieldInfo.FieldType.BaseType?.GetExtendedType(_typeSupportOptions); 37 | 38 | /// 39 | /// Gets the class object that was used to obtain this instance of MemberInfo 40 | /// 41 | public ExtendedType ReflectedType => _fieldInfo.ReflectedType?.GetExtendedType(_typeSupportOptions); 42 | 43 | /// 44 | /// Gets a collection that contains this member's custom attributes 45 | /// 46 | public IEnumerable CustomAttributes 47 | { 48 | get { 49 | return _customAttributesCached.Value; 50 | } 51 | } 52 | 53 | /// 54 | /// True if this field backs an auto-property 55 | /// 56 | public bool IsBackingField { get; private set; } 57 | 58 | /// 59 | /// True if field is defined as static 60 | /// 61 | public bool IsStatic { get; set; } 62 | 63 | /// 64 | /// True if field is defined as a constant 65 | /// 66 | public bool IsConstant { get; set; } 67 | 68 | /// 69 | /// True if field is defined as private 70 | /// 71 | public bool IsPrivate { get; set; } 72 | 73 | /// 74 | /// True if field is defined as public 75 | /// 76 | public bool IsPublic { get; set; } 77 | 78 | /// 79 | /// True if field is defined as protected 80 | /// 81 | public bool IsProtected { get; set; } 82 | 83 | /// 84 | /// True if field is defined as internal 85 | /// 86 | public bool IsInternal { get; set; } 87 | 88 | /// 89 | /// For backing fields, the property name it stores data for 90 | /// 91 | public string BackedPropertyName { get; private set; } 92 | 93 | /// 94 | /// For backing fields, the property it stores data for 95 | /// 96 | public ExtendedProperty BackedProperty { get; private set; } 97 | 98 | /// 99 | /// Create an extended field 100 | /// 101 | /// 102 | public ExtendedField(FieldInfo fieldInfo) : this(fieldInfo, TypeSupportOptions.All) { } 103 | 104 | /// 105 | /// Create an extended field 106 | /// 107 | /// 108 | /// The type support options to use for type inspection 109 | public ExtendedField(FieldInfo fieldInfo, TypeSupportOptions typeSupportOptions) 110 | { 111 | _fieldInfo = fieldInfo; 112 | _typeSupportOptions = typeSupportOptions; 113 | 114 | IsStatic = _fieldInfo.IsStatic; 115 | IsPrivate = _fieldInfo.IsPrivate; 116 | IsPublic = _fieldInfo.IsPublic; 117 | IsConstant = _fieldInfo.IsLiteral; 118 | IsProtected = _fieldInfo.IsFamily; 119 | IsInternal = _fieldInfo.IsAssembly; 120 | 121 | #if FEATURE_CUSTOM_ATTRIBUTES 122 | _customAttributesCached = new Lazy>(() => _fieldInfo.CustomAttributes); 123 | #else 124 | _customAttributesCached = new Lazy>(() => _fieldInfo.GetCustomAttributesData()); 125 | #endif 126 | var name = fieldInfo.Name; 127 | if (name.Contains("k__BackingField") || name.StartsWith("<")) 128 | { 129 | IsBackingField = true; 130 | var i = name.IndexOf("<"); 131 | var end = name.LastIndexOf(">"); 132 | 133 | BackedPropertyName = name.Substring(i + 1, end - (i + 1)); 134 | BackedProperty = ReflectedType.GetExtendedProperty(BackedPropertyName, fieldInfo.DeclaringType); 135 | } 136 | } 137 | 138 | public bool HasAttribute() where TAttribute : class => Attribute.GetCustomAttribute(this, typeof(TAttribute)) != null; 139 | 140 | public bool HasAttribute(Type attributeType) => Attribute.GetCustomAttribute(this, attributeType) != null; 141 | 142 | public TAttribute GetAttribute() where TAttribute : class => Attribute.GetCustomAttribute(this, typeof(TAttribute)) as TAttribute; 143 | 144 | public Attribute GetAttribute(Type attributeType) => Attribute.GetCustomAttribute(this, attributeType); 145 | 146 | /// 147 | /// Get all custom attributes on field 148 | /// 149 | /// 150 | public IEnumerable GetAttributes() 151 | { 152 | var attributes = _fieldInfo.GetCustomAttributes(true); 153 | return attributes.Cast(); 154 | } 155 | 156 | /// 157 | /// Get all custom attributes on field 158 | /// 159 | /// 160 | public IEnumerable GetAttributes() 161 | where TAttribute : Attribute 162 | { 163 | var attributes = _fieldInfo.GetCustomAttributes(true); 164 | return attributes.OfType().Cast(); 165 | } 166 | 167 | public static implicit operator ExtendedField(FieldInfo fieldInfo) 168 | { 169 | if (fieldInfo == null) 170 | return null; 171 | return new ExtendedField(fieldInfo); 172 | } 173 | 174 | public static implicit operator FieldInfo(ExtendedField extendedField) 175 | { 176 | if (extendedField == null) 177 | return null; 178 | return extendedField._fieldInfo; 179 | } 180 | 181 | public override string ToString() => $"{ReflectedType}.{Name}"; 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /TypeSupport/TypeSupport/ExtendedMethod.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using System.Runtime.CompilerServices; 6 | using TypeSupport.Extensions; 7 | 8 | namespace TypeSupport 9 | { 10 | /// 11 | /// Discovers the attributes of a method and provides access to method metadata 12 | /// 13 | public class ExtendedMethod : IAttributeInspection 14 | { 15 | private readonly MethodInfo _methodInfo; 16 | private readonly TypeSupportOptions _typeSupportOptions; 17 | private readonly Type _parentType; 18 | private readonly string[] _operatorOverloadNames = { 19 | "op_Implicit", 20 | "op_Explicit", 21 | "op_Addition", 22 | "op_Subtraction", 23 | "op_Multiply", 24 | "op_Division", 25 | "op_Modulus", 26 | "op_ExclusiveOr", 27 | "op_BitwiseAnd", 28 | "op_BitwiseOr", 29 | "op_LogicalAnd", 30 | "op_LogicalOr", 31 | "op_Assign", 32 | "op_LeftShift", 33 | "op_RightShift", 34 | "op_SignedRightShift", 35 | "op_UnsignedRightShift", 36 | "op_Equality", 37 | "op_GreaterThan", 38 | "op_LessThan", 39 | "op_Inequality", 40 | "op_GreaterThanOrEqual", 41 | "op_LessThanOrEqual", 42 | "op_MultiplicationAssignment", 43 | "op_SubtractionAssignment", 44 | "op_ExclusiveOrAssignment", 45 | "op_LeftShiftAssignment", 46 | "op_ModulusAssignment", 47 | "op_AdditionAssignment", 48 | "op_BitwiseAndAssignment", 49 | "op_BitwiseOrAssignment", 50 | "op_Comma", 51 | "op_DivisionAssignment", 52 | "op_Decrement", 53 | "op_Increment", 54 | "op_UnaryNegation", 55 | "op_UnaryPlus", 56 | "op_OnesComplement" 57 | }; 58 | 59 | /// 60 | /// Original MethodInfo of the method 61 | /// 62 | public MethodInfo MethodInfo => _methodInfo; 63 | 64 | /// 65 | /// Gets the name of the current member 66 | /// 67 | public string Name => _methodInfo.Name; 68 | 69 | /// 70 | /// Gets the return type of this method 71 | /// 72 | public ExtendedType ReturnType => _methodInfo.ReturnType?.GetExtendedType(_typeSupportOptions); 73 | 74 | /// 75 | /// Gets the type of this method 76 | /// 77 | public Type DeclaringType => _methodInfo.DeclaringType; 78 | 79 | /// 80 | /// True if the method is marked static 81 | /// 82 | public bool IsStatic => _methodInfo.IsStatic; 83 | 84 | /// 85 | /// True if the method is marked virtual 86 | /// 87 | public bool IsVirtual => _methodInfo.IsVirtual; 88 | 89 | /// 90 | /// True if the method is marked public 91 | /// 92 | public bool IsPublic => _methodInfo.IsPublic; 93 | 94 | /// 95 | /// True if the method is marked private 96 | /// 97 | public bool IsPrivate => _methodInfo.IsPrivate; 98 | 99 | /// 100 | /// True if the method is a generic method 101 | /// 102 | public bool IsGenericMethod => _methodInfo.IsGenericMethod; 103 | 104 | /// 105 | /// True if the method is marked abstract 106 | /// 107 | public bool IsAbstract => _methodInfo.IsAbstract; 108 | 109 | /// 110 | /// True if the method is marked final 111 | /// 112 | public bool IsFinal => _methodInfo.IsFinal; 113 | 114 | /// 115 | /// True if the method is an overriden method 116 | /// 117 | public bool IsOverride => _methodInfo.GetBaseDefinition().DeclaringType != _methodInfo.DeclaringType; 118 | 119 | /// 120 | /// True if the method is an overriden method 121 | /// 122 | public bool IsOverridden { get; } 123 | 124 | /// 125 | /// True if this method is a constructor 126 | /// 127 | public bool IsConstructor => _methodInfo.IsConstructor; 128 | 129 | /// 130 | /// True if this method signature is hidden by an overriding method 131 | /// 132 | public bool IsHideBySig => _methodInfo.IsHideBySig; 133 | 134 | /// 135 | /// True if this method is an auto property accessor 136 | /// 137 | public bool IsAutoPropertyAccessor { get; } 138 | 139 | /// 140 | /// True if this method is an auto property getter 141 | /// 142 | public bool IsGetter { get; } 143 | 144 | /// 145 | /// True if this method is an auto property setter 146 | /// 147 | public bool IsSetter { get; } 148 | 149 | /// 150 | /// True if this method is an operator overload 151 | /// 152 | public bool IsOperatorOverload { get; } 153 | 154 | /// 155 | /// Get the parameters for the method 156 | /// 157 | public IEnumerable Parameters => _methodInfo.GetParameters(); 158 | 159 | /// 160 | /// Create an extended property 161 | /// 162 | /// 163 | /// 164 | /// The type support options to use for type inspection 165 | public ExtendedMethod(MethodInfo methodInfo, Type parentType, TypeSupportOptions typeSupportOptions) 166 | { 167 | _methodInfo = methodInfo; 168 | _parentType = parentType; 169 | _typeSupportOptions = typeSupportOptions; 170 | IsAutoPropertyAccessor = _methodInfo.IsSpecialName 171 | && _methodInfo.IsHideBySig 172 | && _methodInfo.GetCustomAttributes(typeof(CompilerGeneratedAttribute), true).Any() 173 | && (_methodInfo.Name.Contains("get_") || _methodInfo.Name.Contains("set_")); 174 | IsGetter = IsAutoPropertyAccessor 175 | && (_methodInfo.Name.Contains("get_")); 176 | IsSetter = IsAutoPropertyAccessor 177 | && (_methodInfo.Name.Contains("set_")); 178 | var declaringTypeMethods = _methodInfo.DeclaringType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Static); 179 | IsOverridden = _parentType != null && _methodInfo.GetBaseDefinition().DeclaringType == _methodInfo.DeclaringType 180 | && declaringTypeMethods.Any(x => x.Name == _methodInfo.Name && x.DeclaringType == _parentType); 181 | IsOperatorOverload = _methodInfo.IsSpecialName && _methodInfo.IsStatic && _operatorOverloadNames.Contains(_methodInfo.Name); 182 | } 183 | 184 | /// 185 | /// Create an extended property 186 | /// 187 | /// 188 | /// The type support options to use for type inspection 189 | public ExtendedMethod(MethodInfo methodInfo, TypeSupportOptions typeSupportOptions) : this(methodInfo, null, typeSupportOptions) 190 | { 191 | } 192 | 193 | /// 194 | /// Create an extended property 195 | /// 196 | /// 197 | public ExtendedMethod(MethodInfo methodInfo) : this(methodInfo, null, TypeSupportOptions.All) 198 | { 199 | } 200 | 201 | public bool HasAttribute() where TAttribute : class => Attribute.GetCustomAttribute(this, typeof(TAttribute)) != null; 202 | 203 | public bool HasAttribute(Type attributeType) => Attribute.GetCustomAttribute(this, attributeType) != null; 204 | 205 | public TAttribute GetAttribute() where TAttribute : class => Attribute.GetCustomAttribute(this, typeof(TAttribute)) as TAttribute; 206 | 207 | public Attribute GetAttribute(Type attributeType) => Attribute.GetCustomAttribute(this, attributeType); 208 | 209 | /// 210 | /// Get all custom attributes on method 211 | /// 212 | /// 213 | public IEnumerable GetAttributes() 214 | { 215 | var attributes = _methodInfo.GetCustomAttributes(true); 216 | return attributes.Cast(); 217 | } 218 | 219 | /// 220 | /// Get all custom attributes on method 221 | /// 222 | /// 223 | public IEnumerable GetAttributes() 224 | where TAttribute : Attribute 225 | { 226 | var attributes = _methodInfo.GetCustomAttributes(true); 227 | return attributes.OfType().Cast(); 228 | } 229 | 230 | public static implicit operator ExtendedMethod(MethodInfo methodInfo) 231 | { 232 | if (methodInfo == null) 233 | return null; 234 | return new ExtendedMethod(methodInfo); 235 | } 236 | 237 | public static implicit operator MethodInfo(ExtendedMethod extendedProperty) 238 | { 239 | if (extendedProperty == null) 240 | return null; 241 | return extendedProperty._methodInfo; 242 | } 243 | 244 | public override string ToString() => $"{Name} {_methodInfo}"; 245 | } 246 | } 247 | -------------------------------------------------------------------------------- /TypeSupport/TypeSupport/ExtendedProperty.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using System.Runtime.CompilerServices; 6 | using TypeSupport.Extensions; 7 | 8 | namespace TypeSupport 9 | { 10 | /// 11 | /// Discovers the attributes of a property and provides access to property metadata 12 | /// 13 | public class ExtendedProperty : IAttributeInspection 14 | { 15 | private readonly PropertyInfo _propertyInfo; 16 | private readonly TypeSupportOptions _typeSupportOptions; 17 | private readonly Lazy> _customAttributesCached; 18 | private readonly Lazy> _attributesCached; 19 | 20 | /// 21 | /// Original PropertyInfo of the property 22 | /// 23 | public PropertyInfo PropertyInfo => _propertyInfo; 24 | 25 | /// 26 | /// Gets the name of the current member 27 | /// 28 | public string Name => _propertyInfo.Name; 29 | 30 | /// 31 | /// Gets the type of this property object 32 | /// 33 | public ExtendedType Type => _propertyInfo.PropertyType?.GetExtendedType(_typeSupportOptions); 34 | 35 | /// 36 | /// Gets the base type of this property object 37 | /// 38 | public ExtendedType BaseType => _propertyInfo.PropertyType.BaseType?.GetExtendedType(_typeSupportOptions); 39 | 40 | /// 41 | /// Gets the class object that was used to obtain this instance of MemberInfo 42 | /// 43 | public ExtendedType ReflectedType => _propertyInfo.ReflectedType?.GetExtendedType(_typeSupportOptions); 44 | 45 | /// 46 | /// Gets a collection that contains this member's custom attributes 47 | /// 48 | public IEnumerable CustomAttributes => _customAttributesCached.Value; 49 | 50 | public IEnumerable Attributes => _attributesCached.Value; 51 | 52 | /// 53 | /// True if an auto-backed property 54 | /// 55 | public bool IsAutoProperty { get; } 56 | 57 | /// 58 | /// True if property is defined as static 59 | /// 60 | public bool IsStatic { get; set; } 61 | 62 | /// 63 | /// True if property is defined as virtual 64 | /// 65 | public bool IsVirtual { get; set; } 66 | 67 | /// 68 | /// True if property is defined as abstract 69 | /// 70 | public bool IsAbstract { get; set; } 71 | 72 | /// 73 | /// True if property is defined as final 74 | /// 75 | public bool IsFinal { get; set; } 76 | 77 | /// 78 | /// True if property is defined as private 79 | /// 80 | public bool IsPrivate { get; set; } 81 | 82 | /// 83 | /// True if property is defined as public 84 | /// 85 | public bool IsPublic { get; set; } 86 | 87 | /// 88 | /// True if property is defined as protected 89 | /// 90 | public bool IsProtected { get; set; } 91 | 92 | /// 93 | /// True if property is defined as internal 94 | /// 95 | public bool IsInternal { get; set; } 96 | 97 | /// 98 | /// If an auto-backed property, the name of the field that backs it 99 | /// 100 | public string BackingFieldName { get; } 101 | 102 | #if FEATURE_GETMETHOD 103 | /// 104 | /// True if property has a get method 105 | /// 106 | public bool HasGetMethod => _propertyInfo.GetMethod != null; 107 | 108 | /// 109 | /// True if property has a set method 110 | /// 111 | public bool HasSetMethod => _propertyInfo.SetMethod != null; 112 | #else 113 | /// 114 | /// True if property has a get method 115 | /// 116 | public bool HasGetMethod => _propertyInfo.GetGetMethod(true) != null; 117 | 118 | /// 119 | /// True if property has a set method 120 | /// 121 | public bool HasSetMethod => _propertyInfo.GetSetMethod(true) != null; 122 | #endif 123 | 124 | /// 125 | /// The getter method for the property 126 | /// 127 | public MethodInfo GetMethod => _propertyInfo.GetGetMethod(true); 128 | 129 | /// 130 | /// The setter method for the property 131 | /// 132 | public MethodInfo SetMethod => _propertyInfo.GetSetMethod(true); 133 | 134 | /// 135 | /// Create an extended property 136 | /// 137 | /// 138 | public ExtendedProperty(PropertyInfo propertyInfo) : this(propertyInfo, TypeSupportOptions.All) { } 139 | 140 | /// 141 | /// Create an extended property 142 | /// 143 | /// 144 | /// The type support options to use for type inspection 145 | public ExtendedProperty(PropertyInfo propertyInfo, TypeSupportOptions typeSupportOptions) 146 | { 147 | _propertyInfo = propertyInfo; 148 | _typeSupportOptions = typeSupportOptions; 149 | 150 | if (HasGetMethod) 151 | { 152 | IsStatic = GetMethod.IsStatic; 153 | IsVirtual = GetMethod.IsVirtual; 154 | IsAbstract = GetMethod.IsAbstract; 155 | IsFinal = GetMethod.IsFinal; 156 | IsPrivate = GetMethod.IsPrivate; 157 | IsPublic = GetMethod.IsPublic; 158 | IsProtected = GetMethod.IsFamily; 159 | IsInternal = GetMethod.IsAssembly; 160 | 161 | #if FEATURE_CUSTOM_ATTRIBUTES 162 | _customAttributesCached = new Lazy>(() => _propertyInfo.CustomAttributes); 163 | #else 164 | _customAttributesCached = new Lazy>(() => _propertyInfo.GetCustomAttributesData()); 165 | #endif 166 | _attributesCached = new Lazy>(() => GetAttributes()); 167 | 168 | if (GetMethod 169 | .GetCustomAttributes(typeof(CompilerGeneratedAttribute), true) 170 | .Any() 171 | && _propertyInfo.DeclaringType 172 | .GetFields(BindingFlags.Instance | BindingFlags.NonPublic) 173 | .Any(x => x.Name.Equals($"<{Name}>k__BackingField"))) 174 | { 175 | IsAutoProperty = true; 176 | BackingFieldName = $"<{Name}>k__BackingField"; 177 | } 178 | } 179 | } 180 | 181 | public bool HasAttribute() where TAttribute : class => Attribute.GetCustomAttribute(this, typeof(TAttribute)) != null; 182 | 183 | public bool HasAttribute(Type attributeType) => Attribute.GetCustomAttribute(this, attributeType) != null; 184 | 185 | public TAttribute GetAttribute() where TAttribute : class => Attribute.GetCustomAttribute(this, typeof(TAttribute)) as TAttribute; 186 | 187 | public Attribute GetAttribute(Type attributeType) => Attribute.GetCustomAttribute(this, attributeType); 188 | 189 | /// 190 | /// Get all custom attributes on property 191 | /// 192 | /// 193 | public IEnumerable GetAttributes() 194 | { 195 | var attributes = _propertyInfo.GetCustomAttributes(true); 196 | return attributes.Cast(); 197 | } 198 | 199 | /// 200 | /// Get all custom attributes on property 201 | /// 202 | /// 203 | public IEnumerable GetAttributes() 204 | where TAttribute : Attribute 205 | { 206 | var attributes = _propertyInfo.GetCustomAttributes(true); 207 | return attributes.OfType().Cast(); 208 | } 209 | 210 | public static implicit operator ExtendedProperty(PropertyInfo propertyInfo) 211 | { 212 | if (propertyInfo == null) 213 | return null; 214 | return new ExtendedProperty(propertyInfo); 215 | } 216 | 217 | public static implicit operator PropertyInfo(ExtendedProperty extendedProperty) 218 | => extendedProperty?._propertyInfo; 219 | 220 | public override string ToString() => $"{ReflectedType.Name}.{Name}"; 221 | } 222 | } 223 | -------------------------------------------------------------------------------- /TypeSupport/TypeSupport/Extensions/BitConverterExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace TypeSupport.Extensions 5 | { 6 | public static class BitConverterExtensions 7 | { 8 | /// 9 | /// Convert a decimal to a byte array 10 | /// 11 | /// 12 | /// 13 | public static byte[] GetBytes(decimal dec) 14 | { 15 | var bits = decimal.GetBits(dec); 16 | var bytes = new List(); 17 | foreach (var i in bits) 18 | { 19 | bytes.AddRange(BitConverter.GetBytes(i)); 20 | } 21 | return bytes.ToArray(); 22 | } 23 | 24 | /// 25 | /// Convert a byte array to a decimal 26 | /// 27 | /// 28 | /// 29 | public static decimal ToDecimal(byte[] bytes) 30 | { 31 | if (bytes.Length != 16) 32 | throw new ArgumentException("A decimal must be created from exactly 16 bytes"); 33 | var bits = new int[4]; 34 | for (var i = 0; i <= 15; i += 4) 35 | { 36 | //convert every 4 bytes into an int32 37 | bits[i / 4] = BitConverter.ToInt32(bytes, i); 38 | } 39 | return new decimal(bits); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /TypeSupport/TypeSupport/Extensions/ConstructorOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace TypeSupport.Extensions 4 | { 5 | [Flags] 6 | public enum ConstructorOptions : byte 7 | { 8 | /// 9 | /// Get all constructors 10 | /// 11 | All = 0, 12 | /// 13 | /// Get only empty constructors 14 | /// 15 | EmptyConstructor = 1, 16 | /// 17 | /// Get only non-empty constructors 18 | /// 19 | NonEmptyConstructor = 2, 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /TypeSupport/TypeSupport/Extensions/EnumExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Linq; 5 | 6 | namespace TypeSupport.Extensions 7 | { 8 | public static class EnumExtensions 9 | { 10 | /// 11 | /// Convert an Enum to UInt16 12 | /// 13 | /// 14 | /// 15 | public static uint AsUInt(this Enum enumValue) => Convert.ToUInt32(enumValue); 16 | 17 | /// 18 | /// Convert an Enum to Int32 19 | /// 20 | /// 21 | /// 22 | public static int AsInt(this Enum enumValue) => Convert.ToInt32(enumValue); 23 | 24 | /// 25 | /// Convert an Enum to UInt16 26 | /// 27 | /// 28 | /// 29 | public static ushort AsUShort(this Enum enumValue) => Convert.ToUInt16(enumValue); 30 | 31 | /// 32 | /// Convert an Enum to Int32 33 | /// 34 | /// 35 | /// 36 | public static short AsShort(this Enum enumValue) => Convert.ToInt16(enumValue); 37 | 38 | /// 39 | /// Convert an Enum to Int64 40 | /// 41 | /// 42 | /// 43 | public static long AsLong(this Enum enumValue) => Convert.ToInt64(enumValue); 44 | 45 | /// 46 | /// Convert an Enum to UInt64 47 | /// 48 | /// 49 | /// 50 | public static ulong AsULong(this Enum enumValue) => Convert.ToUInt64(enumValue); 51 | 52 | /// 53 | /// Convert an Enum to Byte 54 | /// 55 | /// 56 | /// 57 | public static byte AsByte(this Enum enumValue) => Convert.ToByte(enumValue); 58 | 59 | /// 60 | /// Convert an Enum to SByte 61 | /// 62 | /// 63 | /// 64 | public static sbyte AsSByte(this Enum enumValue) => Convert.ToSByte(enumValue); 65 | 66 | public static bool BitwiseHasFlag(this T flag, T value) 67 | where T : struct 68 | { 69 | return (Convert.ToInt64(flag) & Convert.ToInt64(value)) == Convert.ToInt64(value); 70 | } 71 | 72 | public static bool BitwiseHasFlag(this Enum flag, Enum value) 73 | { 74 | return ((flag.AsLong() & value.AsLong()) == value.AsLong()); 75 | } 76 | 77 | public static bool BitwiseHasFlag(this Enum flag, byte value) 78 | { 79 | return ((flag.AsByte() & value) == value); 80 | } 81 | 82 | public static bool BitwiseHasFlag(this Enum flag, short value) 83 | { 84 | return ((flag.AsShort() & value) == value); 85 | } 86 | 87 | public static bool BitwiseHasFlag(this Enum flag, int value) 88 | { 89 | return ((flag.AsInt() & value) == value); 90 | } 91 | 92 | public static bool BitwiseHasFlag(this Enum flag, long value) 93 | { 94 | return ((flag.AsLong() & value) == value); 95 | } 96 | 97 | /// 98 | /// Convert a Bitmask/Enum flags to a List of Enum values 99 | /// 100 | /// 101 | /// 102 | public static IEnumerable ToListOfEnum(this Enum flags) 103 | { 104 | if (!typeof(Enum).GetCustomAttributes(typeof(FlagsAttribute), false).Any()) 105 | throw new InvalidOperationException("Enum must have flags attribute."); 106 | var flag = 1ul; 107 | foreach (var value in Enum.GetValues(flags.GetType()).Cast()) 108 | { 109 | var bits = Convert.ToUInt64(value); 110 | while (flag < bits) 111 | { 112 | flag <<= 1; 113 | } 114 | 115 | if (flag == bits && flags.HasFlag(value)) 116 | { 117 | yield return value; 118 | } 119 | } 120 | } 121 | 122 | /// 123 | /// Convert a Bitmask/Enum flags to a List of Enum values 124 | /// 125 | /// 126 | /// 127 | public static IEnumerable ToListOfEnum(this T flags) 128 | where T : struct, IConvertible 129 | { 130 | var t = typeof(T); 131 | if (t.IsEnum) 132 | { 133 | if (!t.GetCustomAttributes(typeof(FlagsAttribute), false).Any()) 134 | throw new InvalidOperationException("Enum must have flags attribute."); 135 | var flagsEnum = Enum.Parse(t, flags.ToString()) as Enum; 136 | var flag = 1ul; 137 | foreach (var value in Enum.GetValues(flags.GetType()).Cast()) 138 | { 139 | var bits = Convert.ToUInt64(value); 140 | while (flag < bits) 141 | { 142 | flag <<= 1; 143 | } 144 | if (flag == bits && flagsEnum.HasFlag(value as Enum)) 145 | { 146 | yield return value; 147 | } 148 | } 149 | } 150 | } 151 | 152 | /// 153 | /// Convert a Bitmask/Enum flags to a List of Enum values 154 | /// 155 | /// 156 | /// 157 | public static IEnumerable ToListOfEnum(this Enum flags) 158 | where T : struct, IConvertible 159 | { 160 | var t = typeof(T); 161 | if (t.IsEnum) 162 | { 163 | if (!t.GetCustomAttributes(typeof(FlagsAttribute), false).Any()) 164 | throw new InvalidOperationException("Enum must have flags attribute."); 165 | var flagsEnum = Enum.Parse(t, flags.ToString()) as Enum; 166 | var flag = 1ul; 167 | foreach (var value in Enum.GetValues(flags.GetType()).Cast()) 168 | { 169 | var bits = Convert.ToUInt64(value); 170 | while (flag < bits) 171 | { 172 | flag <<= 1; 173 | } 174 | if (flag == bits && flagsEnum.HasFlag(value as Enum)) 175 | { 176 | yield return value; 177 | } 178 | } 179 | } 180 | } 181 | 182 | /// 183 | /// Convert a enum to a list of key value pairs (int id and string value) 184 | /// 185 | /// 186 | /// 187 | /// 188 | public static IEnumerable> ToListOfKeyValuePairs(this Type enumType) 189 | where T : struct, IConvertible 190 | { 191 | var result = new List>(); 192 | foreach (var name in Enum.GetNames(enumType)) 193 | { 194 | result.Add(new KeyValuePair((T)Enum.Parse(enumType, name), name)); 195 | } 196 | return result; 197 | } 198 | 199 | /// 200 | /// Convert a enum to a list of key value pairs (int id and string value) 201 | /// 202 | /// 203 | /// 204 | /// 205 | public static IEnumerable> ToListOfKeyValuePairs(this Type enumType, Type enumValueType) 206 | { 207 | var result = new List>(); 208 | foreach (var name in Enum.GetNames(enumType)) 209 | { 210 | result.Add(new KeyValuePair(Convert.ChangeType(Enum.Parse(enumType, name), enumValueType), name)); 211 | } 212 | return result; 213 | } 214 | 215 | /// 216 | /// Get the component model description of the value (if provided) 217 | /// 218 | /// 219 | /// 220 | public static string GetDescription(this Enum value) 221 | { 222 | var fi = value.GetType().GetField(value.ToString()); 223 | var attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false); 224 | if (attributes.Length > 0) 225 | return attributes[0].Description; 226 | else 227 | return value.ToString(); 228 | } 229 | 230 | /// 231 | /// Check an enum bitmask against a flags enum for valid values 232 | /// 233 | /// 234 | /// The enumeration 235 | /// A flags bitmask 236 | /// 237 | public static bool ContainsValidEnumFlags(this T flags, int bitmask) where T : struct, IConvertible 238 | { 239 | var enumList = flags.ToListOfEnum(); 240 | var maxValue = enumList.Sum(x => Convert.ToInt32(x)); 241 | 242 | // if 0 is a valid value, then let it pass. 243 | if (bitmask == 0 && maxValue == 0) 244 | return true; 245 | // if 0 is a valid value and its defined, let it pass. 246 | else if (bitmask == 0 && maxValue > 0 && enumList.Where(x => Convert.ToInt32(x) == 0).Count() == 0) 247 | { 248 | return false; 249 | } 250 | 251 | // if value is larger than max enum size, it's not defined. 252 | if (bitmask > maxValue) 253 | return false; 254 | 255 | return true; 256 | } 257 | } 258 | } 259 | -------------------------------------------------------------------------------- /TypeSupport/TypeSupport/Extensions/EnumerableExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Concurrent; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | 7 | namespace TypeSupport.Extensions 8 | { 9 | /// 10 | /// Enumerable extensions 11 | /// 12 | public static class EnumerableExtensions 13 | { 14 | /// 15 | /// An awaitable ForEach implementation 16 | /// 17 | /// 18 | /// 19 | /// Number of threads to use 20 | /// 21 | /// 22 | public static Task ForEachAsync(this IEnumerable source, int degreeOfParallelism, Func body) 23 | { 24 | #if FEATURE_TASK 25 | return Task.WhenAll( 26 | from partition in Partitioner.Create(source).GetPartitions(degreeOfParallelism) 27 | select Task.Run(async delegate { 28 | using (partition) 29 | { 30 | while (partition.MoveNext()) 31 | { 32 | await body(partition.Current); 33 | } 34 | } 35 | })); 36 | #else 37 | var taskFactory = new TaskFactory(); 38 | var tasks = from partition in Partitioner.Create(source).GetPartitions(degreeOfParallelism) 39 | select taskFactory.StartNew(delegate 40 | { 41 | using (partition) 42 | { 43 | while (partition.MoveNext()) 44 | { 45 | body(partition.Current); 46 | } 47 | } 48 | }); 49 | return taskFactory.ContinueWhenAll(tasks.ToArray(), continuation => { }, TaskContinuationOptions.ExecuteSynchronously); 50 | #endif 51 | } 52 | 53 | /// 54 | /// An awaitable ForEach implementation 55 | /// 56 | /// 57 | /// 58 | /// 59 | /// 60 | public static Task ForEachAsync(this IEnumerable source, Func body) 61 | { 62 | return source.ForEachAsync(Environment.ProcessorCount, body); 63 | } 64 | 65 | /// 66 | /// Determines wether an element is in the List<> with case sensitivity options 67 | /// 68 | /// 69 | /// 70 | /// 71 | /// 72 | /// 73 | public static bool Contains(this IEnumerable source, string toCheck, StringComparison comp) 74 | { 75 | foreach (var el in source) 76 | { 77 | var els = el.ToString(); 78 | if (els.IndexOf(toCheck, comp) >= 0) 79 | return true; 80 | } 81 | 82 | return false; 83 | } 84 | 85 | /// 86 | /// Determines whether a contains any items in another 87 | /// 88 | /// The type of data to compare 89 | /// The source enumerable/list 90 | /// The enumerable/list containing items to compare 91 | /// 92 | public static bool ContainsAny(this IEnumerable source, IEnumerable anyItems) 93 | { 94 | return source.Any(x => anyItems.Any(y => y.Equals(x))); 95 | } 96 | 97 | /// 98 | /// Fill/append a list with default values 99 | /// 100 | /// 101 | /// 102 | /// The number of items to add 103 | public static IEnumerable Fill(this ICollection source, int count) 104 | { 105 | var type = typeof(T); 106 | for (var i = 0; i < count; i++) 107 | { 108 | if (type.IsValueType) 109 | source.Add((T)Convert.ChangeType(0, type)); 110 | else 111 | source.Add(Activator.CreateInstance()); 112 | } 113 | 114 | return source; 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /TypeSupport/TypeSupport/Extensions/FieldOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace TypeSupport.Extensions 4 | { 5 | /// 6 | /// Specify field retrieval options 7 | /// 8 | [Flags] 9 | public enum FieldOptions : byte 10 | { 11 | /// 12 | /// All fields 13 | /// 14 | All = 0, 15 | /// 16 | /// All publicly defined fields 17 | /// 18 | Public = 1, 19 | /// 20 | /// All privately defined fields 21 | /// 22 | Private = 2, 23 | /// 24 | /// All static fields 25 | /// 26 | Static = 4, 27 | /// 28 | /// All auto-property backing fields 29 | /// 30 | BackingFields = 8, 31 | /// 32 | /// All constant fields 33 | /// 34 | Constants = 16, 35 | /// 36 | /// All writable fields (all fields except constants) 37 | /// 38 | AllWritable = 32 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /TypeSupport/TypeSupport/Extensions/MethodOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace TypeSupport.Extensions 4 | { 5 | /// 6 | /// Specify method retrieval options 7 | /// 8 | [Flags] 9 | public enum MethodOptions 10 | { 11 | /// 12 | /// All methods 13 | /// 14 | All = 0, 15 | /// 16 | /// All methods declared public 17 | /// 18 | Public = 1, 19 | /// 20 | /// All methods declared private 21 | /// 22 | Private = 2, 23 | /// 24 | /// All methods declared static 25 | /// 26 | Static = 4, 27 | /// 28 | /// All methods declared as a constructor 29 | /// 30 | Constructor = 8, 31 | /// 32 | /// All methods which are base implementation 33 | /// 34 | BaseImplementation = 16, 35 | /// 36 | /// All methods which are overriding base implementation 37 | /// 38 | Overridden = 32, 39 | /// 40 | /// All methods declared virtual 41 | /// 42 | Virtual = 64, 43 | /// 44 | /// All methods acting as property accessors 45 | /// 46 | AutoPropertyAccessor = 128, 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /TypeSupport/TypeSupport/Extensions/PropertyOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace TypeSupport.Extensions 4 | { 5 | /// 6 | /// Specify property retrieval options 7 | /// 8 | [Flags] 9 | public enum PropertyOptions : byte 10 | { 11 | /// 12 | /// All properties 13 | /// 14 | All = 0, 15 | /// 16 | /// All properties with public accessors 17 | /// 18 | Public = 1, 19 | /// 20 | /// All properties with private accessors 21 | /// 22 | Private = 2, 23 | /// 24 | /// Properties with a setter defined 25 | /// 26 | HasSetter = 4, 27 | /// 28 | /// Properties with a getter defined 29 | /// 30 | HasGetter = 8, 31 | /// 32 | /// Properties that contain a collection indexer 33 | /// 34 | HasIndexer = 16, 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /TypeSupport/TypeSupport/Extensions/ReflectionExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | 3 | namespace TypeSupport.Extensions 4 | { 5 | /// 6 | /// Reflection extensions 7 | /// 8 | public static class ReflectionExtensions 9 | { 10 | /// 11 | /// Get the extended field 12 | /// 13 | /// 14 | /// 15 | public static ExtendedField ExtendedField(this FieldInfo fieldInfo) => new (fieldInfo); 16 | 17 | /// 18 | /// Get the extended property 19 | /// 20 | /// 21 | /// 22 | public static ExtendedProperty ExtendedProperty(this PropertyInfo propertyInfo) => new (propertyInfo); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /TypeSupport/TypeSupport/Extensions/StringExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Text.RegularExpressions; 6 | 7 | namespace TypeSupport.Extensions 8 | { 9 | /// 10 | /// String extensions 11 | /// 12 | public static class StringExtensions 13 | { 14 | /// 15 | /// Removes all whitespace in a string (leading, trailing, inside) 16 | /// 17 | /// 18 | /// 19 | public static string RemoveWhiteSpace(this string str) 20 | { 21 | return new string(str.ToCharArray() 22 | .Where(c => !char.IsWhiteSpace(c)) 23 | .ToArray()); 24 | } 25 | 26 | /// 27 | /// Expand a string into multiple words based on casing 28 | /// 29 | /// 30 | /// 31 | public static string ExpandOnCase(this string str) 32 | { 33 | return Regex.Replace(str, "(?<=[a-z])([A-Z])", " $1", RegexOptions.Compiled); 34 | } 35 | 36 | /// 37 | /// Contains extension with case sensitivity options 38 | /// 39 | /// 40 | /// 41 | /// 42 | /// 43 | public static bool Contains(this string source, string toCheck, StringComparison comp) 44 | { 45 | return source.IndexOf(toCheck, comp) >= 0; 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /TypeSupport/TypeSupport/Extensions/TupleExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | 6 | namespace TypeSupport.Extensions 7 | { 8 | /// 9 | /// Type extensions for Tuples and ValueTuples 10 | /// 11 | public static class TupleExtensions 12 | { 13 | /// 14 | /// Mapping for types that are generic ValueTuples 15 | /// 16 | private static readonly HashSet _valueTupleTypes = new HashSet(new Type[] 17 | { 18 | #if FEATURE_CUSTOM_VALUETUPLE 19 | typeof(ValueTuple<>), 20 | typeof(ValueTuple<,>), 21 | typeof(ValueTuple<,,>), 22 | typeof(ValueTuple<,,,>), 23 | typeof(ValueTuple<,,,,>), 24 | typeof(ValueTuple<,,,,,>), 25 | typeof(ValueTuple<,,,,,,>), 26 | typeof(ValueTuple<,,,,,,,>) 27 | #endif 28 | }); 29 | 30 | /// 31 | /// Mapping for types that are generic Tuples 32 | /// 33 | private static readonly HashSet _tupleTypes = new HashSet(new [] 34 | { 35 | typeof(Tuple<>), 36 | typeof(Tuple<,>), 37 | typeof(Tuple<,,>), 38 | typeof(Tuple<,,,>), 39 | typeof(Tuple<,,,,>), 40 | typeof(Tuple<,,,,,>), 41 | typeof(Tuple<,,,,,,>), 42 | typeof(Tuple<,,,,,,,>) 43 | }); 44 | 45 | /// 46 | /// Create a new ValueTuple 47 | /// 48 | /// 49 | /// 50 | public static Type CreateValueTuple(ICollection types) 51 | { 52 | Type type = _valueTupleTypes.Skip(types.Count - 1).First(); 53 | return type.MakeGenericType(types.ToArray()); 54 | } 55 | 56 | /// 57 | /// Create a new Tuple 58 | /// 59 | /// 60 | /// 61 | public static Type CreateTuple(ICollection types) 62 | { 63 | Type type = _tupleTypes.Skip(types.Count - 1).First(); 64 | return type.MakeGenericType(types.ToArray()); 65 | } 66 | 67 | /// 68 | /// True if an object is a ValueTuple 69 | /// 70 | /// 71 | /// 72 | public static bool IsValueTuple(this object obj) => IsValueTupleType(obj.GetType()); 73 | 74 | /// 75 | /// True if an object is a Tuple 76 | /// 77 | /// 78 | /// 79 | public static bool IsTuple(this object obj) => IsTupleType(obj.GetType()); 80 | 81 | /// 82 | /// True if the type is a ValueTuple 83 | /// 84 | /// 85 | /// 86 | public static bool IsValueTupleType(this Type type) 87 | { 88 | #if FEATURE_CUSTOM_TYPEINFO 89 | return type.GetTypeInfo().IsGenericType 90 | && _valueTupleTypes.Contains(type.GetGenericTypeDefinition()); 91 | #else 92 | return type.IsGenericType 93 | && _valueTupleTypes.Contains(type.GetGenericTypeDefinition()); 94 | #endif 95 | } 96 | 97 | /// 98 | /// True if the type is a Tuple 99 | /// 100 | /// 101 | /// 102 | public static bool IsTupleType(this Type type) 103 | { 104 | #if FEATURE_CUSTOM_TYPEINFO 105 | return type.GetTypeInfo().IsGenericType 106 | && _tupleTypes.Contains(type.GetGenericTypeDefinition()); 107 | #else 108 | return type.IsGenericType 109 | && _tupleTypes.Contains(type.GetGenericTypeDefinition()); 110 | #endif 111 | } 112 | 113 | /// 114 | /// Get the items within a Tuple 115 | /// 116 | /// 117 | /// 118 | public static List GetValueTupleItemObjects(this object tuple) 119 | => GetValueTupleItemFields(tuple.GetType()) 120 | .Select(f => f.GetValue(tuple)) 121 | .ToList(); 122 | 123 | /// 124 | /// Get the items within a Tuple 125 | /// 126 | /// 127 | /// 128 | public static List GetTupleItemObjects(this object tuple) 129 | => GetTupleItemFields(tuple.GetType()) 130 | .Select(f => f.GetValue(tuple)) 131 | .ToList(); 132 | 133 | /// 134 | /// Get the type values of a ValueTuple 135 | /// 136 | /// 137 | /// 138 | public static List GetValueTupleItemTypes(this Type tupleType) 139 | => GetValueTupleItemFields(tupleType) 140 | .Select(f => f.FieldType) 141 | .ToList(); 142 | 143 | /// 144 | /// Get the type values of a Tuple 145 | /// 146 | /// 147 | /// 148 | public static List GetTupleItemTypes(this Type tupleType) 149 | => GetTupleItemFields(tupleType) 150 | .Select(f => f.FieldType) 151 | .ToList(); 152 | 153 | /// 154 | /// Get a particular Item field from a ValueTuple 155 | /// 156 | /// 157 | /// 158 | public static List GetValueTupleItemFields(this Type tupleType) 159 | { 160 | var items = new List(); 161 | 162 | FieldInfo field; 163 | int nth = 1; 164 | while ((field = tupleType.GetField($"Item{nth}", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) != null) 165 | { 166 | nth++; 167 | items.Add(field); 168 | } 169 | 170 | return items; 171 | } 172 | 173 | /// 174 | /// Get a particular Item field from a Tuple 175 | /// 176 | /// 177 | /// 178 | public static List GetTupleItemFields(this Type tupleType) 179 | { 180 | var items = new List(); 181 | 182 | FieldInfo field; 183 | int nth = 1; 184 | while ((field = tupleType.GetField($"m_Item{nth}", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) != null) 185 | { 186 | nth++; 187 | items.Add(field); 188 | } 189 | 190 | return items; 191 | } 192 | #if FEATURE_CUSTOM_VALUETUPLE 193 | /// 194 | /// Get the names of a named value tuple contained in a method or constructor 195 | /// 196 | /// 197 | /// The container that declared the named tuple (method or constructor) 198 | /// The optional type of the named tuple, if inspecting a constructor 199 | /// 200 | /// 201 | /// From tuple declared in a constructor: 202 | /// var instance = new ObjectWithNamedTuple((id: 1, value: "test")); 203 | /// var tupleType = typeof((int, string)); 204 | /// var names = instance.GetTupleNamedParameters(instance.GetType().GetConstructor(new Type[] { tupleType }), tupleType); 205 | /// From tuple declared in a method: 206 | /// private ICollection InspectNamedValueTuple((int id, string value) tuple) { 207 | /// return tuple.GetTupleNamedParameters(System.Reflection.MethodBase.GetCurrentMethod()); 208 | /// } 209 | /// 210 | public static ICollection GetTupleNamedParameters(this object tuple, MethodBase container, Type tupleType = null) 211 | { 212 | if (tupleType == null) 213 | tupleType = tuple.GetType(); 214 | var parameters = container.GetParameters().FirstOrDefault(x => x.ParameterType.Name.Equals(tupleType.Name)); 215 | var elementAttributes = parameters?.GetCustomAttributes().FirstOrDefault(t => t.GetType() == typeof(System.Runtime.CompilerServices.TupleElementNamesAttribute)) as System.Runtime.CompilerServices.TupleElementNamesAttribute; 216 | return elementAttributes?.TransformNames ?? new List(); 217 | } 218 | 219 | /// 220 | /// Get the names of a named value tuple contained in a class 221 | /// 222 | /// 223 | /// The property or field name that stores the tuple 224 | /// 225 | /// 226 | /// var instance = new ObjectWithNamedTuple(); 227 | /// var names = instance.GetTupleNamedParameters(nameof(instance.TupleValue)); 228 | /// 229 | public static ICollection GetTupleNamedParameters(this object instance, string fieldName) 230 | { 231 | var property = instance.GetProperty(fieldName); 232 | var elementAttributes = property.GetCustomAttributes().FirstOrDefault(t => t.GetType() == typeof(System.Runtime.CompilerServices.TupleElementNamesAttribute)) as System.Runtime.CompilerServices.TupleElementNamesAttribute; 233 | if (elementAttributes == null) 234 | { 235 | var field = instance.GetField(fieldName); 236 | elementAttributes = field.GetCustomAttributes().FirstOrDefault(t => t.GetType() == typeof(System.Runtime.CompilerServices.TupleElementNamesAttribute)) as System.Runtime.CompilerServices.TupleElementNamesAttribute; 237 | } 238 | return elementAttributes?.TransformNames ?? new List(); 239 | } 240 | #endif 241 | } 242 | } 243 | -------------------------------------------------------------------------------- /TypeSupport/TypeSupport/Extensions/TypeExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | 6 | namespace TypeSupport.Extensions 7 | { 8 | /// 9 | /// Type extensions 10 | /// 11 | public static class TypeExtensions 12 | { 13 | /// 14 | /// Get the extended type for a Type 15 | /// 16 | /// 17 | /// 18 | public static ExtendedType GetExtendedType(this Type type) 19 | => GetExtendedType(type, TypeSupportOptions.All); 20 | 21 | /// 22 | /// Get the extended type for a Type 23 | /// 24 | /// 25 | /// The type support inspection options 26 | /// 27 | public static ExtendedType GetExtendedType(this Type type, TypeSupportOptions options) 28 | { 29 | if (type is null) 30 | return null; 31 | if (object.ReferenceEquals(type, typeof(ExtendedType))) 32 | return type; 33 | 34 | return ExtendedTypeCache.GetOrCreate(type, options); 35 | } 36 | 37 | /// 38 | /// Get all of the properties of an object 39 | /// 40 | /// 41 | /// 42 | public static ICollection GetProperties(this Type type, PropertyOptions options, TypeSupportOptions propogateTypeSupportOptions = TypeSupportOptions.All) 43 | { 44 | if (type == null) 45 | return new List(); 46 | var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static; 47 | var allProperties = type.GetProperties(flags); 48 | IEnumerable returnProperties = allProperties; 49 | 50 | if (options.HasFlag(PropertyOptions.Public)) 51 | returnProperties = returnProperties.Where(x => x.GetGetMethod(true).IsPublic && x.GetSetMethod(true).IsPublic); 52 | if (options.HasFlag(PropertyOptions.Private)) 53 | returnProperties = returnProperties.Where(x => x.GetGetMethod(true).IsPrivate && x.GetSetMethod(true).IsPrivate); 54 | #if FEATURE_CUSTOM_ATTRIBUTES 55 | if (options.HasFlag(PropertyOptions.HasSetter)) 56 | returnProperties = returnProperties.Where(x => x.SetMethod != null); 57 | if (options.HasFlag(PropertyOptions.HasGetter)) 58 | returnProperties = returnProperties.Where(x => x.GetMethod != null); 59 | #else 60 | if (options.HasFlag(PropertyOptions.HasSetter)) 61 | returnProperties = returnProperties.Where(x => x.GetSetMethod(true) != null); 62 | if (options.HasFlag(PropertyOptions.HasGetter)) 63 | returnProperties = returnProperties.Where(x => x.GetGetMethod(true) != null); 64 | #endif 65 | if (options.HasFlag(PropertyOptions.HasIndexer)) 66 | returnProperties = returnProperties.Where(x => x.GetIndexParameters().Any()); 67 | 68 | return returnProperties 69 | .Select(x => new ExtendedProperty(x, propogateTypeSupportOptions)).ToList(); 70 | } 71 | 72 | /// 73 | /// Get all of the properties of an object 74 | /// 75 | /// 76 | /// 77 | public static ICollection GetProperties(this ExtendedType type, PropertyOptions options) 78 | => type.Type.GetProperties(options); 79 | 80 | /// 81 | /// Get all of the fields of an object 82 | /// 83 | /// 84 | /// 85 | /// 86 | /// 87 | public static ICollection GetFields(this Type type, FieldOptions options, TypeSupportOptions propogateTypeSupportOptions = TypeSupportOptions.All) 88 | { 89 | if (type == null) 90 | return new List(); 91 | var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly; 92 | var allFields = type.GetFields(flags) 93 | .Select(x => new ExtendedField(x, propogateTypeSupportOptions)) 94 | .Concat(GetFields(type.BaseType, options)); 95 | var returnFields = allFields; 96 | 97 | if (options.HasFlag(FieldOptions.AllWritable)) 98 | { 99 | returnFields = returnFields.Where(x => !x.FieldInfo.IsLiteral); 100 | // technically init only are writable when constructed 101 | // returnFields = returnFields.Where(x => !x.FieldInfo.IsInitOnly); 102 | } 103 | 104 | if (options.HasFlag(FieldOptions.Public)) 105 | returnFields = returnFields.Where(x => x.FieldInfo.IsPublic); 106 | if (options.HasFlag(FieldOptions.Private)) 107 | returnFields = returnFields.Where(x => x.FieldInfo.IsPrivate); 108 | if (options.HasFlag(FieldOptions.Static)) 109 | returnFields = returnFields.Where(x => x.FieldInfo.IsStatic); 110 | if (options.HasFlag(FieldOptions.BackingFields)) 111 | returnFields = allFields.Where(x => x.IsBackingField); 112 | if (options.HasFlag(FieldOptions.Constants)) 113 | returnFields = returnFields.Where(x => x.FieldInfo.IsLiteral); 114 | return returnFields.ToList(); 115 | } 116 | 117 | /// 118 | /// Get all of the fields of an object 119 | /// 120 | /// 121 | /// 122 | public static ICollection GetFields(this ExtendedType type, FieldOptions options) 123 | => type.Type.GetFields(options); 124 | 125 | /// 126 | /// Get all of the fields of an object 127 | /// 128 | /// 129 | /// 130 | /// 131 | public static ICollection GetMethods(this Type type, MethodOptions options, TypeSupportOptions propogateTypeSupportOptions = TypeSupportOptions.All) 132 | { 133 | if (type == null) 134 | return new List(); 135 | var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Static; 136 | var allMethods = type.GetMethods(flags) 137 | .Select(x => new ExtendedMethod(x, type, propogateTypeSupportOptions)) 138 | .Concat(GetMethods(type.BaseType, options)); 139 | var returnMethods = allMethods; 140 | 141 | if (options.HasFlag(MethodOptions.Public)) 142 | returnMethods = returnMethods.Where(x => x.IsPublic); 143 | if (options.HasFlag(MethodOptions.Private)) 144 | returnMethods = returnMethods.Where(x => x.IsPrivate); 145 | if (options.HasFlag(MethodOptions.Static)) 146 | returnMethods = returnMethods.Where(x => x.IsStatic); 147 | if (options.HasFlag(MethodOptions.Overridden)) 148 | returnMethods = allMethods.Where(x => x.IsOverride); 149 | if (options.HasFlag(MethodOptions.Virtual)) 150 | returnMethods = returnMethods.Where(x => x.IsVirtual); 151 | if (options.HasFlag(MethodOptions.Constructor)) 152 | returnMethods = returnMethods.Where(x => x.IsConstructor); 153 | return returnMethods.ToList(); 154 | } 155 | 156 | /// 157 | /// Get all of the fields of an object 158 | /// 159 | /// 160 | /// True to include the compiler generated backing fields for auto-property getters/setters 161 | /// 162 | public static ICollection GetMethods(this ExtendedType type, MethodOptions options) 163 | => type.Type.GetMethods(options); 164 | 165 | /// 166 | /// Check if a type contains a property 167 | /// 168 | /// 169 | /// Property name 170 | /// 171 | public static bool ContainsProperty(this Type type, string name) 172 | => type.GetProperty(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) != null; 173 | 174 | /// 175 | /// Check if a type contains a property 176 | /// 177 | /// 178 | /// Property name 179 | /// 180 | public static bool ContainsProperty(this ExtendedType type, string name) 181 | => type.Type.ContainsProperty(name); 182 | 183 | /// 184 | /// Check if a type contains a field 185 | /// 186 | /// 187 | /// Field name 188 | /// 189 | public static bool ContainsField(this Type type, string name) 190 | => type.GetField(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) != null; 191 | 192 | /// 193 | /// Check if a type contains a field 194 | /// 195 | /// 196 | /// Field name 197 | /// 198 | public static bool ContainsField(this ExtendedType type, string name) 199 | => type.Type.ContainsField(name); 200 | 201 | /// 202 | /// Get a list of all constructors of a type 203 | /// 204 | /// 205 | /// 206 | public static ICollection GetConstructors(this Type type, ConstructorOptions options) 207 | { 208 | if (type == null) 209 | return new List(); 210 | var allConstructors = type.GetConstructors() 211 | .Concat(GetConstructors(type.BaseType != typeof(object) ? type.BaseType : null, options)); 212 | IEnumerable returnFields = allConstructors; 213 | if (options.HasFlag(ConstructorOptions.EmptyConstructor)) 214 | returnFields = returnFields.Where(x => x.GetParameters().Any() == false); 215 | if (options.HasFlag(ConstructorOptions.NonEmptyConstructor)) 216 | returnFields = returnFields.Where(x => x.GetParameters().Any() == true); 217 | 218 | return returnFields.ToList(); 219 | } 220 | 221 | /// 222 | /// Get a list of all constructors of a type 223 | /// 224 | /// 225 | /// 226 | public static ICollection GetConstructors(this ExtendedType type, ConstructorOptions options) 227 | => type.Type.GetConstructors(options); 228 | 229 | /// 230 | /// Get an extended property object by name 231 | /// 232 | /// 233 | /// 234 | /// 235 | public static ExtendedProperty GetExtendedProperty(this Type type, string name) 236 | => type.GetProperty(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static); 237 | 238 | /// 239 | /// Get an extended property object by name 240 | /// 241 | /// 242 | /// 243 | /// 244 | public static ExtendedProperty GetExtendedProperty(this ExtendedType type, string name) 245 | => type.Type.GetExtendedProperty(name); 246 | 247 | /// 248 | /// Get an extended property object by name 249 | /// 250 | /// 251 | /// 252 | /// The declaring type the property belongs to 253 | /// 254 | public static ExtendedProperty GetExtendedProperty(this Type type, string name, Type declaringType) 255 | { 256 | var properties = type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static); 257 | return properties.Single(x => x.Name.Equals(name) && x.DeclaringType.Equals(declaringType)); 258 | } 259 | 260 | /// 261 | /// Get an extended property object by name 262 | /// 263 | /// 264 | /// 265 | /// The declaring type the property belongs to 266 | /// 267 | public static ExtendedProperty GetExtendedProperty(this ExtendedType type, string name, Type declaringType) 268 | => type.Type.GetExtendedProperty(name, declaringType); 269 | 270 | /// 271 | /// Get an extended field object by name 272 | /// 273 | /// 274 | /// 275 | /// 276 | public static ExtendedField GetExtendedField(this Type type, string name) 277 | => type.GetField(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static); 278 | 279 | /// 280 | /// Get an extended field object by name 281 | /// 282 | /// 283 | /// 284 | /// 285 | public static ExtendedField GetExtendedField(this ExtendedType type, string name) 286 | => type.Type.GetExtendedField(name); 287 | 288 | /// 289 | /// Get an extended field object by name 290 | /// 291 | /// 292 | /// 293 | /// The delcaring type the field belongs to 294 | /// 295 | public static ExtendedField GetExtendedField(this Type type, string name, Type declaringType) 296 | { 297 | var fields = type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static); 298 | return fields.Single(x => x.Name.Equals(name) && x.DeclaringType.Equals(declaringType)); 299 | } 300 | 301 | /// 302 | /// Get an extended field object by name 303 | /// 304 | /// 305 | /// 306 | /// The delcaring type the field belongs to 307 | /// 308 | public static ExtendedField GetExtendedField(this ExtendedType type, string name, Type declaringType) 309 | => type.Type.GetExtendedField(name, declaringType); 310 | } 311 | } 312 | -------------------------------------------------------------------------------- /TypeSupport/TypeSupport/IAttributeInspection.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace TypeSupport 5 | { 6 | public interface IAttributeInspection 7 | { 8 | /// 9 | /// Returns true if object is decorated by attribute 10 | /// 11 | /// 12 | /// 13 | bool HasAttribute() where TAttribute : class; 14 | 15 | /// 16 | /// Returns true if object is decorated by attribute 17 | /// 18 | /// 19 | /// 20 | bool HasAttribute(Type attributeType); 21 | 22 | /// 23 | /// Returns the requested attribute if declared on object, null otherwise 24 | /// 25 | /// 26 | /// 27 | TAttribute GetAttribute() where TAttribute : class; 28 | 29 | /// 30 | /// Returns the requested attribute if declared on object, null otherwise 31 | /// 32 | /// 33 | /// 34 | Attribute GetAttribute(Type attributeType); 35 | 36 | /// 37 | /// Get all custom attributes on object 38 | /// 39 | /// 40 | IEnumerable GetAttributes(); 41 | 42 | /// 43 | /// Get all custom attributes on object 44 | /// 45 | /// 46 | IEnumerable GetAttributes() where TAttribute : Attribute; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /TypeSupport/TypeSupport/ObjectFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Runtime.Serialization; 6 | using TypeSupport.Extensions; 7 | 8 | namespace TypeSupport 9 | { 10 | /// 11 | /// Factory for creating any type of object 12 | /// 13 | public class ObjectFactory 14 | { 15 | /// 16 | /// Get the type registry 17 | /// 18 | public TypeRegistry TypeRegistry { get; } 19 | 20 | /// 21 | /// Create a factory for creating any type of object 22 | /// 23 | public ObjectFactory() 24 | { 25 | } 26 | 27 | /// 28 | /// Create a factory for creating any type of object 29 | /// 30 | /// A type registry for custom mappings 31 | public ObjectFactory(TypeRegistry typeRegistry) 32 | { 33 | TypeRegistry = typeRegistry; 34 | } 35 | 36 | /// 37 | /// Create a new, empty object of a given type 38 | /// 39 | /// The type of object to construct 40 | /// 41 | public object CreateEmptyObject(Type type) => CreateEmptyObject(type, TypeRegistry); 42 | 43 | /// 44 | /// Create a new, empty object of a given type 45 | /// 46 | /// The type of object to construct 47 | /// 48 | public object CreateEmptyObject(ExtendedType type) => CreateEmptyObject(type, TypeRegistry); 49 | 50 | /// 51 | /// Create a new, empty object of a given type 52 | /// 53 | /// The full name of the type to create, 54 | /// 55 | public object CreateEmptyObject(string assemblyQualifiedFullName) 56 | => CreateEmptyObject(assemblyQualifiedFullName, TypeRegistry, null, 0); 57 | 58 | /// 59 | /// Create a new, empty object of a given type 60 | /// 61 | /// The full name of the type to create, 62 | /// A type registry that specifies custom mappings or factories 63 | /// 64 | public object CreateEmptyObject(string assemblyQualifiedFullName, TypeRegistry typeRegistry) 65 | => CreateEmptyObject(assemblyQualifiedFullName, typeRegistry, null, 0); 66 | 67 | /// 68 | /// Create a new, empty object of a given type 69 | /// 70 | /// The full name of the type to create, 71 | /// A type registry that specifies custom mappings or factories 72 | /// For array types, the dimensions of the array to create 73 | /// 74 | public object CreateEmptyObject(string assemblyQualifiedFullName, TypeRegistry typeRegistry, params object[] dimensions) 75 | => CreateEmptyObject(assemblyQualifiedFullName, typeRegistry, null, dimensions); 76 | 77 | /// 78 | /// Create a new, empty object of a given type 79 | /// 80 | /// The full name of the type to create, 81 | /// An optional initializer to use to create the object 82 | /// For array types, the dimensions of the array to create 83 | /// 84 | public object CreateEmptyObject(string assemblyQualifiedFullName, Func initializer, params object[] dimensions) 85 | => CreateEmptyObject(assemblyQualifiedFullName, TypeRegistry, initializer, dimensions); 86 | 87 | /// 88 | /// Create a new, empty object of a given type 89 | /// 90 | /// The full name of the type to create, 91 | /// A type registry that specifies custom mappings or factories 92 | /// An optional initializer to use to create the object 93 | /// For array types, the dimensions of the array to create 94 | /// 95 | public object CreateEmptyObject(string assemblyQualifiedFullName, TypeRegistry typeRegistry, Func initializer, params object[] dimensions) 96 | { 97 | if (string.IsNullOrEmpty(assemblyQualifiedFullName)) 98 | throw new ArgumentNullException(nameof(assemblyQualifiedFullName)); 99 | var type = Type.GetType(assemblyQualifiedFullName); 100 | return CreateEmptyObject(type.GetExtendedType(), typeRegistry, initializer, dimensions); 101 | } 102 | 103 | /// 104 | /// Create a new, empty object of a given type 105 | /// 106 | /// The type to create 107 | /// An optional initializer to use to create the object 108 | /// For array types, the dimensions of the array to create 109 | /// 110 | public object CreateEmptyObject(Type type, Func initializer, params object[] dimensions) 111 | => CreateEmptyObject(type.GetExtendedType(), TypeRegistry, initializer, dimensions); 112 | 113 | /// 114 | /// Create a new, empty object of a given type 115 | /// 116 | /// The type to create 117 | /// A type registry that specifies custom mappings or factories 118 | /// For array types, the dimensions of the array to create 119 | /// 120 | public object CreateEmptyObject(Type type, TypeRegistry typeRegistry, params object[] dimensions) 121 | => CreateEmptyObject(type.GetExtendedType(), typeRegistry, null, dimensions); 122 | 123 | /// 124 | /// Create a new, empty object of a given type 125 | /// 126 | /// The type to create 127 | /// A type registry that specifies custom mappings or factories 128 | /// For array types, the dimensions of the array to create 129 | /// 130 | public object CreateEmptyObject(ExtendedType type, TypeRegistry typeRegistry, params object[] dimensions) 131 | => CreateEmptyObject(type, typeRegistry, null, dimensions); 132 | 133 | /// 134 | /// Create a new, empty object of a given type 135 | /// 136 | /// A type registry that specifies custom mappings or factories 137 | /// For array types, the dimensions of the array to create 138 | /// 139 | public object CreateEmptyObject(Type type, params object[] dimensions) 140 | => CreateEmptyObject(type.GetExtendedType(), TypeRegistry, null, dimensions); 141 | 142 | /// 143 | /// Create a new, empty object of a given type 144 | /// 145 | /// A type registry that specifies custom mappings or factories 146 | /// An optional initializer to use to create the object 147 | /// For array types, the dimensions of the array to create 148 | /// 149 | public T CreateEmptyObject(params object[] dimensions) 150 | => (T)CreateEmptyObject(typeof(T).GetExtendedType(), TypeRegistry, null, dimensions); 151 | 152 | /// 153 | /// Create a new, empty object of a given type 154 | /// 155 | /// A type registry that specifies custom mappings or factories 156 | /// An optional initializer to use to create the object 157 | /// 158 | public T CreateEmptyObject(Func initializer) 159 | { 160 | Func init = null; 161 | if (initializer != null) 162 | init = () => initializer(); 163 | return (T)CreateEmptyObject(typeof(T).GetExtendedType(), TypeRegistry, init); 164 | } 165 | 166 | /// 167 | /// Create a new, empty object of a given type 168 | /// 169 | /// A type registry that specifies custom mappings or factories 170 | /// An optional initializer to use to create the object 171 | /// For array types, the dimensions of the array to create 172 | /// 173 | public T CreateEmptyObject(Func initializer, params object[] dimensions) 174 | { 175 | Func init = null; 176 | if (initializer != null) 177 | init = () => initializer(); 178 | return (T)CreateEmptyObject(typeof(T), init, dimensions); 179 | } 180 | 181 | /// 182 | /// Create a new, empty object of a given type 183 | /// 184 | /// A type registry that specifies custom mappings or factories 185 | /// An optional initializer to use to create the object 186 | /// For array types, the dimensions of the array to create 187 | /// 188 | public T CreateEmptyObject(TypeRegistry typeRegistry, Func initializer, params object[] dimensions) 189 | => (T)CreateEmptyObject(typeof(T).GetExtendedType(), typeRegistry, initializer as Func, dimensions); 190 | 191 | /// 192 | /// Create a new, empty object of a given type 193 | /// 194 | /// The type of object to construct 195 | /// A type registry for constructing unknown types 196 | /// A type descriptor that indicates the embedded concrete type for an interface type 197 | /// An optional initializer to use to create the object 198 | /// For array types, the dimensions of the array to create 199 | /// 200 | public object CreateEmptyObject(ExtendedType type, TypeRegistry typeRegistry, Func initializer, params object[] dimensions) 201 | { 202 | if (initializer != null) 203 | { 204 | return initializer(); 205 | } 206 | 207 | // check the type registry for a custom type mapping 208 | if (typeRegistry?.ContainsType(type.Type) == true) 209 | type = typeRegistry.GetMapping(type); 210 | // check the type registry for a custom type factory 211 | if (typeRegistry?.ContainsFactoryType(type.Type) == true) 212 | return typeRegistry.GetFactory(type.Type).Invoke(); 213 | 214 | // if we are asked to create an instance of an interface, try to initialize using a valid concrete type 215 | if (type.IsInterface && !type.IsEnumerable) 216 | { 217 | // try a known concrete type from typeSupport 218 | var concreteType = type.KnownConcreteTypes.FirstOrDefault(); 219 | if (concreteType == null) 220 | throw new TypeSupportException(type.Type, $"Unable to locate a concrete type for '{type.Type.FullName}'! Cannot create instance."); 221 | 222 | type = new ExtendedType(concreteType); 223 | } 224 | 225 | if (type.IsArray) 226 | { 227 | var createParameters = dimensions; 228 | // we also want to allow passing of collections/lists/arrays so do some conversion first 229 | if (createParameters?.Length > 0) 230 | { 231 | var parameterType = createParameters[0].GetType(); 232 | if (parameterType.IsArray) 233 | { 234 | var ar = (Array)createParameters[0]; 235 | createParameters = ar.Cast().ToArray(); 236 | } 237 | else if (typeof(ICollection).IsAssignableFrom(parameterType) 238 | || typeof(IList).IsAssignableFrom(parameterType)) 239 | { 240 | var ar = (ICollection)createParameters[0]; 241 | createParameters = ar.Cast().ToArray(); 242 | } 243 | } 244 | if (createParameters != null && createParameters.Length > 1) 245 | createParameters.Reverse(); 246 | if (createParameters == null || createParameters.Length == 0) 247 | createParameters = new object[] { 0 }; 248 | return Activator.CreateInstance(type.Type, createParameters); 249 | } 250 | else if (type.IsDictionary) 251 | { 252 | var genericType = type.Type.GetGenericArguments().ToList(); 253 | Type listType; 254 | if (genericType.Count == 0) 255 | { 256 | if(type.IsInterface) 257 | return Activator.CreateInstance() as IDictionary; 258 | return Activator.CreateInstance(type.Type) as IDictionary; 259 | } 260 | else if (genericType.Count != 2) 261 | throw new TypeSupportException(type.Type, "IDictionary should contain 2 element types."); 262 | Type[] typeArgs = { genericType[0], genericType[1] }; 263 | 264 | listType = typeof(Dictionary<,>).MakeGenericType(typeArgs); 265 | return Activator.CreateInstance(listType) as IDictionary; 266 | } 267 | else if (type.IsEnumerable && !type.IsImmutable) 268 | { 269 | var genericType = type.Type.GetGenericArguments().FirstOrDefault(); 270 | // test specifically for ICollection and List 271 | var isGenericCollection = type.Type.IsGenericType 272 | && type.Type.GetGenericTypeDefinition() == typeof(ICollection<>); 273 | var isGenericList = type.Type.IsGenericType 274 | && type.Type.GetGenericTypeDefinition() == typeof(List<>); 275 | var isGenericIList = type.Type.IsGenericType 276 | && type.Type.GetGenericTypeDefinition() == typeof(IList<>); 277 | if (!isGenericList && !isGenericIList && !isGenericCollection) 278 | { 279 | if (type.HasEmptyConstructor) 280 | { 281 | var newList = Activator.CreateInstance(type.Type); 282 | return newList; 283 | } 284 | else if (type.Constructors.Any()) 285 | { 286 | // special handling is required here as custom collections can't be properly 287 | // initialized using FormatterServices.GetUninitializedObject() 288 | var constructor = type.Constructors.First(); 289 | var parameters = constructor.GetParameters(); 290 | var param = new List(); 291 | // initialize using defaults for constructor parameters 292 | foreach (var p in parameters) 293 | param.Add(CreateEmptyObject(p.ParameterType)); 294 | var newList = Activator.CreateInstance(type.Type, param.ToArray()); 295 | return newList; 296 | } 297 | } 298 | else if (genericType != null) 299 | { 300 | var listType = typeof(List<>).MakeGenericType(genericType); 301 | var newList = (IList)Activator.CreateInstance(listType); 302 | return newList; 303 | } 304 | return Enumerable.Empty(); 305 | } 306 | else if (type.Type.ContainsGenericParameters) 307 | { 308 | // create a generic type and create an instance 309 | // to accomplish this, we need to create a new generic type using the type arguments from the interface 310 | // and the concrete class definition. voodoo! 311 | var originalTypeSupport = new ExtendedType(type.Type); 312 | var genericArguments = originalTypeSupport.Type.GetGenericArguments(); 313 | var newType = type.Type.MakeGenericType(genericArguments); 314 | object newObject; 315 | if (type.HasEmptyConstructor) 316 | newObject = Activator.CreateInstance(newType); 317 | else 318 | newObject = FormatterServices.GetUninitializedObject(newType); 319 | return newObject; 320 | } 321 | else if (type.HasEmptyConstructor && !type.Type.ContainsGenericParameters) 322 | return Activator.CreateInstance(type.Type); 323 | else if (type.IsImmutable) 324 | return null; 325 | 326 | return FormatterServices.GetUninitializedObject(type.Type); 327 | } 328 | } 329 | } 330 | -------------------------------------------------------------------------------- /TypeSupport/TypeSupport/ObjectHashcode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace TypeSupport 4 | { 5 | /// 6 | /// Tracks an object reference by hashcode and type 7 | /// 8 | public struct ObjectHashcode 9 | { 10 | /// 11 | /// The object's hashcode 12 | /// 13 | public int Hashcode { get; set; } 14 | 15 | /// 16 | /// The object's type 17 | /// 18 | public Type Type { get; set; } 19 | 20 | /// 21 | /// Tracks an object reference by hashcode and type 22 | /// 23 | /// The hashcode of the object 24 | /// The object type 25 | public ObjectHashcode(int hashcode, Type type) 26 | { 27 | if (ReferenceEquals(type, null)) 28 | throw new ArgumentNullException(nameof(type)); 29 | 30 | Hashcode = hashcode; 31 | Type = type; 32 | } 33 | 34 | public override int GetHashCode() 35 | { 36 | // recompute a new hashcode based on the type's hashcode and the object's hashcode 37 | var computedHashcode = 23; 38 | computedHashcode = computedHashcode * 31 + Hashcode; 39 | computedHashcode = computedHashcode * 31 + Type.GetHashCode(); 40 | return computedHashcode; 41 | } 42 | 43 | public override bool Equals(object obj) 44 | { 45 | if (obj == null) 46 | return false; 47 | var typedObj = (ObjectHashcode)obj; 48 | return typedObj.Hashcode.Equals(Hashcode) && typedObj.Type.Equals(Type); 49 | } 50 | 51 | public static bool operator ==(ObjectHashcode left, ObjectHashcode right) => left.Equals(right); 52 | 53 | public static bool operator !=(ObjectHashcode left, ObjectHashcode right) => !(left == right); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /TypeSupport/TypeSupport/ObjectHashcodeMap.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace TypeSupport 5 | { 6 | /// 7 | /// A hashset for tracking hashcodes in use 8 | /// 9 | public class ObjectHashcodeMap : HashSet 10 | { 11 | /// 12 | /// A hashset for tracking hashcodes in use 13 | /// 14 | public ObjectHashcodeMap() { } 15 | 16 | /// 17 | /// Add an object to the hashcode map 18 | /// 19 | /// 20 | public void Add(object obj) 21 | { 22 | if (ReferenceEquals(obj, null)) 23 | throw new ArgumentNullException(nameof(obj)); 24 | var hashCode = GetHashcodeForObject(obj); 25 | var type = obj.GetType(); 26 | Add(hashCode, type); 27 | } 28 | 29 | /// 30 | /// Add a hashcode/type pair to the hashcode map 31 | /// 32 | /// 33 | /// Object Extended type 34 | public void Add(int hashcode, ExtendedType type) 35 | { 36 | if (ReferenceEquals(type, null)) 37 | throw new ArgumentNullException(nameof(type)); 38 | var key = new ObjectHashcode(hashcode, type.Type); 39 | base.Add(key); 40 | } 41 | 42 | /// 43 | /// Add a hashcode/type pair to the hashcode map 44 | /// 45 | /// 46 | /// Object type 47 | public void Add(int hashcode, Type type) 48 | { 49 | if (ReferenceEquals(type, null)) 50 | throw new ArgumentNullException(nameof(type)); 51 | var key = new ObjectHashcode(hashcode, type); 52 | base.Add(key); 53 | } 54 | 55 | /// 56 | /// Check if an object is in the hashcode map 57 | /// 58 | /// 59 | /// 60 | public bool Contains(object obj) 61 | { 62 | if (ReferenceEquals(obj, null)) 63 | throw new ArgumentNullException(nameof(obj)); 64 | var hashcode = GetHashcodeForObject(obj); 65 | var type = obj.GetType(); 66 | var key = new ObjectHashcode(hashcode, type); 67 | return base.Contains(key); 68 | } 69 | 70 | /// 71 | /// Check if an object is in the hashcode map 72 | /// 73 | /// 74 | /// 75 | /// 76 | public bool Contains(int hashcode, Type type) 77 | { 78 | if (ReferenceEquals(type, null)) 79 | throw new ArgumentNullException(nameof(type)); 80 | var key = new ObjectHashcode(hashcode, type); 81 | return base.Contains(key); 82 | } 83 | 84 | /// 85 | /// Check if an object is in the hashcode map 86 | /// 87 | /// 88 | /// 89 | /// 90 | public bool Contains(int hashcode, ExtendedType type) 91 | { 92 | if (ReferenceEquals(type, null)) 93 | throw new ArgumentNullException(nameof(type)); 94 | var key = new ObjectHashcode(hashcode, type.Type); 95 | return base.Contains(key); 96 | } 97 | 98 | /// 99 | /// Return the hashcode for an object instance 100 | /// 101 | /// 102 | /// 103 | private int GetHashcodeForObject(object obj) => System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(obj); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /TypeSupport/TypeSupport/TypeConfiguration.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace TypeSupport 4 | { 5 | public class TypeConfiguration 6 | { 7 | /// 8 | /// Map to a destination type 9 | /// 10 | /// 11 | /// 12 | public TypeMap Create() => new TypeMap(); 13 | 14 | /// 15 | /// Use a factory to create instance of type 16 | /// 17 | /// 18 | /// 19 | /// 20 | public TypeFactory CreateUsing(Func factory) 21 | => new TypeFactory(factory); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /TypeSupport/TypeSupport/TypeFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace TypeSupport 4 | { 5 | /// 6 | /// Type factory 7 | /// 8 | /// 9 | /// 10 | public class TypeFactory : TypeFactory 11 | { 12 | /// 13 | /// Generic factory method 14 | /// 15 | public new Func Factory { get; } 16 | 17 | public TypeFactory(Func factory) : base(typeof(TSource), factory as Func) 18 | { 19 | Factory = factory; 20 | } 21 | } 22 | 23 | /// 24 | /// Type factory 25 | /// 26 | public class TypeFactory 27 | { 28 | /// 29 | /// The source type 30 | /// 31 | public Type Source { get; } 32 | /// 33 | /// The factory method 34 | /// 35 | public Func Factory { get; } 36 | internal TypeFactory(Type source) 37 | { 38 | Source = source; 39 | } 40 | internal TypeFactory(Type source, Func factory) 41 | { 42 | Source = source; 43 | Factory = factory; 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /TypeSupport/TypeSupport/TypeMap.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace TypeSupport 4 | { 5 | /// 6 | /// Custom type mapping 7 | /// 8 | /// 9 | /// 10 | public class TypeMap : TypeMap 11 | { 12 | public TypeMap() : base(typeof(TSource), typeof(TDestination)) 13 | { 14 | } 15 | } 16 | 17 | /// 18 | /// Custom type mapping 19 | /// 20 | public class TypeMap 21 | { 22 | public Type Source { get; set; } 23 | public Type Destination { get; set; } 24 | 25 | internal TypeMap(Type source, Type destination) 26 | { 27 | Source = source; 28 | Destination = destination; 29 | } 30 | 31 | public override string ToString() => $"{Source.Name} => {Destination.Name}"; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /TypeSupport/TypeSupport/TypeRegistry.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using TypeSupport.Extensions; 5 | 6 | namespace TypeSupport 7 | { 8 | /// 9 | /// A type registry to map one type to another 10 | /// 11 | public class TypeRegistry 12 | { 13 | /// 14 | /// Gets the registered type mappings 15 | /// 16 | public ICollection Mappings { get; private set; } 17 | /// 18 | /// Gets the registered type factories 19 | /// 20 | public ICollection Factories { get; private set; } 21 | 22 | private TypeRegistry() 23 | { 24 | Mappings = new List(); 25 | Factories = new List(); 26 | } 27 | 28 | internal TypeRegistry(TypeMap[] typeMaps) 29 | { 30 | Mappings = new List(); 31 | foreach (var typeMap in typeMaps) 32 | Mappings.Add(typeMap); 33 | } 34 | 35 | /// 36 | /// Add a type mapping from source type to destination type 37 | /// 38 | /// Source type 39 | /// Destination type 40 | public void AddMapping() 41 | => Mappings.Add(new TypeMap()); 42 | 43 | /// 44 | /// Add a type factory for creating types 45 | /// 46 | /// Source type 47 | /// Destination type 48 | /// 49 | public void AddFactory(Func factory) 50 | => Factories.Add(new TypeFactory(factory)); 51 | 52 | /// 53 | /// True if a mapping exists for the source type 54 | /// 55 | /// 56 | /// 57 | public bool ContainsType(Type type) => Mappings.Any(x => x.Source.Equals(type)); 58 | 59 | /// 60 | /// True if a mapping exists for the source type 61 | /// 62 | /// 63 | /// 64 | public bool ContainsType(ExtendedType type) => Mappings.Any(x => x.Source.Equals(type.Type)); 65 | 66 | /// 67 | /// True if a factory exists for the source type 68 | /// 69 | /// 70 | /// 71 | public bool ContainsFactoryType(Type type) => Factories.Any(x => x.Source.Equals(type)); 72 | 73 | /// 74 | /// True if a factory exists for the source type 75 | /// 76 | /// 77 | /// 78 | public bool ContainsFactoryType(ExtendedType type) => ContainsFactoryType(type.Type); 79 | 80 | /// 81 | /// Get the destination mapping for a source type 82 | /// 83 | /// 84 | /// 85 | internal Type GetMapping(Type type) 86 | { 87 | var mapping = Mappings 88 | .Where(x => x.Source.Equals(type)) 89 | .Select(x => x.Destination) 90 | .FirstOrDefault(); 91 | return mapping; 92 | } 93 | 94 | /// 95 | /// Get the destination mapping for a source type 96 | /// 97 | /// 98 | /// 99 | internal ExtendedType GetMapping(ExtendedType type) 100 | { 101 | var mapping = Mappings 102 | .Where(x => x.Source.Equals(type)) 103 | .Select(x => x.Destination) 104 | .FirstOrDefault() 105 | .GetExtendedType(); 106 | return mapping; 107 | } 108 | 109 | /// 110 | /// Get the factory for creating a source type 111 | /// 112 | /// 113 | /// 114 | internal Func GetFactory(Type type) 115 | { 116 | var factory = Factories.Where(x => x.Source.Equals(type)).Select(x => x.Factory).FirstOrDefault(); 117 | return factory; 118 | } 119 | 120 | /// 121 | /// Get the factory for creating a source type 122 | /// 123 | /// 124 | /// 125 | internal Func GetFactory(ExtendedType type) => GetFactory(type.Type); 126 | 127 | /// 128 | /// Configure a new type registry 129 | /// 130 | /// 131 | /// 132 | public static TypeRegistry Configure(Action config) 133 | { 134 | var registry = new TypeRegistry(); 135 | config(registry); 136 | return registry; 137 | } 138 | 139 | /// 140 | /// For the source type 141 | /// 142 | /// 143 | /// 144 | public static TypeConfiguration For() => new TypeConfiguration(); 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /TypeSupport/TypeSupport/TypeSupport.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0;netstandard2.1;net40;net45;net46;net461;net462;net47;net471;net472;net48;net5;net6.0;net7.0 5 | https://github.com/replaysMike/TypeSupport 6 | https://github.com/replaysMike/TypeSupport 7 | type support utility reflection tools 8 | TypeSupport provides tools to give you more information about .Net types and factories for working with objects, collections, enums and more. 9 | TypeSupport provides tools to give you more information about .Net types and factories for working with objects, collections, enums and more. 10 | Refactor Software 11 | Michael Brown 12 | 1.2.0.0 13 | 1.2 14 | 1.2.0.0 15 | true 16 | true 17 | snupkg 18 | latest 19 | true 20 | typesupport.png 21 | false 22 | ..\TypeSupportStrongNameKey.snk 23 | 24 | 25 | 26 | FEATURE_CUSTOM_ATTRIBUTES;FEATURE_CUSTOM_TYPEINFO;FEATURE_GETMETHOD;FEATURE_SETVALUE;FEATURE_TASK;FEATURE_ASSEMBLYBUILDER 27 | 28 | 29 | 30 | FEATURE_CUSTOM_VALUETUPLE;FEATURE_CUSTOM_ATTRIBUTES;FEATURE_CUSTOM_TYPEINFO;FEATURE_GETMETHOD;FEATURE_SETVALUE;FEATURE_TASK;FEATURE_ASSEMBLYBUILDER 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /TypeSupport/TypeSupport/TypeSupportException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace TypeSupport 4 | { 5 | /// 6 | /// A type support exception 7 | /// 8 | public class TypeSupportException : Exception 9 | { 10 | Type RequestedType { get; } 11 | 12 | /// 13 | /// A type support exception 14 | /// 15 | /// 16 | public TypeSupportException(string message) : base(message) 17 | { 18 | 19 | } 20 | 21 | /// 22 | /// A type support exception 23 | /// 24 | /// 25 | /// 26 | public TypeSupportException(Type requestedType, string message) : base(message) 27 | { 28 | RequestedType = requestedType; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /TypeSupport/TypeSupport/TypeSupportOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace TypeSupport 4 | { 5 | /// 6 | /// Type support options 7 | /// 8 | [Flags] 9 | public enum TypeSupportOptions : int 10 | { 11 | /// 12 | /// Load and inspect custom attributes for object 13 | /// 14 | Attributes = 1, 15 | /// 16 | /// Load and inspect collection information 17 | /// 18 | Collections = 2, 19 | /// 20 | /// Load and discover all concrete types for an interface 21 | /// 22 | ConcreteTypes = 4, 23 | /// 24 | /// Load all constructor information 25 | /// 26 | Constructors = 8, 27 | /// 28 | /// Load and inspect enum information for an object 29 | /// 30 | Enums = 16, 31 | /// 32 | /// Load and inspect fields for object 33 | /// 34 | Fields = 32, 35 | /// 36 | /// Load and inspect generics information 37 | /// 38 | Generics = 64, 39 | /// 40 | /// Load and inspect indexers object 41 | /// 42 | Indexers = 128, 43 | /// 44 | /// Load and inspect properties for object 45 | /// 46 | Properties = 256, 47 | /// 48 | /// Enable type caching 49 | /// 50 | Caching = 512, 51 | /// 52 | /// Load and inspect methods 53 | /// 54 | Methods = 1024, 55 | /// 56 | /// Uses all default options 57 | /// 58 | All = Attributes | Collections | ConcreteTypes | Constructors | Enums | Fields | Generics | Indexers | Properties | Caching | Methods, 59 | /// 60 | /// Uses all default options, without caching 61 | /// 62 | AllExceptCaching = Attributes | Collections | ConcreteTypes | Constructors | Enums | Fields | Generics | Indexers | Properties | Methods, 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /TypeSupport/TypeSupport/typesupport.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/replaysMike/TypeSupport/54bf3051ed6ad679b8e71b424605111ef2445703/TypeSupport/TypeSupport/typesupport.png -------------------------------------------------------------------------------- /TypeSupport/TypeSupportStrongNameKey.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/replaysMike/TypeSupport/54bf3051ed6ad679b8e71b424605111ef2445703/TypeSupport/TypeSupportStrongNameKey.snk -------------------------------------------------------------------------------- /TypeSupport/runtests.ps1: -------------------------------------------------------------------------------- 1 | # this script is for generating coverage reports to the path c:\coverlet - the path is hardcoded for supporting PrestoCoverage extension 2 | # requires installing coverlet, and may require .net core 2.2+ - `dotnet tool install --global coverlet.console` 3 | dotnet test 4 | coverlet.exe .\TypeSupport.Tests\bin\Debug\netcoreapp2.1\TypeSupport.Tests.dll --target "dotnet" --targetargs "test .\TypeSupport.Tests\TypeSupport.Tests.csproj --no-build" --output "C:\coverlet\coverage" --format json -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: 1.2.{build} 2 | image: Visual Studio 2022 3 | configuration: Release 4 | dotnet_csproj: 5 | patch: true 6 | file: '**\*.csproj' 7 | version: '{version}' 8 | package_version: '{version}' 9 | assembly_version: '{version}' 10 | file_version: '{version}' 11 | informational_version: '{version}' 12 | environment: 13 | CODACY_TOKEN: 14 | secure: i4htiDvo1KvqjlwwqZoFE+MUhANU+/ODvqQ94ocj+ciTCzRzJlpLU4YmBkeGGX+v 15 | cache: 16 | - packages -> **\packages.config 17 | - '%USERPROFILE%\.nuget\packages -> **\project.json' # project.json cache 18 | before_build: 19 | - ps: dotnet restore .\TypeSupport\TypeSupport.sln 20 | build_script: 21 | - ps: .\scripts\build.ps1 22 | test_script: 23 | - ps: .\scripts\run-tests.ps1 24 | after_test: 25 | - ps: .\scripts\send-coverage.ps1 26 | -------------------------------------------------------------------------------- /scripts/build.ps1: -------------------------------------------------------------------------------- 1 | Write-Host "Building..." -ForegroundColor green 2 | 3 | dotnet build .\TypeSupport\TypeSupport.sln | Select-String -Pattern " warning " -NotMatch | Select-String -Pattern "INFO:" -NotMatch | Select-String -Pattern "WARNING:" -NotMatch 4 | 5 | Write-Host "Packaging..." -ForegroundColor green 6 | dotnet pack .\TypeSupport\TypeSupport\TypeSupport.csproj --configuration Release --no-build -p:IncludeSymbols=true -p:SymbolPackageFormat=snupkg 7 | 8 | Get-ChildItem .\*.nupkg -recurse | % { Push-AppveyorArtifact $_.FullName -FileName $_.Name -Type NuGetPackage } 9 | 10 | Get-ChildItem .\*.snupkg -recurse | % { Push-AppveyorArtifact $_.FullName -FileName $_.Name -Type NuGetPackage } 11 | -------------------------------------------------------------------------------- /scripts/run-tests.ps1: -------------------------------------------------------------------------------- 1 | Write-Host "Running Tests..." -ForegroundColor green 2 | 3 | Get-ChildItem ".\TypeSupport\TypeSupport.Tests\" -recurse | where {$_.extension -eq ".csproj"} | % { dotnet test --no-build --no-restore --test-adapter-path:. --logger:Appveyor /p:CollectCoverage=true /p:CoverletOutputFormat=cobertura $_.FullName } 4 | -------------------------------------------------------------------------------- /scripts/send-coverage.ps1: -------------------------------------------------------------------------------- 1 | Write-Host "Submitting Codacy Coverage (commit $env:APPVEYOR_REPO_COMMIT)" -ForegroundColor green 2 | 3 | Start-FileDownload 'https://github.com/codacy/codacy-coverage-reporter/releases/download/4.0.5/codacy-coverage-reporter-4.0.5-assembly.jar' 4 | 5 | Get-ChildItem ".\TypeSupport\TypeSupport.Tests\" -recurse | where {$_.name -eq "coverage.cobertura.xml"} | % { java -jar codacy-coverage-reporter-4.0.5-assembly.jar report -l CSharp -r $_.FullName --partial --project-token "$env:CODACY_TOKEN" --commit-uuid "$env:APPVEYOR_REPO_COMMIT" | Select-String -Pattern "INFO" | Select-String -Pattern "-INFO" -NotMatch } 6 | 7 | java -jar codacy-coverage-reporter-4.0.5-assembly.jar final --project-token "$env:CODACY_TOKEN" --commit-uuid "$env:APPVEYOR_REPO_COMMIT" | Select-String -Pattern "INFO" | Select-String -Pattern "-INFO" -NotMatch --------------------------------------------------------------------------------