From 2578317d345d88c0887e66c8bb8c0a460cdc9614 Mon Sep 17 00:00:00 2001 From: "shoguns6@yahoo.com" Date: Wed, 28 Oct 2020 12:37:18 +0530 Subject: [PATCH 01/13] 'Other 'Objects ' registered as 'scoped' too, gives 'same' instance for all 'Request'. This fix will ensure 'addscoped' gives different object instance for each request. --- .../Extensions/ServiceCollectionExtensions.cs | 37 ++++++++++++------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/SimpleProxy/Extensions/ServiceCollectionExtensions.cs b/SimpleProxy/Extensions/ServiceCollectionExtensions.cs index 66ad411..9587a90 100644 --- a/SimpleProxy/Extensions/ServiceCollectionExtensions.cs +++ b/SimpleProxy/Extensions/ServiceCollectionExtensions.cs @@ -45,16 +45,20 @@ public static IServiceCollection EnableSimpleProxy(this IServiceCollection servi /// public static IServiceCollection AddTransientWithProxy(this IServiceCollection services) where TService : TInterface { - var serviceProvider = services.BuildServiceProvider(); - var proxyConfiguration = services.GetProxyConfiguration(); - var proxyGenerator = serviceProvider.GetService(); - var proxyInstance = ActivatorUtilities.CreateInstance(serviceProvider); - // Wrap the service with a Proxy instance and add it with Transient Scope services.AddTransient(typeof(TInterface), - p => new ProxyFactory(serviceProvider, proxyGenerator, proxyConfiguration) - .CreateProxy(ActivatorUtilities.CreateInstance(serviceProvider))); + p => + { + var serviceProvider = services.BuildServiceProvider(); + var proxyConfiguration = services.GetProxyConfiguration(); + var proxyGenerator = serviceProvider.GetService(); + return new ProxyFactory( + serviceProvider, + proxyGenerator, + proxyConfiguration) + .CreateProxy(ActivatorUtilities.CreateInstance(serviceProvider)); + }); // Return the IServiceCollection for chaining configuration return services; } @@ -68,13 +72,20 @@ public static IServiceCollection AddTransientWithProxy(thi /// public static IServiceCollection AddScopedWithProxy(this IServiceCollection services) where TService : TInterface { - var serviceProvider = services.BuildServiceProvider(); - var proxyConfiguration = services.GetProxyConfiguration(); - var proxyGenerator = serviceProvider.GetService(); - var proxyInstance = ActivatorUtilities.CreateInstance(serviceProvider); - // Wrap the service with a Proxy instance and add it with Scoped Scope - services.AddScoped(typeof(TInterface), p => new ProxyFactory(serviceProvider, proxyGenerator, proxyConfiguration).CreateProxy(proxyInstance)); + services.AddScoped(typeof(TInterface), + p => + { + var serviceProvider = services.BuildServiceProvider(); + var proxyConfiguration = services.GetProxyConfiguration(); + var proxyGenerator = serviceProvider.GetService(); + + return new ProxyFactory( + serviceProvider, + proxyGenerator, + proxyConfiguration) + .CreateProxy(ActivatorUtilities.CreateInstance(serviceProvider)); + }); // Return the IServiceCollection for chaining configuration return services; From a07edf897ed2087fdd75f23a48e12930dfa566d1 Mon Sep 17 00:00:00 2001 From: "shoguns6@yahoo.com" Date: Fri, 30 Oct 2020 23:50:36 +0530 Subject: [PATCH 02/13] Upgrade dependenct --- SampleApp/SampleApp.csproj | 4 ++-- .../SimpleProxy.Logging.csproj | 2 +- SimpleProxy/SimpleProxy.csproj | 24 +++++++++++++++---- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/SampleApp/SampleApp.csproj b/SampleApp/SampleApp.csproj index a665cba..f193e5e 100644 --- a/SampleApp/SampleApp.csproj +++ b/SampleApp/SampleApp.csproj @@ -8,8 +8,8 @@ - - + + diff --git a/SimpleProxy.Logging/SimpleProxy.Logging.csproj b/SimpleProxy.Logging/SimpleProxy.Logging.csproj index e4b7d6e..5ee8ab1 100644 --- a/SimpleProxy.Logging/SimpleProxy.Logging.csproj +++ b/SimpleProxy.Logging/SimpleProxy.Logging.csproj @@ -5,7 +5,7 @@ - + diff --git a/SimpleProxy/SimpleProxy.csproj b/SimpleProxy/SimpleProxy.csproj index 1bf7096..9e0f305 100644 --- a/SimpleProxy/SimpleProxy.csproj +++ b/SimpleProxy/SimpleProxy.csproj @@ -2,17 +2,31 @@ netcoreapp3.1 - Simple Proxy is a simple extension library built to solve the problem of Aspect Orientated Programming in Net Core projects + Simple Proxy is a simple extension library built to solve the problem of Aspect Orientated Programming in Net Core projects. Robert Perry https://github.com/f135ta/SimpleProxy + 1.0.3 + false + SimpleProxyCp + SimpleProxyCp + SimpleProxyCp + SimpleProxyCp + LICENSE - + - - - + + + + + + + + True + + From b66b6be911b60b4536315c45880629bcde1ac845 Mon Sep 17 00:00:00 2001 From: "shoguns6@yahoo.com" Date: Tue, 3 Nov 2020 10:41:01 +0530 Subject: [PATCH 03/13] Update --- .../Extensions/ServiceCollectionExtensions.cs | 20 +++++++++---------- SimpleProxy/SimpleProxy.csproj | 8 ++++---- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/SimpleProxy/Extensions/ServiceCollectionExtensions.cs b/SimpleProxy/Extensions/ServiceCollectionExtensions.cs index 9587a90..62d7de4 100644 --- a/SimpleProxy/Extensions/ServiceCollectionExtensions.cs +++ b/SimpleProxy/Extensions/ServiceCollectionExtensions.cs @@ -45,19 +45,19 @@ public static IServiceCollection EnableSimpleProxy(this IServiceCollection servi /// public static IServiceCollection AddTransientWithProxy(this IServiceCollection services) where TService : TInterface { + var serviceProvider = services.BuildServiceProvider(); + var proxyConfiguration = services.GetProxyConfiguration(); + var proxyGenerator = serviceProvider.GetService(); + // Wrap the service with a Proxy instance and add it with Transient Scope services.AddTransient(typeof(TInterface), p => { - var serviceProvider = services.BuildServiceProvider(); - var proxyConfiguration = services.GetProxyConfiguration(); - var proxyGenerator = serviceProvider.GetService(); - return new ProxyFactory( serviceProvider, proxyGenerator, proxyConfiguration) - .CreateProxy(ActivatorUtilities.CreateInstance(serviceProvider)); + .CreateProxy(ActivatorUtilities.CreateInstance(services.BuildServiceProvider())); }); // Return the IServiceCollection for chaining configuration return services; @@ -72,19 +72,19 @@ public static IServiceCollection AddTransientWithProxy(thi /// public static IServiceCollection AddScopedWithProxy(this IServiceCollection services) where TService : TInterface { + + var serviceProvider = services.BuildServiceProvider(); + var proxyConfiguration = services.GetProxyConfiguration(); + var proxyGenerator = serviceProvider.GetService(); // Wrap the service with a Proxy instance and add it with Scoped Scope services.AddScoped(typeof(TInterface), p => { - var serviceProvider = services.BuildServiceProvider(); - var proxyConfiguration = services.GetProxyConfiguration(); - var proxyGenerator = serviceProvider.GetService(); - return new ProxyFactory( serviceProvider, proxyGenerator, proxyConfiguration) - .CreateProxy(ActivatorUtilities.CreateInstance(serviceProvider)); + .CreateProxy(ActivatorUtilities.CreateInstance(services.BuildServiceProvider())); }); // Return the IServiceCollection for chaining configuration diff --git a/SimpleProxy/SimpleProxy.csproj b/SimpleProxy/SimpleProxy.csproj index 9e0f305..63e970d 100644 --- a/SimpleProxy/SimpleProxy.csproj +++ b/SimpleProxy/SimpleProxy.csproj @@ -5,7 +5,7 @@ Simple Proxy is a simple extension library built to solve the problem of Aspect Orientated Programming in Net Core projects. Robert Perry https://github.com/f135ta/SimpleProxy - 1.0.3 + 1.0.4 false SimpleProxyCp SimpleProxyCp @@ -17,9 +17,9 @@ - - - + + + From 21a5432e6ecf0a284b59052bb24b28b8d78a4d24 Mon Sep 17 00:00:00 2001 From: "shoguns6@yahoo.com" Date: Tue, 3 Nov 2020 10:43:37 +0530 Subject: [PATCH 04/13] Update --- SimpleProxy/SimpleProxy.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SimpleProxy/SimpleProxy.csproj b/SimpleProxy/SimpleProxy.csproj index 63e970d..77c2f0d 100644 --- a/SimpleProxy/SimpleProxy.csproj +++ b/SimpleProxy/SimpleProxy.csproj @@ -5,7 +5,7 @@ Simple Proxy is a simple extension library built to solve the problem of Aspect Orientated Programming in Net Core projects. Robert Perry https://github.com/f135ta/SimpleProxy - 1.0.4 + 1.0.5 false SimpleProxyCp SimpleProxyCp From 762b5dc3d8cc33e7397aeb4c6fd0a0785d068811 Mon Sep 17 00:00:00 2001 From: "shoguns6@yahoo.com" Date: Thu, 10 Dec 2020 12:03:04 +0530 Subject: [PATCH 05/13] upate --- SampleApp/ITestClass.cs | 11 +++++++++++ SampleApp/Program.cs | 34 +++++++++++++++++++++++----------- SampleApp/TestClass.cs | 36 +++++++++++++++++++++++++++++++++++- 3 files changed, 69 insertions(+), 12 deletions(-) diff --git a/SampleApp/ITestClass.cs b/SampleApp/ITestClass.cs index 173e383..ef912d6 100644 --- a/SampleApp/ITestClass.cs +++ b/SampleApp/ITestClass.cs @@ -5,8 +5,19 @@ namespace SampleApp public interface ITestClass { + string Instance { get; set; } DateTime TestMethod(); DateTime TestMethodWithExpirationPolicy(); Task TestMethodAsync(); } + + public interface ICommon + { + string Instance { get; set; } + } + + public interface IDBMock + { + string Instance { get; set; } + } } diff --git a/SampleApp/Program.cs b/SampleApp/Program.cs index cd68dce..9345da6 100644 --- a/SampleApp/Program.cs +++ b/SampleApp/Program.cs @@ -13,7 +13,18 @@ namespace SampleApp { public class Program { - public static async Task Main(string[] args) + public static void Main(string[] args) + { + for (int i = 0; i <= 300; i++) + { + AddScopedTest(); + Console.WriteLine($"Run completed for index {i}"); + } + Console.WriteLine("All completed."); + Console.ReadLine(); + } + + private static async Task AddScopedTest() { // Configure the Service Provider var services = new ServiceCollection(); @@ -22,6 +33,8 @@ public static async Task Main(string[] args) services.AddOptions(); services.AddMemoryCache(); services.AddLogging(p => p.AddConsole(x => x.IncludeScopes = true).SetMinimumLevel(LogLevel.Trace)); + services.AddScoped(); + services.AddScoped(); services.EnableSimpleProxy(p => p .AddInterceptor() @@ -29,25 +42,24 @@ public static async Task Main(string[] args) .AddInterceptor() .WithOrderingStrategy()); - services.AddTransientWithProxy(); + services.AddScopedWithProxy(); // Get a Proxied Class and call a method var serviceProvider = services.BuildServiceProvider(); var testProxy = serviceProvider.GetService(); + System.Diagnostics.Debug.WriteLine($"Test Class Instance {testProxy.Instance}"); + for (int j = 0; j < 100; j++) + { + var testProxy1 = serviceProvider.GetService(); + System.Diagnostics.Debug.WriteLine($"Test Class Instance {testProxy1.Instance}"); - testProxy.TestMethod(); - - await testProxy.TestMethodAsync(); - - testProxy.TestMethodWithExpirationPolicy(); // set the cache - testProxy.TestMethodWithExpirationPolicy(); // execute just using the cache value - System.Threading.Thread.Sleep(25000); // time to expire the registry - testProxy.TestMethodWithExpirationPolicy(); // execute the method again + testProxy.TestMethod(); + testProxy.TestMethodWithExpirationPolicy(); // set the cache + } Console.WriteLine("====> All Test Methods Complete. Press a key. <===="); - Console.ReadLine(); } } } diff --git a/SampleApp/TestClass.cs b/SampleApp/TestClass.cs index 9b8a665..58c8cab 100644 --- a/SampleApp/TestClass.cs +++ b/SampleApp/TestClass.cs @@ -12,20 +12,28 @@ namespace SampleApp /// public class TestClass : ITestClass { + private static int count = 0; + /// /// The Logger /// private readonly ILogger logger; + private readonly ICommon common; + /// /// Initialises a new instance of the /// /// Logger Factory - public TestClass(ILoggerFactory loggerFactory) + public TestClass(ILoggerFactory loggerFactory, ICommon common) { this.logger = loggerFactory.CreateLogger(); + this.common = common; + this.Instance = $"Test Class Instnce: {++count}. -- Common: {common.Instance} "; } + public string Instance { get; set; } + /// /// Test Method /// @@ -69,4 +77,30 @@ public Task TestMethodAsync() } } + public class Common : ICommon + { + private static int count = 0; + public IDBMock mock; + public Common(IDBMock dBMock) + { + this.mock = dBMock; + + Instance = $"Common Instance Id {++count} -- DBMOck Id: {mock.Instance }"; + } + public string Instance { get; set; } + } + + public class DBMOck : IDBMock + { + private static int count = 0; + + public DBMOck() + { + Instance = $"DB MOCK ID : {++count}"; + + } + + public string Instance { get; set; } + } + } From c0d64f7e9fb46c612bea8b78157d866f9f006b21 Mon Sep 17 00:00:00 2001 From: "shoguns6@yahoo.com" Date: Mon, 29 Mar 2021 10:59:55 +0530 Subject: [PATCH 06/13] push --- SampleApp/SampleApp.csproj | 2 +- SimpleProxy/SimpleProxy.csproj | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/SampleApp/SampleApp.csproj b/SampleApp/SampleApp.csproj index f193e5e..1092c75 100644 --- a/SampleApp/SampleApp.csproj +++ b/SampleApp/SampleApp.csproj @@ -8,7 +8,7 @@ - + diff --git a/SimpleProxy/SimpleProxy.csproj b/SimpleProxy/SimpleProxy.csproj index 77c2f0d..635d11c 100644 --- a/SimpleProxy/SimpleProxy.csproj +++ b/SimpleProxy/SimpleProxy.csproj @@ -16,10 +16,9 @@ - - - - + + + From c2963491727c18b4ee697734c549dcf618948641 Mon Sep 17 00:00:00 2001 From: "shoguns6@yahoo.com" Date: Mon, 29 Mar 2021 13:59:16 +0530 Subject: [PATCH 07/13] Update --- SimpleProxy/SimpleProxy.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SimpleProxy/SimpleProxy.csproj b/SimpleProxy/SimpleProxy.csproj index 635d11c..dae9805 100644 --- a/SimpleProxy/SimpleProxy.csproj +++ b/SimpleProxy/SimpleProxy.csproj @@ -5,7 +5,7 @@ Simple Proxy is a simple extension library built to solve the problem of Aspect Orientated Programming in Net Core projects. Robert Perry https://github.com/f135ta/SimpleProxy - 1.0.5 + 1.0.6 false SimpleProxyCp SimpleProxyCp From 0b40728d55042ae3354def8ad1963a02c473d432 Mon Sep 17 00:00:00 2001 From: "shoguns6@yahoo.com" Date: Fri, 9 Apr 2021 16:39:03 +0530 Subject: [PATCH 08/13] Update --- .../AsyncDeterminationInterceptor.cs | 115 ++ .../AsyncInterceptorBase.cs | 205 +++ .../AsyncTimingInterceptor.cs | 55 + .../Castle.Core.AsyncInterceptor.csproj | 57 + .../IAsyncInterceptor.cs | 32 + .../NoCoverage/RethrowHelper.cs | 67 + .../ProcessingAsyncInterceptor.cs | 147 ++ .../Properties/AssemblyInfo.cs | 35 + .../ProxyGeneratorExtensions.cs | 444 +++++ Castle.Core.AsyncInterceptor/SharedKey.snk | Bin 0 -> 596 bytes Castle.Core/Castle.Core.csproj | 52 + .../AbstractDictionaryAdapter.cs | 170 ++ .../AbstractDictionaryAdapterVisitor.cs | 159 ++ .../Attributes/ComponentAttribute.cs | 94 + .../Attributes/DictionaryAdapterAttribute.cs | 32 + .../Attributes/DictionaryBehaviorAttribute.cs | 40 + .../Attributes/FetchAttribute.cs | 45 + .../Attributes/GroupAttribute.cs | 48 + .../Attributes/IfExistsAttribute.cs | 26 + .../Attributes/KeyAttribute.cs | 50 + .../Attributes/KeyPrefixAttribute.cs | 54 + .../Attributes/KeySubstitutionAttribute.cs | 44 + .../Attributes/MultiLevelEditAttribute.cs | 30 + .../Attributes/NewGuidAttribute.cs | 39 + .../Attributes/OnDemandAttribute.cs | 198 +++ .../Attributes/ReferenceAttribute.cs | 27 + .../Attributes/RemoveIfAttribute.cs | 123 ++ .../Attributes/RemoveIfEmptyAttribute.cs | 60 + .../Attributes/StringFormatAttribute.cs | 77 + .../Attributes/StringListAttribute.cs | 245 +++ .../Attributes/StringStorageAttribute.cs | 28 + .../Attributes/StringValuesAttribute.cs | 58 + .../SuppressNotificationsAttribute.cs | 30 + .../Attributes/TypeKeyPrefixAttribute.cs | 30 + .../Attributes/VolatileAttribute.cs | 26 + .../Attributes/XPathAttribute.cs | 57 + .../Attributes/XPathFunctionAttribute.cs | 38 + .../Attributes/XPathVariableAttribute.cs | 34 + .../Attributes/XmlDefaultsAttribute.cs | 26 + .../Attributes/XmlNamespaceAttribute.cs | 36 + .../CascadingDictionaryAdapter.cs | 56 + .../DefaultPropertyGetter.cs | 74 + .../DictionaryAdapterBase.Coerce.cs | 40 + .../DictionaryAdapterBase.Copy.cs | 56 + .../DictionaryAdapterBase.Create.cs | 61 + .../DictionaryAdapterBase.Edit.cs | 244 +++ .../DictionaryAdapterBase.Notify.cs | 215 +++ .../DictionaryAdapterBase.Validate.cs | 105 ++ .../DictionaryAdapterBase.cs | 216 +++ .../DictionaryAdapterExtensions.cs | 29 + .../DictionaryAdapterFactory.cs | 495 ++++++ .../DictionaryAdapterInstance.cs | 154 ++ .../DictionaryAdapterMeta.cs | 130 ++ .../DictionaryValidateGroup.cs | 106 ++ .../DynamicDictionary.cs | 52 + .../GenericDictionaryAdapter.cs | 66 + .../IDictionaryAdapter.cs | 52 + .../IDictionaryAdapterFactory.cs | 128 ++ .../IDictionaryAdapterVisitor.cs | 34 + .../IDictionaryBehavior.cs | 33 + .../IDictionaryBehaviorBuilder.cs | 29 + .../IDictionaryCoerceStrategy.cs | 23 + .../IDictionaryCopyStrategy.cs | 23 + .../IDictionaryCreate.cs | 37 + .../IDictionaryCreateStrategy.cs | 24 + .../IDictionaryEdit.cs | 37 + .../IDictionaryEqualityHashCodeStrategy.cs | 23 + .../IDictionaryInitializer.cs | 29 + .../IDictionaryKeyBuilder.cs | 34 + .../IDictionaryMetaInitializer.cs | 43 + .../IDictionaryNotify.cs | 37 + .../IDictionaryPropertyGetter.cs | 36 + .../IDictionaryPropertySetter.cs | 34 + .../IDictionaryReferenceManager.cs | 26 + .../IDictionaryValidate.cs | 35 + .../IDictionaryValidator.cs | 50 + .../IPropertyDescriptorInitializer.cs | 29 + .../MemberwiseEqualityHashCodeStrategy.cs | 152 ++ .../NameValueCollectionAdapter.cs | 93 + .../PropertyChangedEventArgsEx.cs | 41 + .../PropertyChangingEventArgsEx.cs | 48 + .../PropertyDescriptor.cs | 471 +++++ .../Util/BindingList.cs | 325 ++++ .../Util/BindingListInitializer.cs | 114 ++ .../Util/DynamicValue.cs | 36 + .../Util/DynamicValueDelegate.cs | 33 + .../Util/EditableBindingList.cs | 94 + .../Util/EditableList.cs | 107 ++ .../Util/IBindingList.cs | 42 + .../Util/IBindingListSource.cs | 23 + .../Util/ICollectionAdapter.cs | 45 + .../Util/ICollectionAdapterObserver.cs | 27 + .../Util/ICollectionProjection.cs | 25 + .../Util/ICondition.cs | 24 + .../Util/IDynamicValue.cs | 33 + .../Util/IValueInitializer.cs | 21 + .../Util/IVirtual.cs | 36 + .../Util/IVirtualSite.cs | 21 + .../Util/IVirtualTarget.cs | 21 + .../Util/ListProjection.cs | 603 +++++++ .../Util/ListProjectionDebugView.cs | 48 + .../Util/SetProjection.cs | 159 ++ .../Util/VirtualObject.cs | 97 + .../Util/VirtualSite.cs | 74 + .../Xml/Core/DefaultXmlReferenceFormat.cs | 65 + .../Xml/Core/IXmlReferenceFormat.cs | 28 + .../Xml/Core/XmlAdapter.cs | 504 ++++++ .../Xml/Core/XmlMetadata.cs | 385 ++++ .../Xml/Core/XmlMetadataBehavior.cs | 56 + .../Xml/Core/XmlReferenceManager.cs | 584 ++++++ .../Xml/Internal/Accessors/IXmlAccessor.cs | 32 + .../Accessors/IXmlBehaviorSemantics.cs | 25 + .../Accessors/IXmlCollectionAccessor.cs | 25 + .../Accessors/IXmlPropertyAccessor.cs | 24 + .../Accessors/XPathBehaviorAccessor.cs | 220 +++ .../Xml/Internal/Accessors/XmlAccessor.cs | 345 ++++ .../Internal/Accessors/XmlAccessorFactory.cs | 22 + .../Accessors/XmlArrayBehaviorAccessor.cs | 131 ++ .../Accessors/XmlAttributeBehaviorAccessor.cs | 64 + .../Accessors/XmlDefaultBehaviorAccessor.cs | 50 + .../Accessors/XmlElementBehaviorAccessor.cs | 122 ++ .../Accessors/XmlIgnoreBehaviorAccessor.cs | 111 ++ .../Xml/Internal/Accessors/XmlNodeAccessor.cs | 223 +++ .../Xml/Internal/Accessors/XmlSelfAccessor.cs | 37 + .../Collections/XmlCollectionAdapter.cs | 258 +++ .../Internal/Collections/XmlCollectionItem.cs | 41 + .../Xml/Internal/Collections/XmlNodeList.cs | 41 + .../Xml/Internal/Collections/XmlNodeSet.cs | 41 + .../Xml/Internal/Cursors/Base/CursorFlags.cs | 57 + .../Xml/Internal/Cursors/Base/IXmlContext.cs | 33 + .../Xml/Internal/Cursors/Base/IXmlCursor.cs | 30 + .../Xml/Internal/Cursors/Base/IXmlIterator.cs | 23 + .../Cursors/Base/IXmlNamespaceSource.cs | 22 + .../Xml/Internal/Cursors/Base/IXmlNode.cs | 55 + .../Internal/Cursors/Base/IXmlNodeSource.cs | 21 + .../Xml/Internal/Cursors/Base/XmlContext.cs | 62 + .../Internal/Cursors/Base/XmlContextBase.cs | 287 +++ .../Internal/Cursors/Base/XmlExtensions.cs | 46 + .../Xml/Internal/Cursors/Base/XmlName.cs | 100 ++ .../Internal/Cursors/Base/XmlNameComparer.cs | 52 + .../Xml/Internal/Cursors/Base/XmlNodeBase.cs | 81 + .../Cursors/Base/XmlPositionComparer.cs | 94 + .../Internal/Cursors/Base/XmlSelfCursor.cs | 250 +++ .../Cursors/SystemXml/SysXmlCursor.cs | 566 ++++++ .../Cursors/SystemXml/SysXmlExtensions.cs | 57 + .../Internal/Cursors/SystemXml/SysXmlNode.cs | 298 ++++ .../SystemXml/SysXmlSubtreeIterator.cs | 96 + .../Internal/Cursors/XPath/CompiledXPath.cs | 88 + .../Cursors/XPath/CompiledXPathNode.cs | 136 ++ .../Cursors/XPath/CompiledXPathStep.cs | 44 + .../XPath/XPathBufferedNodeIterator.cs | 83 + .../Internal/Cursors/XPath/XPathCompiler.cs | 452 +++++ .../Internal/Cursors/XPath/XPathContext.cs | 68 + .../Internal/Cursors/XPath/XPathExtensions.cs | 76 + .../Cursors/XPath/XPathMutableCursor.cs | 415 +++++ .../Xml/Internal/Cursors/XPath/XPathNode.cs | 233 +++ .../Cursors/XPath/XPathReadOnlyCursor.cs | 140 ++ .../Xml/Internal/Namespaces/Wsdl.cs | 27 + .../Xml/Internal/Namespaces/XRef.cs | 53 + .../Xml/Internal/Namespaces/Xmlns.cs | 23 + .../Xml/Internal/Namespaces/Xsd.cs | 26 + .../Xml/Internal/Namespaces/Xsi.cs | 75 + .../Serializers/XmlArraySerializer.cs | 102 ++ .../Serializers/XmlCollectionSerializer.cs | 76 + .../Serializers/XmlComponentSerializer.cs | 73 + .../Serializers/XmlCustomSerializer.cs | 60 + .../Serializers/XmlDefaultSerializer.cs | 55 + .../Serializers/XmlDynamicSerializer.cs | 44 + .../Serializers/XmlEnumerationSerializer.cs | 36 + .../Internal/Serializers/XmlListSerializer.cs | 31 + .../Internal/Serializers/XmlSetSerializer.cs | 31 + .../Serializers/XmlSimpleSerializer.cs | 82 + .../Serializers/XmlStringSerializer.cs | 39 + .../Xml/Internal/Serializers/XmlTypeKind.cs | 23 + .../Internal/Serializers/XmlTypeSerializer.cs | 42 + .../Serializers/XmlTypeSerializerCache.cs | 98 ++ .../Serializers/XmlXmlNodeSerializer.cs | 49 + .../Xml/Internal/Types/IXmlIdentity.cs | 22 + .../Xml/Internal/Types/IXmlIncludedType.cs | 24 + .../Xml/Internal/Types/IXmlIncludedTypeMap.cs | 38 + .../Xml/Internal/Types/IXmlKnownType.cs | 23 + .../Xml/Internal/Types/IXmlKnownTypeMap.cs | 38 + .../Xml/Internal/Types/XmlIncludedType.cs | 48 + .../Xml/Internal/Types/XmlIncludedTypeSet.cs | 95 + .../Xml/Internal/Types/XmlKnownType.cs | 61 + .../Xml/Internal/Types/XmlKnownTypeSet.cs | 176 ++ .../Utilities/DictionaryAdapterExtensions.cs | 90 + .../Xml/Internal/Utilities/Error.cs | 219 +++ .../Xml/Internal/Utilities/IConfigurable.cs | 21 + .../Xml/Internal/Utilities/IRealizable.cs | 40 + .../Internal/Utilities/SingletonDispenser.cs | 131 ++ .../Internal/Utilities/StringExtensions.cs | 26 + .../Xml/Internal/Utilities/Try.cs | 35 + .../Xml/Internal/Utilities/TypeExtensions.cs | 54 + .../Internal/Utilities/XmlSubtreeReader.cs | 227 +++ .../Internal/Utilities/XmlSubtreeWriter.cs | 355 ++++ .../Configuration/AbstractConfiguration.cs | 99 ++ .../ConfigurationAttributeCollection.cs | 38 + .../Configuration/ConfigurationCollection.cs | 58 + .../Core/Configuration/IConfiguration.cs | 65 + .../Configuration/MutableConfiguration.cs | 75 + .../Xml/XmlConfigurationDeserializer.cs | 80 + Castle.Core/Core/IServiceEnabledComponent.cs | 34 + Castle.Core/Core/IServiceProviderEx.cs | 26 + .../Core/IServiceProviderExAccessor.cs | 31 + Castle.Core/Core/Internal/AttributesUtil.cs | 146 ++ .../Core/Internal/InterfaceAttributeUtil.cs | 190 ++ Castle.Core/Core/Internal/InternalsVisible.cs | 47 + .../Core/Internal/SynchronizedDictionary.cs | 120 ++ Castle.Core/Core/Internal/TypeExtensions.cs | 37 + Castle.Core/Core/Internal/WeakKey.cs | 45 + Castle.Core/Core/Internal/WeakKeyComparer.cs | 71 + .../Core/Internal/WeakKeyDictionary.cs | 246 +++ .../Logging/AbstractExtendedLoggerFactory.cs | 111 ++ .../Core/Logging/AbstractLoggerFactory.cs | 70 + Castle.Core/Core/Logging/ConsoleFactory.cs | 59 + Castle.Core/Core/Logging/ConsoleLogger.cs | 100 ++ Castle.Core/Core/Logging/DiagnosticsLogger.cs | 146 ++ .../Core/Logging/DiagnosticsLoggerFactory.cs | 38 + .../Core/Logging/IContextProperties.cs | 43 + Castle.Core/Core/Logging/IContextStack.cs | 29 + Castle.Core/Core/Logging/IContextStacks.cs | 21 + Castle.Core/Core/Logging/IExtendedLogger.cs | 39 + .../Core/Logging/IExtendedLoggerFactory.cs | 45 + Castle.Core/Core/Logging/ILogger.cs | 374 ++++ Castle.Core/Core/Logging/ILoggerFactory.cs | 44 + .../Core/Logging/LevelFilteredLogger.cs | 787 +++++++++ Castle.Core/Core/Logging/LoggerException.cs | 39 + Castle.Core/Core/Logging/LoggerLevel.cs | 51 + Castle.Core/Core/Logging/NullLogFactory.cs | 46 + Castle.Core/Core/Logging/NullLogger.cs | 532 ++++++ Castle.Core/Core/Logging/StreamLogger.cs | 160 ++ .../Core/Logging/StreamLoggerFactory.cs | 44 + Castle.Core/Core/Logging/TraceLogger.cs | 227 +++ .../Core/Logging/TraceLoggerFactory.cs | 57 + Castle.Core/Core/ProxyServices.cs | 41 + Castle.Core/Core/ReferenceEqualityComparer.cs | 58 + .../Core/ReflectionBasedDictionaryAdapter.cs | 299 ++++ Castle.Core/Core/Resource/AbstractResource.cs | 46 + .../Core/Resource/AbstractStreamResource.cs | 54 + .../Core/Resource/AssemblyBundleResource.cs | 72 + Castle.Core/Core/Resource/AssemblyResource.cs | 156 ++ .../Core/Resource/AssemblyResourceFactory.cs | 41 + Castle.Core/Core/Resource/ConfigResource.cs | 78 + .../Core/Resource/ConfigResourceFactory.cs | 44 + Castle.Core/Core/Resource/CustomUri.cs | 139 ++ Castle.Core/Core/Resource/FileResource.cs | 119 ++ .../Core/Resource/FileResourceFactory.cs | 46 + Castle.Core/Core/Resource/IResource.cs | 56 + Castle.Core/Core/Resource/IResourceFactory.cs | 48 + .../Core/Resource/ResourceException.cs | 39 + .../Core/Resource/StaticContentResource.cs | 48 + Castle.Core/Core/Resource/UncResource.cs | 102 ++ .../Core/Resource/UncResourceFactory.cs | 40 + Castle.Core/Core/Smtp/DefaultSmtpSender.cs | 250 +++ Castle.Core/Core/Smtp/IEmailSender.cs | 46 + .../Core/StringObjectDictionaryAdapter.cs | 227 +++ .../DynamicProxy/AbstractInvocation.cs | 211 +++ Castle.Core/DynamicProxy/AllMethodsHook.cs | 56 + .../Contributors/ClassMembersCollector.cs | 46 + .../ClassProxySerializableContributor.cs | 247 +++ .../ClassProxyTargetContributor.cs | 180 ++ .../ClassProxyWithTargetTargetContributor.cs | 180 ++ .../Contributors/CompositeTypeContributor.cs | 184 ++ .../DelegateTypeMembersCollector.cs | 42 + .../DynamicProxy/Contributors/Delegates.cs | 28 + .../Contributors/FieldReferenceComparer.cs | 37 + .../IInvocationCreationContributor.cs | 33 + .../Contributors/IMembersCollectorSink.cs | 25 + .../Contributors/ITypeContributor.cs | 29 + .../Contributors/InterfaceMembersCollector.cs | 40 + .../InterfaceMembersOnClassCollector.cs | 68 + .../InterfaceProxySerializableContributor.cs | 54 + .../InterfaceProxyTargetContributor.cs | 101 ++ ...rfaceProxyWithOptionalTargetContributor.cs | 43 + ...oxyWithTargetInterfaceTargetContributor.cs | 34 + .../InterfaceProxyWithoutTargetContributor.cs | 97 + .../InvocationWithDelegateContributor.cs | 107 ++ ...nvocationWithGenericDelegateContributor.cs | 88 + .../Contributors/MembersCollector.cs | 228 +++ .../Contributors/MixinContributor.cs | 153 ++ .../NonInheritableAttributesContributor.cs | 47 + .../ProxyTargetAccessorContributor.cs | 74 + .../Contributors/SerializableContributor.cs | 153 ++ .../WrappedClassMembersCollector.cs | 82 + .../DynamicProxy/CustomAttributeInfo.cs | 347 ++++ .../DynamicProxy/DefaultProxyBuilder.cs | 164 ++ Castle.Core/DynamicProxy/DynProxy.snk | Bin 0 -> 596 bytes .../DynamicProxy/DynamicProxyException.cs | 39 + .../DynamicProxy/ExceptionMessageBuilder.cs | 87 + .../AttributesToAvoidReplicating.cs | 63 + .../Generators/BaseClassProxyGenerator.cs | 219 +++ .../Generators/BaseInterfaceProxyGenerator.cs | 296 ++++ .../Generators/BaseProxyGenerator.cs | 409 +++++ .../DynamicProxy/Generators/CacheKey.cs | 113 ++ .../Generators/ClassProxyGenerator.cs | 58 + .../ClassProxyWithTargetGenerator.cs | 80 + .../CompositionInvocationTypeGenerator.cs | 71 + .../Generators/DelegateTypeGenerator.cs | 109 ++ .../Emitters/AbstractTypeEmitter.cs | 374 ++++ .../Generators/Emitters/ArgumentsUtil.cs | 105 ++ .../Generators/Emitters/ClassEmitter.cs | 109 ++ .../Generators/Emitters/CodeBuilder.cs | 68 + .../Generators/Emitters/ConstructorEmitter.cs | 94 + .../Generators/Emitters/EventEmitter.cs | 99 ++ .../Generators/Emitters/GenericUtil.cs | 160 ++ .../Generators/Emitters/IMemberEmitter.cs | 30 + .../Emitters/LdcOpCodesDictionary.cs | 69 + .../Emitters/LdindOpCodesDictionary.cs | 70 + .../Generators/Emitters/MethodEmitter.cs | 350 ++++ .../Generators/Emitters/NestedClassEmitter.cs | 52 + .../Generators/Emitters/OpCodeUtil.cs | 178 ++ .../Generators/Emitters/PropertyEmitter.cs | 116 ++ .../Emitters/SimpleAST/ArgumentReference.cs | 78 + .../Emitters/SimpleAST/AsTypeReference.cs | 63 + .../SimpleAST/AssignArgumentStatement.cs | 36 + .../SimpleAST/AssignArrayStatement.cs | 43 + .../Emitters/SimpleAST/AssignStatement.cs | 37 + .../Emitters/SimpleAST/BlockStatement.cs | 37 + .../Emitters/SimpleAST/ByRefReference.cs | 48 + .../ConstructorInvocationStatement.cs | 71 + .../Emitters/SimpleAST/ConvertExpression.cs | 116 ++ .../SimpleAST/DefaultValueExpression.cs | 84 + .../SimpleAST/EndExceptionBlockStatement.cs | 26 + .../Emitters/SimpleAST/FieldReference.cs | 95 + .../Emitters/SimpleAST/FinallyStatement.cs | 26 + .../Emitters/SimpleAST/IExpression.cs | 20 + .../SimpleAST/IExpressionOrStatement.cs | 23 + .../Emitters/SimpleAST/IStatement.cs | 20 + .../Emitters/SimpleAST/IfNullExpression.cs | 62 + .../Emitters/SimpleAST/IndirectReference.cs | 73 + .../SimpleAST/LiteralBoolExpression.cs | 33 + .../SimpleAST/LiteralIntExpression.cs | 68 + .../SimpleAST/LiteralStringExpression.cs | 33 + .../LoadRefArrayElementExpression.cs | 37 + .../Emitters/SimpleAST/LocalReference.cs | 50 + .../SimpleAST/MethodInvocationExpression.cs | 69 + .../SimpleAST/MethodTokenExpression.cs | 43 + .../Emitters/SimpleAST/NewArrayExpression.cs | 37 + .../SimpleAST/NewInstanceExpression.cs | 51 + .../NullCoalescingOperatorExpression.cs | 52 + .../Emitters/SimpleAST/NullExpression.cs | 32 + .../Emitters/SimpleAST/Reference.cs | 53 + .../ReferencesToObjectArrayExpression.cs | 67 + .../Emitters/SimpleAST/ReturnStatement.cs | 52 + .../Emitters/SimpleAST/SelfReference.cs | 45 + .../Emitters/SimpleAST/ThrowStatement.cs | 44 + .../Emitters/SimpleAST/TryStatement.cs | 26 + .../Emitters/SimpleAST/TypeReference.cs | 37 + .../Emitters/SimpleAST/TypeTokenExpression.cs | 37 + .../Emitters/StindOpCodesDictionary.cs | 70 + .../Generators/Emitters/StrongNameUtil.cs | 61 + .../Emitters/TypeConstructorEmitter.cs | 34 + .../Generators/ForwardingMethodGenerator.cs | 46 + .../DynamicProxy/Generators/GeneratorUtil.cs | 131 ++ .../DynamicProxy/Generators/IGenerator.cs | 23 + .../DynamicProxy/Generators/INamingScope.cs | 45 + .../InheritanceInvocationTypeGenerator.cs | 59 + .../InterfaceProxyWithTargetGenerator.cs | 68 + ...erfaceProxyWithTargetInterfaceGenerator.cs | 74 + .../InterfaceProxyWithoutTargetGenerator.cs | 59 + .../Generators/InvocationTypeGenerator.cs | 311 ++++ .../DynamicProxy/Generators/MetaEvent.cs | 151 ++ .../DynamicProxy/Generators/MetaMethod.cs | 143 ++ .../DynamicProxy/Generators/MetaProperty.cs | 199 +++ .../DynamicProxy/Generators/MetaType.cs | 64 + .../Generators/MetaTypeElement.cs | 99 ++ .../Generators/MetaTypeElementCollection.cs | 68 + .../DynamicProxy/Generators/MethodFinder.cs | 83 + .../Generators/MethodGenerator.cs | 59 + .../Generators/MethodSignatureComparer.cs | 159 ++ .../MethodWithInvocationGenerator.cs | 251 +++ .../MinimialisticMethodGenerator.cs | 61 + .../DynamicProxy/Generators/NamingScope.cs | 61 + .../OptionallyForwardingMethodGenerator.cs | 93 + .../DynamicProxy/IChangeProxyTarget.cs | 59 + Castle.Core/DynamicProxy/IInterceptor.cs | 24 + .../DynamicProxy/IInterceptorSelector.cs | 42 + Castle.Core/DynamicProxy/IInvocation.cs | 135 ++ .../DynamicProxy/IInvocationProceedInfo.cs | 31 + Castle.Core/DynamicProxy/IProxyBuilder.cs | 137 ++ .../DynamicProxy/IProxyGenerationHook.cs | 50 + Castle.Core/DynamicProxy/IProxyGenerator.cs | 1033 +++++++++++ .../DynamicProxy/IProxyTargetAccessor.cs | 39 + .../DynamicProxy/Internal/AttributeUtil.cs | 251 +++ .../Internal/CompositionInvocation.cs | 86 + .../Internal/InheritanceInvocation.cs | 52 + .../InterfaceMethodWithoutTargetInvocation.cs | 61 + .../DynamicProxy/Internal/InvocationHelper.cs | 132 ++ Castle.Core/DynamicProxy/Internal/TypeUtil.cs | 225 +++ Castle.Core/DynamicProxy/MixinData.cs | 210 +++ Castle.Core/DynamicProxy/ModuleScope.cs | 539 ++++++ .../DynamicProxy/PersistentProxyBuilder.cs | 49 + .../DynamicProxy/ProxyGenerationOptions.cs | 353 ++++ Castle.Core/DynamicProxy/ProxyGenerator.cs | 1564 +++++++++++++++++ Castle.Core/DynamicProxy/ProxyUtil.cs | 236 +++ .../Serialization/CacheMappingsAttribute.cs | 73 + .../Serialization/ProxyObjectReference.cs | 294 ++++ .../Serialization/ProxyTypeConstants.cs | 25 + .../DynamicProxy/StandardInterceptor.cs | 44 + .../DynamicProxy/Tokens/DelegateMethods.cs | 25 + .../Tokens/FormatterServicesMethods.cs | 33 + .../Tokens/InterceptorSelectorMethods.cs | 23 + .../DynamicProxy/Tokens/InvocationMethods.cs | 103 ++ .../DynamicProxy/Tokens/MethodBaseMethods.cs | 25 + .../Tokens/SerializationInfoMethods.cs | 60 + .../DynamicProxy/Tokens/TypeMethods.cs | 26 + .../DynamicProxy/Tokens/TypeUtilMethods.cs | 26 + .../Properties/InternalsVisibleToTests.cs | 17 + SimpleProxy.sln | 61 +- SimpleProxy/SimpleProxy.csproj | 9 +- 411 files changed, 42523 insertions(+), 48 deletions(-) create mode 100644 Castle.Core.AsyncInterceptor/AsyncDeterminationInterceptor.cs create mode 100644 Castle.Core.AsyncInterceptor/AsyncInterceptorBase.cs create mode 100644 Castle.Core.AsyncInterceptor/AsyncTimingInterceptor.cs create mode 100644 Castle.Core.AsyncInterceptor/Castle.Core.AsyncInterceptor.csproj create mode 100644 Castle.Core.AsyncInterceptor/IAsyncInterceptor.cs create mode 100644 Castle.Core.AsyncInterceptor/NoCoverage/RethrowHelper.cs create mode 100644 Castle.Core.AsyncInterceptor/ProcessingAsyncInterceptor.cs create mode 100644 Castle.Core.AsyncInterceptor/Properties/AssemblyInfo.cs create mode 100644 Castle.Core.AsyncInterceptor/ProxyGeneratorExtensions.cs create mode 100644 Castle.Core.AsyncInterceptor/SharedKey.snk create mode 100644 Castle.Core/Castle.Core.csproj create mode 100644 Castle.Core/Components.DictionaryAdapter/AbstractDictionaryAdapter.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/AbstractDictionaryAdapterVisitor.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Attributes/ComponentAttribute.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Attributes/DictionaryAdapterAttribute.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Attributes/DictionaryBehaviorAttribute.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Attributes/FetchAttribute.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Attributes/GroupAttribute.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Attributes/IfExistsAttribute.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Attributes/KeyAttribute.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Attributes/KeyPrefixAttribute.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Attributes/KeySubstitutionAttribute.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Attributes/MultiLevelEditAttribute.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Attributes/NewGuidAttribute.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Attributes/OnDemandAttribute.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Attributes/ReferenceAttribute.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Attributes/RemoveIfAttribute.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Attributes/RemoveIfEmptyAttribute.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Attributes/StringFormatAttribute.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Attributes/StringListAttribute.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Attributes/StringStorageAttribute.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Attributes/StringValuesAttribute.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Attributes/SuppressNotificationsAttribute.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Attributes/TypeKeyPrefixAttribute.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Attributes/VolatileAttribute.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Attributes/XPathAttribute.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Attributes/XPathFunctionAttribute.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Attributes/XPathVariableAttribute.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Attributes/XmlDefaultsAttribute.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Attributes/XmlNamespaceAttribute.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/CascadingDictionaryAdapter.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/DefaultPropertyGetter.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/DictionaryAdapterBase.Coerce.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/DictionaryAdapterBase.Copy.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/DictionaryAdapterBase.Create.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/DictionaryAdapterBase.Edit.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/DictionaryAdapterBase.Notify.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/DictionaryAdapterBase.Validate.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/DictionaryAdapterBase.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/DictionaryAdapterExtensions.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/DictionaryAdapterFactory.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/DictionaryAdapterInstance.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/DictionaryAdapterMeta.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/DictionaryValidateGroup.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/DynamicDictionary.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/GenericDictionaryAdapter.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/IDictionaryAdapter.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/IDictionaryAdapterFactory.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/IDictionaryAdapterVisitor.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/IDictionaryBehavior.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/IDictionaryBehaviorBuilder.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/IDictionaryCoerceStrategy.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/IDictionaryCopyStrategy.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/IDictionaryCreate.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/IDictionaryCreateStrategy.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/IDictionaryEdit.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/IDictionaryEqualityHashCodeStrategy.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/IDictionaryInitializer.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/IDictionaryKeyBuilder.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/IDictionaryMetaInitializer.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/IDictionaryNotify.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/IDictionaryPropertyGetter.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/IDictionaryPropertySetter.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/IDictionaryReferenceManager.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/IDictionaryValidate.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/IDictionaryValidator.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/IPropertyDescriptorInitializer.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/MemberwiseEqualityHashCodeStrategy.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/NameValueCollectionAdapter.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/PropertyChangedEventArgsEx.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/PropertyChangingEventArgsEx.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/PropertyDescriptor.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Util/BindingList.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Util/BindingListInitializer.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Util/DynamicValue.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Util/DynamicValueDelegate.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Util/EditableBindingList.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Util/EditableList.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Util/IBindingList.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Util/IBindingListSource.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Util/ICollectionAdapter.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Util/ICollectionAdapterObserver.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Util/ICollectionProjection.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Util/ICondition.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Util/IDynamicValue.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Util/IValueInitializer.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Util/IVirtual.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Util/IVirtualSite.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Util/IVirtualTarget.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Util/ListProjection.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Util/ListProjectionDebugView.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Util/SetProjection.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Util/VirtualObject.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Util/VirtualSite.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Core/DefaultXmlReferenceFormat.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Core/IXmlReferenceFormat.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Core/XmlAdapter.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Core/XmlMetadata.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Core/XmlMetadataBehavior.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Core/XmlReferenceManager.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/IXmlAccessor.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/IXmlBehaviorSemantics.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/IXmlCollectionAccessor.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/IXmlPropertyAccessor.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XPathBehaviorAccessor.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlAccessor.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlAccessorFactory.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlArrayBehaviorAccessor.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlAttributeBehaviorAccessor.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlDefaultBehaviorAccessor.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlElementBehaviorAccessor.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlIgnoreBehaviorAccessor.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlNodeAccessor.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlSelfAccessor.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Collections/XmlCollectionAdapter.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Collections/XmlCollectionItem.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Collections/XmlNodeList.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Collections/XmlNodeSet.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/CursorFlags.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/IXmlContext.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/IXmlCursor.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/IXmlIterator.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/IXmlNamespaceSource.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/IXmlNode.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/IXmlNodeSource.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/XmlContext.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/XmlContextBase.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/XmlExtensions.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/XmlName.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/XmlNameComparer.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/XmlNodeBase.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/XmlPositionComparer.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/XmlSelfCursor.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/SystemXml/SysXmlCursor.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/SystemXml/SysXmlExtensions.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/SystemXml/SysXmlNode.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/SystemXml/SysXmlSubtreeIterator.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/CompiledXPath.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/CompiledXPathNode.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/CompiledXPathStep.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/XPathBufferedNodeIterator.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/XPathCompiler.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/XPathContext.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/XPathExtensions.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/XPathMutableCursor.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/XPathNode.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/XPathReadOnlyCursor.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Namespaces/Wsdl.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Namespaces/XRef.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Namespaces/Xmlns.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Namespaces/Xsd.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Namespaces/Xsi.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlArraySerializer.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlCollectionSerializer.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlComponentSerializer.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlCustomSerializer.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlDefaultSerializer.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlDynamicSerializer.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlEnumerationSerializer.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlListSerializer.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlSetSerializer.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlSimpleSerializer.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlStringSerializer.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlTypeKind.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlTypeSerializer.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlTypeSerializerCache.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlXmlNodeSerializer.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/IXmlIdentity.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/IXmlIncludedType.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/IXmlIncludedTypeMap.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/IXmlKnownType.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/IXmlKnownTypeMap.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/XmlIncludedType.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/XmlIncludedTypeSet.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/XmlKnownType.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/XmlKnownTypeSet.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/DictionaryAdapterExtensions.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/Error.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/IConfigurable.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/IRealizable.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/SingletonDispenser.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/StringExtensions.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/Try.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/TypeExtensions.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/XmlSubtreeReader.cs create mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/XmlSubtreeWriter.cs create mode 100644 Castle.Core/Core/Configuration/AbstractConfiguration.cs create mode 100644 Castle.Core/Core/Configuration/ConfigurationAttributeCollection.cs create mode 100644 Castle.Core/Core/Configuration/ConfigurationCollection.cs create mode 100644 Castle.Core/Core/Configuration/IConfiguration.cs create mode 100644 Castle.Core/Core/Configuration/MutableConfiguration.cs create mode 100644 Castle.Core/Core/Configuration/Xml/XmlConfigurationDeserializer.cs create mode 100644 Castle.Core/Core/IServiceEnabledComponent.cs create mode 100644 Castle.Core/Core/IServiceProviderEx.cs create mode 100644 Castle.Core/Core/IServiceProviderExAccessor.cs create mode 100644 Castle.Core/Core/Internal/AttributesUtil.cs create mode 100644 Castle.Core/Core/Internal/InterfaceAttributeUtil.cs create mode 100644 Castle.Core/Core/Internal/InternalsVisible.cs create mode 100644 Castle.Core/Core/Internal/SynchronizedDictionary.cs create mode 100644 Castle.Core/Core/Internal/TypeExtensions.cs create mode 100644 Castle.Core/Core/Internal/WeakKey.cs create mode 100644 Castle.Core/Core/Internal/WeakKeyComparer.cs create mode 100644 Castle.Core/Core/Internal/WeakKeyDictionary.cs create mode 100644 Castle.Core/Core/Logging/AbstractExtendedLoggerFactory.cs create mode 100644 Castle.Core/Core/Logging/AbstractLoggerFactory.cs create mode 100644 Castle.Core/Core/Logging/ConsoleFactory.cs create mode 100644 Castle.Core/Core/Logging/ConsoleLogger.cs create mode 100644 Castle.Core/Core/Logging/DiagnosticsLogger.cs create mode 100644 Castle.Core/Core/Logging/DiagnosticsLoggerFactory.cs create mode 100644 Castle.Core/Core/Logging/IContextProperties.cs create mode 100644 Castle.Core/Core/Logging/IContextStack.cs create mode 100644 Castle.Core/Core/Logging/IContextStacks.cs create mode 100644 Castle.Core/Core/Logging/IExtendedLogger.cs create mode 100644 Castle.Core/Core/Logging/IExtendedLoggerFactory.cs create mode 100644 Castle.Core/Core/Logging/ILogger.cs create mode 100644 Castle.Core/Core/Logging/ILoggerFactory.cs create mode 100644 Castle.Core/Core/Logging/LevelFilteredLogger.cs create mode 100644 Castle.Core/Core/Logging/LoggerException.cs create mode 100644 Castle.Core/Core/Logging/LoggerLevel.cs create mode 100644 Castle.Core/Core/Logging/NullLogFactory.cs create mode 100644 Castle.Core/Core/Logging/NullLogger.cs create mode 100644 Castle.Core/Core/Logging/StreamLogger.cs create mode 100644 Castle.Core/Core/Logging/StreamLoggerFactory.cs create mode 100644 Castle.Core/Core/Logging/TraceLogger.cs create mode 100644 Castle.Core/Core/Logging/TraceLoggerFactory.cs create mode 100644 Castle.Core/Core/ProxyServices.cs create mode 100644 Castle.Core/Core/ReferenceEqualityComparer.cs create mode 100644 Castle.Core/Core/ReflectionBasedDictionaryAdapter.cs create mode 100644 Castle.Core/Core/Resource/AbstractResource.cs create mode 100644 Castle.Core/Core/Resource/AbstractStreamResource.cs create mode 100644 Castle.Core/Core/Resource/AssemblyBundleResource.cs create mode 100644 Castle.Core/Core/Resource/AssemblyResource.cs create mode 100644 Castle.Core/Core/Resource/AssemblyResourceFactory.cs create mode 100644 Castle.Core/Core/Resource/ConfigResource.cs create mode 100644 Castle.Core/Core/Resource/ConfigResourceFactory.cs create mode 100644 Castle.Core/Core/Resource/CustomUri.cs create mode 100644 Castle.Core/Core/Resource/FileResource.cs create mode 100644 Castle.Core/Core/Resource/FileResourceFactory.cs create mode 100644 Castle.Core/Core/Resource/IResource.cs create mode 100644 Castle.Core/Core/Resource/IResourceFactory.cs create mode 100644 Castle.Core/Core/Resource/ResourceException.cs create mode 100644 Castle.Core/Core/Resource/StaticContentResource.cs create mode 100644 Castle.Core/Core/Resource/UncResource.cs create mode 100644 Castle.Core/Core/Resource/UncResourceFactory.cs create mode 100644 Castle.Core/Core/Smtp/DefaultSmtpSender.cs create mode 100644 Castle.Core/Core/Smtp/IEmailSender.cs create mode 100644 Castle.Core/Core/StringObjectDictionaryAdapter.cs create mode 100644 Castle.Core/DynamicProxy/AbstractInvocation.cs create mode 100644 Castle.Core/DynamicProxy/AllMethodsHook.cs create mode 100644 Castle.Core/DynamicProxy/Contributors/ClassMembersCollector.cs create mode 100644 Castle.Core/DynamicProxy/Contributors/ClassProxySerializableContributor.cs create mode 100644 Castle.Core/DynamicProxy/Contributors/ClassProxyTargetContributor.cs create mode 100644 Castle.Core/DynamicProxy/Contributors/ClassProxyWithTargetTargetContributor.cs create mode 100644 Castle.Core/DynamicProxy/Contributors/CompositeTypeContributor.cs create mode 100644 Castle.Core/DynamicProxy/Contributors/DelegateTypeMembersCollector.cs create mode 100644 Castle.Core/DynamicProxy/Contributors/Delegates.cs create mode 100644 Castle.Core/DynamicProxy/Contributors/FieldReferenceComparer.cs create mode 100644 Castle.Core/DynamicProxy/Contributors/IInvocationCreationContributor.cs create mode 100644 Castle.Core/DynamicProxy/Contributors/IMembersCollectorSink.cs create mode 100644 Castle.Core/DynamicProxy/Contributors/ITypeContributor.cs create mode 100644 Castle.Core/DynamicProxy/Contributors/InterfaceMembersCollector.cs create mode 100644 Castle.Core/DynamicProxy/Contributors/InterfaceMembersOnClassCollector.cs create mode 100644 Castle.Core/DynamicProxy/Contributors/InterfaceProxySerializableContributor.cs create mode 100644 Castle.Core/DynamicProxy/Contributors/InterfaceProxyTargetContributor.cs create mode 100644 Castle.Core/DynamicProxy/Contributors/InterfaceProxyWithOptionalTargetContributor.cs create mode 100644 Castle.Core/DynamicProxy/Contributors/InterfaceProxyWithTargetInterfaceTargetContributor.cs create mode 100644 Castle.Core/DynamicProxy/Contributors/InterfaceProxyWithoutTargetContributor.cs create mode 100644 Castle.Core/DynamicProxy/Contributors/InvocationWithDelegateContributor.cs create mode 100644 Castle.Core/DynamicProxy/Contributors/InvocationWithGenericDelegateContributor.cs create mode 100644 Castle.Core/DynamicProxy/Contributors/MembersCollector.cs create mode 100644 Castle.Core/DynamicProxy/Contributors/MixinContributor.cs create mode 100644 Castle.Core/DynamicProxy/Contributors/NonInheritableAttributesContributor.cs create mode 100644 Castle.Core/DynamicProxy/Contributors/ProxyTargetAccessorContributor.cs create mode 100644 Castle.Core/DynamicProxy/Contributors/SerializableContributor.cs create mode 100644 Castle.Core/DynamicProxy/Contributors/WrappedClassMembersCollector.cs create mode 100644 Castle.Core/DynamicProxy/CustomAttributeInfo.cs create mode 100644 Castle.Core/DynamicProxy/DefaultProxyBuilder.cs create mode 100644 Castle.Core/DynamicProxy/DynProxy.snk create mode 100644 Castle.Core/DynamicProxy/DynamicProxyException.cs create mode 100644 Castle.Core/DynamicProxy/ExceptionMessageBuilder.cs create mode 100644 Castle.Core/DynamicProxy/Generators/AttributesToAvoidReplicating.cs create mode 100644 Castle.Core/DynamicProxy/Generators/BaseClassProxyGenerator.cs create mode 100644 Castle.Core/DynamicProxy/Generators/BaseInterfaceProxyGenerator.cs create mode 100644 Castle.Core/DynamicProxy/Generators/BaseProxyGenerator.cs create mode 100644 Castle.Core/DynamicProxy/Generators/CacheKey.cs create mode 100644 Castle.Core/DynamicProxy/Generators/ClassProxyGenerator.cs create mode 100644 Castle.Core/DynamicProxy/Generators/ClassProxyWithTargetGenerator.cs create mode 100644 Castle.Core/DynamicProxy/Generators/CompositionInvocationTypeGenerator.cs create mode 100644 Castle.Core/DynamicProxy/Generators/DelegateTypeGenerator.cs create mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/AbstractTypeEmitter.cs create mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/ArgumentsUtil.cs create mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/ClassEmitter.cs create mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/CodeBuilder.cs create mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/ConstructorEmitter.cs create mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/EventEmitter.cs create mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/GenericUtil.cs create mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/IMemberEmitter.cs create mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/LdcOpCodesDictionary.cs create mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/LdindOpCodesDictionary.cs create mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/MethodEmitter.cs create mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/NestedClassEmitter.cs create mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/OpCodeUtil.cs create mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/PropertyEmitter.cs create mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ArgumentReference.cs create mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/AsTypeReference.cs create mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/AssignArgumentStatement.cs create mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/AssignArrayStatement.cs create mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/AssignStatement.cs create mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/BlockStatement.cs create mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ByRefReference.cs create mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ConstructorInvocationStatement.cs create mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ConvertExpression.cs create mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/DefaultValueExpression.cs create mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/EndExceptionBlockStatement.cs create mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/FieldReference.cs create mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/FinallyStatement.cs create mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/IExpression.cs create mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/IExpressionOrStatement.cs create mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/IStatement.cs create mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/IfNullExpression.cs create mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/IndirectReference.cs create mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/LiteralBoolExpression.cs create mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/LiteralIntExpression.cs create mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/LiteralStringExpression.cs create mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/LoadRefArrayElementExpression.cs create mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/LocalReference.cs create mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/MethodInvocationExpression.cs create mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/MethodTokenExpression.cs create mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/NewArrayExpression.cs create mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/NewInstanceExpression.cs create mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/NullCoalescingOperatorExpression.cs create mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/NullExpression.cs create mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/Reference.cs create mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ReferencesToObjectArrayExpression.cs create mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ReturnStatement.cs create mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/SelfReference.cs create mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ThrowStatement.cs create mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/TryStatement.cs create mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/TypeReference.cs create mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/TypeTokenExpression.cs create mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/StindOpCodesDictionary.cs create mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/StrongNameUtil.cs create mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/TypeConstructorEmitter.cs create mode 100644 Castle.Core/DynamicProxy/Generators/ForwardingMethodGenerator.cs create mode 100644 Castle.Core/DynamicProxy/Generators/GeneratorUtil.cs create mode 100644 Castle.Core/DynamicProxy/Generators/IGenerator.cs create mode 100644 Castle.Core/DynamicProxy/Generators/INamingScope.cs create mode 100644 Castle.Core/DynamicProxy/Generators/InheritanceInvocationTypeGenerator.cs create mode 100644 Castle.Core/DynamicProxy/Generators/InterfaceProxyWithTargetGenerator.cs create mode 100644 Castle.Core/DynamicProxy/Generators/InterfaceProxyWithTargetInterfaceGenerator.cs create mode 100644 Castle.Core/DynamicProxy/Generators/InterfaceProxyWithoutTargetGenerator.cs create mode 100644 Castle.Core/DynamicProxy/Generators/InvocationTypeGenerator.cs create mode 100644 Castle.Core/DynamicProxy/Generators/MetaEvent.cs create mode 100644 Castle.Core/DynamicProxy/Generators/MetaMethod.cs create mode 100644 Castle.Core/DynamicProxy/Generators/MetaProperty.cs create mode 100644 Castle.Core/DynamicProxy/Generators/MetaType.cs create mode 100644 Castle.Core/DynamicProxy/Generators/MetaTypeElement.cs create mode 100644 Castle.Core/DynamicProxy/Generators/MetaTypeElementCollection.cs create mode 100644 Castle.Core/DynamicProxy/Generators/MethodFinder.cs create mode 100644 Castle.Core/DynamicProxy/Generators/MethodGenerator.cs create mode 100644 Castle.Core/DynamicProxy/Generators/MethodSignatureComparer.cs create mode 100644 Castle.Core/DynamicProxy/Generators/MethodWithInvocationGenerator.cs create mode 100644 Castle.Core/DynamicProxy/Generators/MinimialisticMethodGenerator.cs create mode 100644 Castle.Core/DynamicProxy/Generators/NamingScope.cs create mode 100644 Castle.Core/DynamicProxy/Generators/OptionallyForwardingMethodGenerator.cs create mode 100644 Castle.Core/DynamicProxy/IChangeProxyTarget.cs create mode 100644 Castle.Core/DynamicProxy/IInterceptor.cs create mode 100644 Castle.Core/DynamicProxy/IInterceptorSelector.cs create mode 100644 Castle.Core/DynamicProxy/IInvocation.cs create mode 100644 Castle.Core/DynamicProxy/IInvocationProceedInfo.cs create mode 100644 Castle.Core/DynamicProxy/IProxyBuilder.cs create mode 100644 Castle.Core/DynamicProxy/IProxyGenerationHook.cs create mode 100644 Castle.Core/DynamicProxy/IProxyGenerator.cs create mode 100644 Castle.Core/DynamicProxy/IProxyTargetAccessor.cs create mode 100644 Castle.Core/DynamicProxy/Internal/AttributeUtil.cs create mode 100644 Castle.Core/DynamicProxy/Internal/CompositionInvocation.cs create mode 100644 Castle.Core/DynamicProxy/Internal/InheritanceInvocation.cs create mode 100644 Castle.Core/DynamicProxy/Internal/InterfaceMethodWithoutTargetInvocation.cs create mode 100644 Castle.Core/DynamicProxy/Internal/InvocationHelper.cs create mode 100644 Castle.Core/DynamicProxy/Internal/TypeUtil.cs create mode 100644 Castle.Core/DynamicProxy/MixinData.cs create mode 100644 Castle.Core/DynamicProxy/ModuleScope.cs create mode 100644 Castle.Core/DynamicProxy/PersistentProxyBuilder.cs create mode 100644 Castle.Core/DynamicProxy/ProxyGenerationOptions.cs create mode 100644 Castle.Core/DynamicProxy/ProxyGenerator.cs create mode 100644 Castle.Core/DynamicProxy/ProxyUtil.cs create mode 100644 Castle.Core/DynamicProxy/Serialization/CacheMappingsAttribute.cs create mode 100644 Castle.Core/DynamicProxy/Serialization/ProxyObjectReference.cs create mode 100644 Castle.Core/DynamicProxy/Serialization/ProxyTypeConstants.cs create mode 100644 Castle.Core/DynamicProxy/StandardInterceptor.cs create mode 100644 Castle.Core/DynamicProxy/Tokens/DelegateMethods.cs create mode 100644 Castle.Core/DynamicProxy/Tokens/FormatterServicesMethods.cs create mode 100644 Castle.Core/DynamicProxy/Tokens/InterceptorSelectorMethods.cs create mode 100644 Castle.Core/DynamicProxy/Tokens/InvocationMethods.cs create mode 100644 Castle.Core/DynamicProxy/Tokens/MethodBaseMethods.cs create mode 100644 Castle.Core/DynamicProxy/Tokens/SerializationInfoMethods.cs create mode 100644 Castle.Core/DynamicProxy/Tokens/TypeMethods.cs create mode 100644 Castle.Core/DynamicProxy/Tokens/TypeUtilMethods.cs create mode 100644 Castle.Core/Properties/InternalsVisibleToTests.cs diff --git a/Castle.Core.AsyncInterceptor/AsyncDeterminationInterceptor.cs b/Castle.Core.AsyncInterceptor/AsyncDeterminationInterceptor.cs new file mode 100644 index 0000000..6323070 --- /dev/null +++ b/Castle.Core.AsyncInterceptor/AsyncDeterminationInterceptor.cs @@ -0,0 +1,115 @@ +// Copyright (c) 2016-2021 James Skimming. All rights reserved. +// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. + +namespace Castle.DynamicProxy +{ + using System; + using System.Collections.Concurrent; + using System.Collections.Generic; + using System.Diagnostics; + using System.Linq; + using System.Reflection; + using System.Threading.Tasks; + + /// + /// Intercepts method invocations and determines if is an asynchronous method. + /// + public class AsyncDeterminationInterceptor : IInterceptor + { + private static readonly MethodInfo HandleAsyncMethodInfo = + typeof(AsyncDeterminationInterceptor) + .GetMethod(nameof(HandleAsyncWithResult), BindingFlags.Static | BindingFlags.NonPublic)!; + + private static readonly ConcurrentDictionary GenericAsyncHandlers = + new ConcurrentDictionary(); + + /// + /// Initializes a new instance of the class. + /// + /// The underlying . + public AsyncDeterminationInterceptor(IAsyncInterceptor asyncInterceptor) + { + AsyncInterceptor = asyncInterceptor; + } + + private delegate void GenericAsyncHandler(IInvocation invocation, IAsyncInterceptor asyncInterceptor); + + private enum MethodType + { + Synchronous, + AsyncAction, + AsyncFunction, + } + + /// + /// Gets the underlying async interceptor. + /// + public IAsyncInterceptor AsyncInterceptor { get; } + + /// + /// Intercepts a method . + /// + /// The method invocation. + [DebuggerStepThrough] + public virtual void Intercept(IInvocation invocation) + { + MethodType methodType = GetMethodType(invocation.Method.ReturnType); + + switch (methodType) + { + case MethodType.AsyncAction: + AsyncInterceptor.InterceptAsynchronous(invocation); + return; + case MethodType.AsyncFunction: + GetHandler(invocation.Method.ReturnType).Invoke(invocation, AsyncInterceptor); + return; + default: + AsyncInterceptor.InterceptSynchronous(invocation); + return; + } + } + + /// + /// Gets the based upon the of the method invocation. + /// + private static MethodType GetMethodType(Type returnType) + { + // If there's no return type, or it's not a task, then assume it's a synchronous method. + if (returnType == typeof(void) || !typeof(Task).IsAssignableFrom(returnType)) + return MethodType.Synchronous; + + // The return type is a task of some sort, so assume it's asynchronous + return returnType.GetTypeInfo().IsGenericType ? MethodType.AsyncFunction : MethodType.AsyncAction; + } + + /// + /// Gets the for the method invocation . + /// + private static GenericAsyncHandler GetHandler(Type returnType) + { + GenericAsyncHandler handler = GenericAsyncHandlers.GetOrAdd(returnType, CreateHandler); + return handler; + } + + /// + /// Creates the generic delegate for the method invocation. + /// + private static GenericAsyncHandler CreateHandler(Type returnType) + { + Type taskReturnType = returnType.GetGenericArguments()[0]; + MethodInfo method = HandleAsyncMethodInfo.MakeGenericMethod(taskReturnType); + return (GenericAsyncHandler)method.CreateDelegate(typeof(GenericAsyncHandler)); + } + + /// + /// This method is created as a delegate and used to make the call to the generic + /// method. + /// + /// The type of the of the method + /// . + private static void HandleAsyncWithResult(IInvocation invocation, IAsyncInterceptor asyncInterceptor) + { + asyncInterceptor.InterceptAsynchronous(invocation); + } + } +} diff --git a/Castle.Core.AsyncInterceptor/AsyncInterceptorBase.cs b/Castle.Core.AsyncInterceptor/AsyncInterceptorBase.cs new file mode 100644 index 0000000..33c9735 --- /dev/null +++ b/Castle.Core.AsyncInterceptor/AsyncInterceptorBase.cs @@ -0,0 +1,205 @@ +// Copyright (c) 2016-2021 James Skimming. All rights reserved. +// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. + +namespace Castle.DynamicProxy +{ + using System; + using System.Collections.Concurrent; + using System.Diagnostics.CodeAnalysis; + using System.Reflection; + using System.Threading.Tasks; + using Castle.DynamicProxy.NoCoverage; + + /// + /// A base type for an to provided a simplified solution of method + /// by enforcing only two types of interception, both asynchronous. + /// + [SuppressMessage( + "Design", + "CA1031:Do not catch general exception types", + Justification = "Must propagate the same exceptions.")] + public abstract class AsyncInterceptorBase : IAsyncInterceptor + { +#if !NETSTANDARD2_0 && !NET5_0 + /// + /// A completed . + /// + private static readonly Task CompletedTask = Task.FromResult(0); +#endif + + private static readonly MethodInfo InterceptSynchronousMethodInfo = + typeof(AsyncInterceptorBase).GetMethod( + nameof(InterceptSynchronousResult), BindingFlags.Static | BindingFlags.NonPublic)!; + + private static readonly ConcurrentDictionary GenericSynchronousHandlers = + new ConcurrentDictionary + { + [typeof(void)] = InterceptSynchronousVoid, + }; + + private delegate void GenericSynchronousHandler(AsyncInterceptorBase me, IInvocation invocation); + + /// + /// Intercepts a synchronous method . + /// + /// The method invocation. + public void InterceptSynchronous(IInvocation invocation) + { + Type returnType = invocation.Method.ReturnType; + GenericSynchronousHandler handler = GenericSynchronousHandlers.GetOrAdd(returnType, CreateHandler); + handler(this, invocation); + } + + /// + /// Intercepts an asynchronous method with return type of . + /// + /// The method invocation. + public void InterceptAsynchronous(IInvocation invocation) + { + invocation.ReturnValue = InterceptAsync(invocation, invocation.CaptureProceedInfo(), ProceedAsynchronous); + } + + /// + /// Intercepts an asynchronous method with return type of . + /// + /// The type of the . + /// The method invocation. + public void InterceptAsynchronous(IInvocation invocation) + { + invocation.ReturnValue = + InterceptAsync(invocation, invocation.CaptureProceedInfo(), ProceedAsynchronous); + } + + /// + /// Override in derived classes to intercept method invocations. + /// + /// The method invocation. + /// The . + /// The function to proceed the . + /// A object that represents the asynchronous operation. + protected abstract Task InterceptAsync( + IInvocation invocation, + IInvocationProceedInfo proceedInfo, + Func proceed); + + /// + /// Override in derived classes to intercept method invocations. + /// + /// The type of the . + /// The method invocation. + /// The . + /// The function to proceed the . + /// A object that represents the asynchronous operation. + protected abstract Task InterceptAsync( + IInvocation invocation, + IInvocationProceedInfo proceedInfo, + Func> proceed); + + private static GenericSynchronousHandler CreateHandler(Type returnType) + { + MethodInfo method = InterceptSynchronousMethodInfo.MakeGenericMethod(returnType); + return (GenericSynchronousHandler)method.CreateDelegate(typeof(GenericSynchronousHandler)); + } + + private static void InterceptSynchronousVoid(AsyncInterceptorBase me, IInvocation invocation) + { + Task task = me.InterceptAsync(invocation, invocation.CaptureProceedInfo(), ProceedSynchronous); + + // If the intercept task has yet to complete, wait for it. + if (!task.IsCompleted) + { + // Need to use Task.Run() to prevent deadlock in .NET Framework ASP.NET requests. + // GetAwaiter().GetResult() prevents a thrown exception being wrapped in a AggregateException. + // See https://stackoverflow.com/a/17284612 + Task.Run(() => task).GetAwaiter().GetResult(); + } + + task.RethrowIfFaulted(); + } + + private static void InterceptSynchronousResult(AsyncInterceptorBase me, IInvocation invocation) + { + Task task = me.InterceptAsync(invocation, invocation.CaptureProceedInfo(), ProceedSynchronous); + + // If the intercept task has yet to complete, wait for it. + if (!task.IsCompleted) + { + // Need to use Task.Run() to prevent deadlock in .NET Framework ASP.NET requests. + // GetAwaiter().GetResult() prevents a thrown exception being wrapped in a AggregateException. + // See https://stackoverflow.com/a/17284612 + Task.Run(() => task).GetAwaiter().GetResult(); + } + + task.RethrowIfFaulted(); + } + + private static Task ProceedSynchronous(IInvocation invocation, IInvocationProceedInfo proceedInfo) + { + try + { + proceedInfo.Invoke(); +#if NETSTANDARD2_0 || NET5_0 + return Task.CompletedTask; +#else + return CompletedTask; +#endif + } + catch (Exception e) + { +#if NETSTANDARD2_0 || NET5_0 + return Task.FromException(e); +#else + var tcs = new TaskCompletionSource(); + tcs.SetException(e); + return tcs.Task; +#endif + } + } + + private static Task ProceedSynchronous( + IInvocation invocation, + IInvocationProceedInfo proceedInfo) + { + try + { + proceedInfo.Invoke(); + return Task.FromResult((TResult)invocation.ReturnValue); + } + catch (Exception e) + { +#if NETSTANDARD2_0 || NET5_0 + return Task.FromException(e); +#else + var tcs = new TaskCompletionSource(); + tcs.SetException(e); + return tcs.Task; +#endif + } + } + + [SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "The name explicitly says Asynchronous.")] + private static async Task ProceedAsynchronous(IInvocation invocation, IInvocationProceedInfo proceedInfo) + { + proceedInfo.Invoke(); + + // Get the task to await. + var originalReturnValue = (Task)invocation.ReturnValue; + + await originalReturnValue.ConfigureAwait(false); + } + + [SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "The name explicitly says Asynchronous.")] + private static async Task ProceedAsynchronous( + IInvocation invocation, + IInvocationProceedInfo proceedInfo) + { + proceedInfo.Invoke(); + + // Get the task to await. + var originalReturnValue = (Task)invocation.ReturnValue; + + TResult result = await originalReturnValue.ConfigureAwait(false); + return result; + } + } +} diff --git a/Castle.Core.AsyncInterceptor/AsyncTimingInterceptor.cs b/Castle.Core.AsyncInterceptor/AsyncTimingInterceptor.cs new file mode 100644 index 0000000..2087a2f --- /dev/null +++ b/Castle.Core.AsyncInterceptor/AsyncTimingInterceptor.cs @@ -0,0 +1,55 @@ +// Copyright (c) 2016-2021 James Skimming. All rights reserved. +// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. + +namespace Castle.DynamicProxy +{ + using System.Diagnostics; + + /// + /// A base type for an which only wants timings for a method + /// . + /// + public abstract class AsyncTimingInterceptor : ProcessingAsyncInterceptor + { + /// + /// Signals before starting a to time the method + /// . + /// + /// The method invocation. + /// The to time the method . + protected sealed override Stopwatch StartingInvocation(IInvocation invocation) + { + StartingTiming(invocation); + var stopwatch = new Stopwatch(); + stopwatch.Start(); + return stopwatch; + } + + /// + /// Signals after stopping a to time the method + /// . + /// + /// The method invocation. + /// The returned by to time + /// the method . + protected sealed override void CompletedInvocation(IInvocation invocation, Stopwatch state) + { + state.Stop(); + CompletedTiming(invocation, state); + } + + /// + /// Override in derived classes to receive signals prior method timing. + /// + /// The method invocation. + protected abstract void StartingTiming(IInvocation invocation); + + /// + /// Override in derived classes to receive signals after method timing. + /// + /// The method invocation. + /// A used to time the method . + /// + protected abstract void CompletedTiming(IInvocation invocation, Stopwatch stopwatch); + } +} diff --git a/Castle.Core.AsyncInterceptor/Castle.Core.AsyncInterceptor.csproj b/Castle.Core.AsyncInterceptor/Castle.Core.AsyncInterceptor.csproj new file mode 100644 index 0000000..87e7997 --- /dev/null +++ b/Castle.Core.AsyncInterceptor/Castle.Core.AsyncInterceptor.csproj @@ -0,0 +1,57 @@ + + + + netcoreapp3.1 + Castle.DynamicProxy + latest + true + false + enable + AllEnabledByDefault + ..\stylecop.ruleset + false + James Skimming + AsyncInterceptor is an extension to Castle DynamicProxy to simplify the development of interceptors for asynchronous methods. + Copyright © 2016-2021 James Skimming + Apache-2.0 + https://github.com/JSkimming/Castle.Core.AsyncInterceptor + castle-logo.png + true + true + https://github.com/JSkimming/Castle.Core.AsyncInterceptor + git + true + snupkg + async asynchronous-methods castle castle-core dynamic dynamicproxy dynamic-proxy dynamicproxy2 intercept-methods proxy + true + + + + + false + $(MSBuildThisFileDirectory)SharedKey.snk + + true + false + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + diff --git a/Castle.Core.AsyncInterceptor/IAsyncInterceptor.cs b/Castle.Core.AsyncInterceptor/IAsyncInterceptor.cs new file mode 100644 index 0000000..45c581a --- /dev/null +++ b/Castle.Core.AsyncInterceptor/IAsyncInterceptor.cs @@ -0,0 +1,32 @@ +// Copyright (c) 2016-2021 James Skimming. All rights reserved. +// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. + +namespace Castle.DynamicProxy +{ + using System.Threading.Tasks; + + /// + /// Implement this interface to intercept method invocations with DynamicProxy2. + /// + public interface IAsyncInterceptor + { + /// + /// Intercepts a synchronous method . + /// + /// The method invocation. + void InterceptSynchronous(IInvocation invocation); + + /// + /// Intercepts an asynchronous method with return type of . + /// + /// The method invocation. + void InterceptAsynchronous(IInvocation invocation); + + /// + /// Intercepts an asynchronous method with return type of . + /// + /// The type of the . + /// The method invocation. + void InterceptAsynchronous(IInvocation invocation); + } +} diff --git a/Castle.Core.AsyncInterceptor/NoCoverage/RethrowHelper.cs b/Castle.Core.AsyncInterceptor/NoCoverage/RethrowHelper.cs new file mode 100644 index 0000000..21bfbd5 --- /dev/null +++ b/Castle.Core.AsyncInterceptor/NoCoverage/RethrowHelper.cs @@ -0,0 +1,67 @@ +// Copyright (c) 2016-2021 James Skimming. All rights reserved. +// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. + +namespace Castle.DynamicProxy.NoCoverage +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Runtime.ExceptionServices; + using System.Threading.Tasks; + + /// + /// A helper class to re-throw exceptions and retain the stack trace. + /// + internal static class RethrowHelper + { + /// + /// Re-throws the supplied exception without losing its stack trace. + /// Prefer throw; where possible, this method is useful for re-throwing + /// which cannot be done with the throw; semantics. + /// + /// The exception. + public static void Rethrow(this Exception? exception) + { + if (exception == null) + throw new ArgumentNullException(nameof(exception)); + + ExceptionDispatchInfo.Capture(exception).Throw(); + } + + /// + /// If the is an the + /// . is re-thrown; otherwise the + /// is re-thrown. + /// + /// The exception. + public static void RethrowInnerIfAggregate(this Exception? exception) + { + if (exception == null) + throw new ArgumentNullException(nameof(exception)); + + switch (exception) + { + case AggregateException aggregate: + Rethrow(aggregate.InnerException); + break; + default: + Rethrow(exception); + break; + } + } + + /// + /// If the the inner exception is re-thrown; otherwise the + /// method is a no-op. + /// + /// The task. + public static void RethrowIfFaulted(this Task task) + { + if (task == null) + throw new ArgumentNullException(nameof(task)); + + if (task.IsFaulted) + RethrowInnerIfAggregate(task.Exception); + } + } +} diff --git a/Castle.Core.AsyncInterceptor/ProcessingAsyncInterceptor.cs b/Castle.Core.AsyncInterceptor/ProcessingAsyncInterceptor.cs new file mode 100644 index 0000000..eb3857c --- /dev/null +++ b/Castle.Core.AsyncInterceptor/ProcessingAsyncInterceptor.cs @@ -0,0 +1,147 @@ +// Copyright (c) 2016-2021 James Skimming. All rights reserved. +// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. + +namespace Castle.DynamicProxy +{ + using System.Diagnostics.CodeAnalysis; + using System.Threading.Tasks; + + /// + /// A base type for an which executes only minimal processing when intercepting a + /// method . + /// + /// + /// The type of the custom object used to maintain state between and + /// . + /// + public abstract class ProcessingAsyncInterceptor : IAsyncInterceptor + where TState : class + { + /// + /// Intercepts a synchronous method . + /// + /// The method invocation. + public void InterceptSynchronous(IInvocation invocation) + { + TState state = Proceed(invocation); + + // Signal that the invocation has been completed. + CompletedInvocation(invocation, state, invocation.ReturnValue); + } + + /// + /// Intercepts an asynchronous method with return type of . + /// + /// The method invocation. + public void InterceptAsynchronous(IInvocation invocation) + { + TState state = Proceed(invocation); + invocation.ReturnValue = SignalWhenCompleteAsync(invocation, state); + } + + /// + /// Intercepts an asynchronous method with return type of . + /// + /// The type of the . + /// The method invocation. + public void InterceptAsynchronous(IInvocation invocation) + { + TState state = Proceed(invocation); + invocation.ReturnValue = SignalWhenCompleteAsync(invocation, state); + } + + /// + /// Override in derived classes to receive signals prior method . + /// + /// The method invocation. + /// The custom object used to maintain state between and + /// . + protected abstract TState StartingInvocation(IInvocation invocation); + + /// + /// Override in derived classes to receive signals after method . + /// + /// The method invocation. + /// The custom object used to maintain state between + /// and + /// . + protected virtual void CompletedInvocation(IInvocation invocation, TState state) + { + } + + /// + /// Override in derived classes to receive signals after method . + /// + /// The method invocation. + /// The custom object used to maintain state between + /// and + /// . + /// + /// The underlying return value of the ; or if the + /// invocation did not return a value. + /// + protected virtual void CompletedInvocation(IInvocation invocation, TState state, object? returnValue) + { + CompletedInvocation(invocation, state); + } + + /// + /// Signals the then on the + /// . + /// + /// The method invocation. + /// The returned by . + private TState Proceed(IInvocation invocation) + { + // Signal that the invocation is about to be started. + TState state = StartingInvocation(invocation); + + // Execute the invocation. + invocation.Proceed(); + + return state; + } + + /// + /// Returns a that replaces the + /// , that only completes after + /// has been signaled. + /// + /// The method invocation. + /// + /// The returned by . + /// + private async Task SignalWhenCompleteAsync(IInvocation invocation, TState state) + { + // Get the task to await. + var returnValue = (Task)invocation.ReturnValue; + + await returnValue.ConfigureAwait(false); + + // Signal that the invocation has been completed. + CompletedInvocation(invocation, state, null); + } + + /// + /// Returns a that replaces the + /// , that only completes after + /// has been signaled. + /// + /// The method invocation. + /// + /// The returned by . + /// + private async Task SignalWhenCompleteAsync(IInvocation invocation, TState state) + { + // Get the task to await. + var returnValue = (Task)invocation.ReturnValue; + + TResult result = await returnValue.ConfigureAwait(false); + + // Signal that the invocation has been completed. + CompletedInvocation(invocation, state, result); + + return result; + } + } +} diff --git a/Castle.Core.AsyncInterceptor/Properties/AssemblyInfo.cs b/Castle.Core.AsyncInterceptor/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..b7b2e8b --- /dev/null +++ b/Castle.Core.AsyncInterceptor/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +// Copyright (c) 2016-2021 James Skimming. All rights reserved. +// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. + +using System; +using System.Reflection; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +#if NET45 +[assembly: AssemblyTitle("Castle.Core.AsyncInterceptor .NET Framework")] +#elif NET5_0 +[assembly: AssemblyTitle("Castle.Core.AsyncInterceptor .NET 5.0")] +#else +[assembly: AssemblyTitle("Castle.Core.AsyncInterceptor .NET Standard")] +#endif + +[assembly: AssemblyDescription("AsyncInterceptor is an extension to Castle DynamicProxy to simplify the development of interceptors for asynchronous methods.")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Castle.Core.AsyncInterceptor")] +[assembly: AssemblyCopyright("Copyright (c) 2016-2021 James Skimming. All rights reserved.")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] +[assembly: CLSCompliant(true)] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +[assembly: AssemblyVersion("0.0.0.1")] +[assembly: AssemblyFileVersion("0.0.0.1")] +[assembly: AssemblyInformationalVersion("0.0.0.1")] diff --git a/Castle.Core.AsyncInterceptor/ProxyGeneratorExtensions.cs b/Castle.Core.AsyncInterceptor/ProxyGeneratorExtensions.cs new file mode 100644 index 0000000..655190e --- /dev/null +++ b/Castle.Core.AsyncInterceptor/ProxyGeneratorExtensions.cs @@ -0,0 +1,444 @@ +// Copyright (c) 2016-2021 James Skimming. All rights reserved. +// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. + +namespace Castle.DynamicProxy +{ + using System; + using System.Collections.Generic; + using System.Diagnostics.CodeAnalysis; + using System.Linq; + + /// + /// Extension methods to . + /// + public static class ProxyGeneratorExtensions + { + /// + /// Creates an for the supplied . + /// + /// The interceptor for asynchronous operations. + /// The for the supplied . + public static IInterceptor ToInterceptor(this IAsyncInterceptor interceptor) + { + return new AsyncDeterminationInterceptor(interceptor); + } + + /// + /// Creates an array of objects for the supplied . + /// + /// The interceptors for asynchronous operations. + /// The array for the supplied . + public static IInterceptor[] ToInterceptors(this IEnumerable interceptors) + { + return interceptors.Select(ToInterceptor).ToArray(); + } + + /// + public static TInterface CreateInterfaceProxyWithTarget( + this IProxyGenerator proxyGenerator, + TInterface target, + params IAsyncInterceptor[] interceptors) + where TInterface : class + { + return proxyGenerator.CreateInterfaceProxyWithTarget(target, interceptors.ToInterceptors()); + } + + /// + public static TInterface CreateInterfaceProxyWithTarget( + this IProxyGenerator proxyGenerator, + TInterface target, + ProxyGenerationOptions options, + params IAsyncInterceptor[] interceptors) + where TInterface : class + { + return proxyGenerator.CreateInterfaceProxyWithTarget(target, options, interceptors.ToInterceptors()); + } + + /// + public static object CreateInterfaceProxyWithTarget( + this IProxyGenerator proxyGenerator, + Type interfaceToProxy, + object target, + params IAsyncInterceptor[] interceptors) + { + return proxyGenerator.CreateInterfaceProxyWithTarget( + interfaceToProxy, + target, + interceptors.ToInterceptors()); + } + + /// + public static object CreateInterfaceProxyWithTarget( + this IProxyGenerator proxyGenerator, + Type interfaceToProxy, + object target, + ProxyGenerationOptions options, + params IAsyncInterceptor[] interceptors) + { + return proxyGenerator.CreateInterfaceProxyWithTarget( + interfaceToProxy, + target, + options, + interceptors.ToInterceptors()); + } + + /// + public static object CreateInterfaceProxyWithTarget( + this IProxyGenerator proxyGenerator, + Type interfaceToProxy, + Type[] additionalInterfacesToProxy, + object target, + params IAsyncInterceptor[] interceptors) + { + return proxyGenerator.CreateInterfaceProxyWithTarget( + interfaceToProxy, + additionalInterfacesToProxy, + target, + interceptors.ToInterceptors()); + } + + /// + public static object CreateInterfaceProxyWithTarget( + this IProxyGenerator proxyGenerator, + Type interfaceToProxy, + Type[] additionalInterfacesToProxy, + object target, + ProxyGenerationOptions options, + params IAsyncInterceptor[] interceptors) + { + return proxyGenerator.CreateInterfaceProxyWithTarget( + interfaceToProxy, + additionalInterfacesToProxy, + target, + options, + interceptors.ToInterceptors()); + } + + /// + public static object CreateInterfaceProxyWithTargetInterface( + this IProxyGenerator proxyGenerator, + Type interfaceToProxy, + object target, + params IAsyncInterceptor[] interceptors) + { + return proxyGenerator.CreateInterfaceProxyWithTargetInterface( + interfaceToProxy, + target, + interceptors.ToInterceptors()); + } + + /// + public static TInterface CreateInterfaceProxyWithTargetInterface( + this IProxyGenerator proxyGenerator, + TInterface target, + params IAsyncInterceptor[] interceptors) + where TInterface : class + { + return proxyGenerator.CreateInterfaceProxyWithTargetInterface(target, interceptors.ToInterceptors()); + } + + /// + public static TInterface CreateInterfaceProxyWithTargetInterface( + this IProxyGenerator proxyGenerator, + TInterface target, + ProxyGenerationOptions options, + params IAsyncInterceptor[] interceptors) + where TInterface : class + { + return proxyGenerator.CreateInterfaceProxyWithTargetInterface( + target, + options, + interceptors.ToInterceptors()); + } + + /// + public static object CreateInterfaceProxyWithTargetInterface( + this IProxyGenerator proxyGenerator, + Type interfaceToProxy, + Type[] additionalInterfacesToProxy, + object target, + params IAsyncInterceptor[] interceptors) + { + return proxyGenerator.CreateInterfaceProxyWithTargetInterface( + interfaceToProxy, + additionalInterfacesToProxy, + target, + interceptors.ToInterceptors()); + } + + /// + public static object CreateInterfaceProxyWithTargetInterface( + this IProxyGenerator proxyGenerator, + Type interfaceToProxy, + object target, + ProxyGenerationOptions options, + params IAsyncInterceptor[] interceptors) + { + return proxyGenerator.CreateInterfaceProxyWithTargetInterface( + interfaceToProxy, + target, + options, + interceptors.ToInterceptors()); + } + + /// + public static object CreateInterfaceProxyWithTargetInterface( + this IProxyGenerator proxyGenerator, + Type interfaceToProxy, + Type[] additionalInterfacesToProxy, + object target, + ProxyGenerationOptions options, + params IAsyncInterceptor[] interceptors) + { + return proxyGenerator.CreateInterfaceProxyWithTargetInterface( + interfaceToProxy, + additionalInterfacesToProxy, + target, + options, + interceptors.ToInterceptors()); + } + + /// + public static TClass CreateClassProxyWithTarget( + this IProxyGenerator proxyGenerator, + TClass target, + params IAsyncInterceptor[] interceptors) + where TClass : class + { + return proxyGenerator.CreateClassProxyWithTarget(target, interceptors.ToInterceptors()); + } + + /// + public static TClass CreateClassProxyWithTarget( + this IProxyGenerator proxyGenerator, + TClass target, + ProxyGenerationOptions options, + params IAsyncInterceptor[] interceptors) + where TClass : class + { + return proxyGenerator.CreateClassProxyWithTarget(target, options, interceptors.ToInterceptors()); + } + + /// + public static object CreateClassProxyWithTarget( + this IProxyGenerator proxyGenerator, + Type classToProxy, + Type[] additionalInterfacesToProxy, + object target, + params IAsyncInterceptor[] interceptors) + { + return proxyGenerator.CreateClassProxyWithTarget( + classToProxy, + additionalInterfacesToProxy, + target, + interceptors.ToInterceptors()); + } + + /// + public static object CreateClassProxyWithTarget( + this IProxyGenerator proxyGenerator, + Type classToProxy, + object target, + ProxyGenerationOptions options, + object[] constructorArguments, + params IAsyncInterceptor[] interceptors) + { + return proxyGenerator.CreateClassProxyWithTarget( + classToProxy, + target, + options, + constructorArguments, + interceptors.ToInterceptors()); + } + + /// + public static object CreateClassProxyWithTarget( + this IProxyGenerator proxyGenerator, + Type classToProxy, + object target, + object[] constructorArguments, + params IAsyncInterceptor[] interceptors) + { + return proxyGenerator.CreateClassProxyWithTarget( + classToProxy, + target, + constructorArguments, + interceptors.ToInterceptors()); + } + + /// + public static object CreateClassProxyWithTarget( + this IProxyGenerator proxyGenerator, + Type classToProxy, + object target, + params IAsyncInterceptor[] interceptors) + { + return proxyGenerator.CreateClassProxyWithTarget(classToProxy, target, interceptors.ToInterceptors()); + } + + /// + public static object CreateClassProxyWithTarget( + this IProxyGenerator proxyGenerator, + Type classToProxy, + object target, + ProxyGenerationOptions options, + params IAsyncInterceptor[] interceptors) + { + return proxyGenerator.CreateClassProxyWithTarget( + classToProxy, + target, + options, + interceptors.ToInterceptors()); + } + + /// + public static object CreateClassProxyWithTarget( + this IProxyGenerator proxyGenerator, + Type classToProxy, + Type[] additionalInterfacesToProxy, + object target, + ProxyGenerationOptions options, + params IAsyncInterceptor[] interceptors) + { + return proxyGenerator.CreateClassProxyWithTarget( + classToProxy, + additionalInterfacesToProxy, + target, + options, + interceptors.ToInterceptors()); + } + + /// + public static object CreateClassProxyWithTarget( + this IProxyGenerator proxyGenerator, + Type classToProxy, + Type[] additionalInterfacesToProxy, + object target, + ProxyGenerationOptions options, + object[] constructorArguments, + params IAsyncInterceptor[] interceptors) + { + return proxyGenerator.CreateClassProxyWithTarget( + classToProxy, + additionalInterfacesToProxy, + target, + options, + constructorArguments, + interceptors.ToInterceptors()); + } + + /// + public static TClass CreateClassProxy( + this IProxyGenerator proxyGenerator, + params IAsyncInterceptor[] interceptors) + where TClass : class + { + return proxyGenerator.CreateClassProxy(interceptors.ToInterceptors()); + } + + /// + public static TClass CreateClassProxy( + this IProxyGenerator proxyGenerator, + ProxyGenerationOptions options, + params IAsyncInterceptor[] interceptors) + where TClass : class + { + return proxyGenerator.CreateClassProxy(options, interceptors.ToInterceptors()); + } + + /// + public static object CreateClassProxy( + this IProxyGenerator proxyGenerator, + Type classToProxy, + Type[] additionalInterfacesToProxy, + params IAsyncInterceptor[] interceptors) + { + return proxyGenerator.CreateClassProxy( + classToProxy, + additionalInterfacesToProxy, + interceptors.ToInterceptors()); + } + + /// + public static object CreateClassProxy( + this IProxyGenerator proxyGenerator, + Type classToProxy, + ProxyGenerationOptions options, + object[] constructorArguments, + params IAsyncInterceptor[] interceptors) + { + return proxyGenerator.CreateClassProxy( + classToProxy, + options, + constructorArguments, + interceptors.ToInterceptors()); + } + + /// + public static object CreateClassProxy( + this IProxyGenerator proxyGenerator, + Type classToProxy, + object[] constructorArguments, + params IAsyncInterceptor[] interceptors) + { + return proxyGenerator.CreateClassProxy( + classToProxy, + constructorArguments, + interceptors.ToInterceptors()); + } + + /// + public static object CreateClassProxy( + this IProxyGenerator proxyGenerator, + Type classToProxy, + params IAsyncInterceptor[] interceptors) + { + return proxyGenerator.CreateClassProxy(classToProxy, interceptors.ToInterceptors()); + } + + /// + public static object CreateClassProxy( + this IProxyGenerator proxyGenerator, + Type classToProxy, + ProxyGenerationOptions options, + params IAsyncInterceptor[] interceptors) + { + return proxyGenerator.CreateClassProxy( + classToProxy, + options, + interceptors.ToInterceptors()); + } + + /// + public static object CreateClassProxy( + this IProxyGenerator proxyGenerator, + Type classToProxy, + Type[] additionalInterfacesToProxy, + ProxyGenerationOptions options, + params IAsyncInterceptor[] interceptors) + { + return proxyGenerator.CreateClassProxy( + classToProxy, + additionalInterfacesToProxy, + options, + interceptors.ToInterceptors()); + } + + /// + public static object CreateClassProxy( + this IProxyGenerator proxyGenerator, + Type classToProxy, + Type[] additionalInterfacesToProxy, + ProxyGenerationOptions options, + object[] constructorArguments, + params IAsyncInterceptor[] interceptors) + { + return proxyGenerator.CreateClassProxy( + classToProxy, + additionalInterfacesToProxy, + options, + constructorArguments, + interceptors.ToInterceptors()); + } + } +} diff --git a/Castle.Core.AsyncInterceptor/SharedKey.snk b/Castle.Core.AsyncInterceptor/SharedKey.snk new file mode 100644 index 0000000000000000000000000000000000000000..8ef35290f70882ffcdfe3e4db0cd425832e0fd2b GIT binary patch literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50098ezcQRec3tOl|7B?nY+t{O`?_AR?qfqz zTg`25$E5JsQB zJRp8`?TC}{t8$l5UG=>w1=I;@A^7D|SNYLgOB*is_*w*I{|iVO32xkP*UZl;`iOrL#GXD6sm~YB*tT}+b8gxL<;xWK(q}a2&&E5Va-_tNFM=eCDbYE}yv(ht?3{+Q`-mF&|KzP`)l0~vQ`T8QKP-u z6(r}`-?LrwOdpoDjOTE(<{wMp(IyPhw(g8AoZ`XkLDY4p#`BPDtE@t&0Xu_BHgDV@ z9hmU!d*9MKa>=pP#;VglXF!9LOz#}^UEU+w7&BL!u|$T|;v0j$e`BxP2AHoc1c`?P zh)elLmuS*)a+jqB%kUcHgpVa&k+t4RAYly6+*^q^p;EBd@>T5Ll1S=>dG9S+AO|4x i7ctP*Zg^_QO&p>l1Pr@n(i@(E`g;6SxCX@g>?axzl_&H7 literal 0 HcmV?d00001 diff --git a/Castle.Core/Castle.Core.csproj b/Castle.Core/Castle.Core.csproj new file mode 100644 index 0000000..606b655 --- /dev/null +++ b/Castle.Core/Castle.Core.csproj @@ -0,0 +1,52 @@ + + + + netcoreapp3.1 + + + + Castle.Core_NL + True + ../../build/ + Castle.Core + Castle + Castle Core + Castle Core, including DynamicProxy(with limited logging), Logging Abstractions and DictionaryAdapter + ..\..\buildscripts\CastleKey.snk + false + true + castle dynamicproxy dynamic proxy dynamicproxy2 dictionaryadapter emailsender + 4.4.1.1 + 4.4.1.1 + 4.4.1.1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Castle.Core/Components.DictionaryAdapter/AbstractDictionaryAdapter.cs b/Castle.Core/Components.DictionaryAdapter/AbstractDictionaryAdapter.cs new file mode 100644 index 0000000..3de0aad --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/AbstractDictionaryAdapter.cs @@ -0,0 +1,170 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"; +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System; + using System.Collections; + + /// + /// Abstract adapter for the support + /// needed by the + /// + public abstract class AbstractDictionaryAdapter : IDictionary + { + /// + /// Adds an element with the provided key and value to the object. + /// + /// The to use as the key of the element to add. + /// The to use as the value of the element to add. + /// An element with the same key already exists in the object. + /// key is null. + /// The is read-only.-or- The has a fixed size. + public void Add(object key, object value) + { + throw new NotSupportedException(); + } + + /// + /// Removes all elements from the object. + /// + /// The object is read-only. + public void Clear() + { + throw new NotSupportedException(); + } + + /// + /// Determines whether the object contains an element with the specified key. + /// + /// The key to locate in the object. + /// + /// true if the contains an element with the key; otherwise, false. + /// + /// key is null. + public abstract bool Contains(object key); + + /// + /// Returns an object for the object. + /// + /// + /// An object for the object. + /// + public IDictionaryEnumerator GetEnumerator() + { + throw new NotSupportedException(); + } + + /// + /// Gets a value indicating whether the object has a fixed size. + /// + /// true if the object has a fixed size; otherwise, false. + public bool IsFixedSize + { + get { throw new NotSupportedException(); } + } + + /// + /// Gets a value indicating whether the object is read-only. + /// + /// true if the object is read-only; otherwise, false. + public abstract bool IsReadOnly { get; } + + /// + /// Gets an object containing the keys of the object. + /// + /// An object containing the keys of the object. + public ICollection Keys + { + get { throw new NotSupportedException(); } + } + + /// + /// Removes the element with the specified key from the object. + /// + /// The key of the element to remove. + /// The object is read-only.-or- The has a fixed size. + /// key is null. + public void Remove(object key) + { + throw new NotSupportedException(); + } + + /// + /// Gets an object containing the values in the object. + /// + /// An object containing the values in the object. + public ICollection Values + { + get { throw new NotSupportedException(); } + } + + /// + /// Gets or sets the with the specified key. + /// + public abstract object this[object key] { get; set; } + + /// + /// Copies the elements of the to an , starting at a particular index. + /// + /// The one-dimensional that is the destination of the elements copied from . The must have zero-based indexing. + /// The zero-based index in array at which copying begins. + /// array is null. + /// The type of the source cannot be cast automatically to the type of the destination array. + /// index is less than zero. + /// array is multidimensional.-or- index is equal to or greater than the length of array.-or- The number of elements in the source is greater than the available space from index to the end of the destination array. + public void CopyTo(Array array, int index) + { + throw new NotSupportedException(); + } + + /// + /// Gets the number of elements contained in the . + /// + /// The number of elements contained in the . + public int Count + { + get { throw new NotSupportedException(); } + } + + /// + /// Gets a value indicating whether access to the is synchronized (thread safe). + /// + /// true if access to the is synchronized (thread safe); otherwise, false. + public virtual bool IsSynchronized + { + get { return false; } + } + + /// + /// Gets an object that can be used to synchronize access to the . + /// + /// An object that can be used to synchronize access to the . + public virtual object SyncRoot + { + get { return this; } + } + + /// + /// Returns an enumerator that iterates through a collection. + /// + /// + /// An object that can be used to iterate through the collection. + /// + IEnumerator IEnumerable.GetEnumerator() + { + throw new NotSupportedException(); + } + } +} \ No newline at end of file diff --git a/Castle.Core/Components.DictionaryAdapter/AbstractDictionaryAdapterVisitor.cs b/Castle.Core/Components.DictionaryAdapter/AbstractDictionaryAdapterVisitor.cs new file mode 100644 index 0000000..4363e4d --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/AbstractDictionaryAdapterVisitor.cs @@ -0,0 +1,159 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System; + using System.Linq; + using System.Collections; + using System.Collections.Generic; + using System.Reflection; + + using Castle.Core; + + /// + /// Abstract implementation of . + /// + public abstract class AbstractDictionaryAdapterVisitor : IDictionaryAdapterVisitor + { + private readonly Dictionary scopes; + + protected AbstractDictionaryAdapterVisitor() + { + scopes = new Dictionary(ReferenceEqualityComparer.Instance); + } + + protected AbstractDictionaryAdapterVisitor(AbstractDictionaryAdapterVisitor parent) + { + scopes = parent.scopes; + } + + protected bool Cancelled { get; set; } + + public virtual bool VisitDictionaryAdapter(IDictionaryAdapter dictionaryAdapter, object state) + { + return VisitDictionaryAdapter(dictionaryAdapter, null, null); + } + + public virtual bool VisitDictionaryAdapter(IDictionaryAdapter dictionaryAdapter, Func selector, object state) + { + if (PushScope(dictionaryAdapter) == false) + { + return false; + } + + try + { + foreach (var property in dictionaryAdapter.This.Properties.Values) + { + if (Cancelled) break; + + if (selector != null && selector(property) == false) + { + continue; + } + + Type collectionItemType; + if (IsCollection(property, out collectionItemType)) + { + VisitCollection(dictionaryAdapter, property, collectionItemType, state); + } + else if (property.PropertyType.IsInterface) + { + VisitInterface(dictionaryAdapter, property, state); + } + else + { + VisitProperty(dictionaryAdapter, property, state); + } + } + } + finally + { + PopScope(dictionaryAdapter); + } + + return true; + } + + void IDictionaryAdapterVisitor.VisitProperty(IDictionaryAdapter dictionaryAdapter, PropertyDescriptor property, object state) + { + VisitProperty(dictionaryAdapter, property, state); + } + + protected virtual void VisitProperty(IDictionaryAdapter dictionaryAdapter, PropertyDescriptor property, object state) + { + } + + void IDictionaryAdapterVisitor.VisitInterface(IDictionaryAdapter dictionaryAdapter, PropertyDescriptor property, object state) + { + + VisitInterface(dictionaryAdapter, property, state); + } + + protected virtual void VisitInterface(IDictionaryAdapter dictionaryAdapter, PropertyDescriptor property, object state) + { + VisitProperty(dictionaryAdapter, property, state); + } + + void IDictionaryAdapterVisitor.VisitCollection(IDictionaryAdapter dictionaryAdapter, PropertyDescriptor property, Type collectionItemType, object state) + { + VisitCollection(dictionaryAdapter, property, collectionItemType, state); + } + + protected virtual void VisitCollection(IDictionaryAdapter dictionaryAdapter, PropertyDescriptor property, Type collectionItemType, object state) + { + VisitProperty(dictionaryAdapter, property, state); + } + + private bool PushScope(IDictionaryAdapter dictionaryAdapter) + { + if (scopes.ContainsKey(dictionaryAdapter)) + { + return false; + } + scopes.Add(dictionaryAdapter, 0); + return true; + } + + private void PopScope(IDictionaryAdapter dictionaryAdapter) + { + scopes.Remove(dictionaryAdapter); + } + + private static bool IsCollection(PropertyDescriptor property, out Type collectionItemType) + { + collectionItemType = null; + var propertyType = property.PropertyType; + if (propertyType != typeof(string) && typeof(IEnumerable).IsAssignableFrom(propertyType)) + { + if (propertyType.IsArray) + { + collectionItemType = propertyType.GetElementType(); + } + else if (propertyType.IsGenericType) + { + var arguments = propertyType.GetGenericArguments(); + collectionItemType = arguments[0]; + } + else + { + collectionItemType = typeof(object); + } + return true; + } + return false; + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Attributes/ComponentAttribute.cs b/Castle.Core/Components.DictionaryAdapter/Attributes/ComponentAttribute.cs new file mode 100644 index 0000000..b1e8220 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Attributes/ComponentAttribute.cs @@ -0,0 +1,94 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System; + + /// + /// Identifies a property should be represented as a nested component. + /// + [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)] + public class ComponentAttribute : DictionaryBehaviorAttribute, IDictionaryKeyBuilder, + IDictionaryPropertyGetter, IDictionaryPropertySetter + { + /// + /// Applies no prefix. + /// + public bool NoPrefix + { + get { return Prefix == ""; } + set + { + if (value) + { + Prefix = ""; + } + } + } + + /// + /// Gets or sets the prefix. + /// + /// The prefix. + public string Prefix { get; set; } + + #region IDictionaryKeyBuilder Members + + string IDictionaryKeyBuilder.GetKey(IDictionaryAdapter dictionaryAdapter, string key, + PropertyDescriptor property) + { + return Prefix ?? key + "_"; + } + + #endregion + + #region IDictionaryPropertyGetter + + object IDictionaryPropertyGetter.GetPropertyValue(IDictionaryAdapter dictionaryAdapter, + string key, object storedValue, PropertyDescriptor property, bool ifExists) + { + if (storedValue == null) + { + var component = dictionaryAdapter.This.ExtendedProperties[property.PropertyName]; + + if (component == null) + { + var descriptor = new PropertyDescriptor(property.Property, null); + descriptor.AddBehavior(new KeyPrefixAttribute(key)); + component = dictionaryAdapter.This.Factory.GetAdapter( + property.Property.PropertyType, dictionaryAdapter.This.Dictionary, descriptor); + dictionaryAdapter.This.ExtendedProperties[property.PropertyName] = component; + } + + return component; + } + + return storedValue; + } + + #endregion + + #region IDictionaryPropertySetter Members + + public bool SetPropertyValue(IDictionaryAdapter dictionaryAdapter, + string key, ref object value, PropertyDescriptor property) + { + dictionaryAdapter.This.ExtendedProperties.Remove(property.PropertyName); + return false; + } + + #endregion + } +} \ No newline at end of file diff --git a/Castle.Core/Components.DictionaryAdapter/Attributes/DictionaryAdapterAttribute.cs b/Castle.Core/Components.DictionaryAdapter/Attributes/DictionaryAdapterAttribute.cs new file mode 100644 index 0000000..5d62f08 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Attributes/DictionaryAdapterAttribute.cs @@ -0,0 +1,32 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System; + + /// + /// Identifies the dictionary adapter types. + /// + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] + public class DictionaryAdapterAttribute : Attribute + { + public DictionaryAdapterAttribute(Type interfaceType) + { + InterfaceType = interfaceType; + } + + public Type InterfaceType { get; private set; } + } +} \ No newline at end of file diff --git a/Castle.Core/Components.DictionaryAdapter/Attributes/DictionaryBehaviorAttribute.cs b/Castle.Core/Components.DictionaryAdapter/Attributes/DictionaryBehaviorAttribute.cs new file mode 100644 index 0000000..4d2d4e0 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Attributes/DictionaryBehaviorAttribute.cs @@ -0,0 +1,40 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System; + + /// + /// Assigns a specific dictionary key. + /// + public abstract class DictionaryBehaviorAttribute : Attribute, IDictionaryBehavior + { + public const int FirstExecutionOrder = 0; + public const int DefaultExecutionOrder = int.MaxValue / 2; + public const int LastExecutionOrder = int.MaxValue; + + public DictionaryBehaviorAttribute() + { + ExecutionOrder = DefaultExecutionOrder; + } + + public int ExecutionOrder { get; set; } + + public virtual IDictionaryBehavior Copy() + { + return this; + } + } +} \ No newline at end of file diff --git a/Castle.Core/Components.DictionaryAdapter/Attributes/FetchAttribute.cs b/Castle.Core/Components.DictionaryAdapter/Attributes/FetchAttribute.cs new file mode 100644 index 0000000..975773c --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Attributes/FetchAttribute.cs @@ -0,0 +1,45 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System; + + /// + /// Identifies an interface or property to be pre-fetched. + /// + [AttributeUsage(AttributeTargets.Interface | AttributeTargets.Property, AllowMultiple = false)] + public class FetchAttribute : Attribute + { + /// + /// Instructs fetching to occur. + /// + public FetchAttribute() : this(true) + { + } + + /// + /// Instructs fetching according to + /// + public FetchAttribute(bool fetch) + { + Fetch = fetch; + } + + /// + /// Gets whether or not fetching should occur. + /// + public bool Fetch { get; private set; } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Attributes/GroupAttribute.cs b/Castle.Core/Components.DictionaryAdapter/Attributes/GroupAttribute.cs new file mode 100644 index 0000000..7180a07 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Attributes/GroupAttribute.cs @@ -0,0 +1,48 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System; + + /// + /// Assigns a property to a group. + /// + [AttributeUsage(AttributeTargets.Property, AllowMultiple = true)] + public class GroupAttribute : Attribute + { + /// + /// Constructs a group assignment. + /// + /// The group name. + public GroupAttribute(object group) + { + Group = new [] { group }; + } + + /// + /// Constructs a group assignment. + /// + /// The group name. + public GroupAttribute(params object[] group) + { + Group = group; + } + + /// + /// Gets the group the property is assigned to. + /// + public object[] Group { get; private set; } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Attributes/IfExistsAttribute.cs b/Castle.Core/Components.DictionaryAdapter/Attributes/IfExistsAttribute.cs new file mode 100644 index 0000000..2e26950 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Attributes/IfExistsAttribute.cs @@ -0,0 +1,26 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System; + + /// + /// Suppresses any on-demand behaviors. + /// + [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] + public class IfExistsAttribute : Attribute + { + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Attributes/KeyAttribute.cs b/Castle.Core/Components.DictionaryAdapter/Attributes/KeyAttribute.cs new file mode 100644 index 0000000..6fde21a --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Attributes/KeyAttribute.cs @@ -0,0 +1,50 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System; + + /// + /// Assigns a specific dictionary key. + /// + [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)] + public class KeyAttribute : DictionaryBehaviorAttribute, IDictionaryKeyBuilder + { + /// + /// Initializes a new instance of the class. + /// + /// The key. + public KeyAttribute(string key) + { + Key = key; + } + + /// + /// Initializes a new instance of the class. + /// + /// The compound key. + public KeyAttribute(string[] keys) + { + Key = string.Join(",", keys); + } + + public string Key { get; private set; } + + string IDictionaryKeyBuilder.GetKey(IDictionaryAdapter dictionaryAdapter, string key, PropertyDescriptor property) + { + return Key; + } + } +} \ No newline at end of file diff --git a/Castle.Core/Components.DictionaryAdapter/Attributes/KeyPrefixAttribute.cs b/Castle.Core/Components.DictionaryAdapter/Attributes/KeyPrefixAttribute.cs new file mode 100644 index 0000000..7f24cc0 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Attributes/KeyPrefixAttribute.cs @@ -0,0 +1,54 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System; + + /// + /// Assigns a prefix to the keyed properties of an interface. + /// + /// + /// Key prefixes are not inherited by sub-interfaces. + /// + [AttributeUsage(AttributeTargets.Interface, AllowMultiple = false, Inherited = false)] + public class KeyPrefixAttribute : DictionaryBehaviorAttribute, IDictionaryKeyBuilder + { + /// + /// Initializes a default instance of the class. + /// + public KeyPrefixAttribute() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The prefix for the keyed properties of the interface. + public KeyPrefixAttribute(string keyPrefix) + { + this.KeyPrefix = keyPrefix; + } + + /// + /// Gets the prefix key added to the properties of the interface. + /// + public string KeyPrefix { get; set; } + + string IDictionaryKeyBuilder.GetKey(IDictionaryAdapter dictionaryAdapter, string key, PropertyDescriptor property) + { + return KeyPrefix + key; + } + } +} \ No newline at end of file diff --git a/Castle.Core/Components.DictionaryAdapter/Attributes/KeySubstitutionAttribute.cs b/Castle.Core/Components.DictionaryAdapter/Attributes/KeySubstitutionAttribute.cs new file mode 100644 index 0000000..c13fa6e --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Attributes/KeySubstitutionAttribute.cs @@ -0,0 +1,44 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System; + + /// + /// Substitutes part of key with another string. + /// + [AttributeUsage(AttributeTargets.Interface | AttributeTargets.Property, AllowMultiple = true, Inherited = true)] + public class KeySubstitutionAttribute : DictionaryBehaviorAttribute, IDictionaryKeyBuilder + { + private readonly string oldValue; + private readonly string newValue; + + /// + /// Initializes a new instance of the class. + /// + /// The old value. + /// The new value. + public KeySubstitutionAttribute(string oldValue, string newValue) + { + this.oldValue = oldValue; + this.newValue = newValue; + } + + string IDictionaryKeyBuilder.GetKey(IDictionaryAdapter dictionaryAdapter, string key, PropertyDescriptor property) + { + return key.Replace(oldValue, newValue); + } + } +} \ No newline at end of file diff --git a/Castle.Core/Components.DictionaryAdapter/Attributes/MultiLevelEditAttribute.cs b/Castle.Core/Components.DictionaryAdapter/Attributes/MultiLevelEditAttribute.cs new file mode 100644 index 0000000..88520b6 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Attributes/MultiLevelEditAttribute.cs @@ -0,0 +1,30 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System; + + /// + /// Requests support for multi-level editing. + /// + [AttributeUsage(AttributeTargets.Interface, AllowMultiple = false)] + public class MultiLevelEditAttribute : DictionaryBehaviorAttribute, IDictionaryInitializer + { + public void Initialize(IDictionaryAdapter dictionaryAdapter, object[] behaviors) + { + dictionaryAdapter.SupportsMultiLevelEdit = true; + } + } +} \ No newline at end of file diff --git a/Castle.Core/Components.DictionaryAdapter/Attributes/NewGuidAttribute.cs b/Castle.Core/Components.DictionaryAdapter/Attributes/NewGuidAttribute.cs new file mode 100644 index 0000000..25e3ad2 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Attributes/NewGuidAttribute.cs @@ -0,0 +1,39 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System; + + /// + /// Generates a new GUID on demand. + /// + [AttributeUsage(AttributeTargets.Interface | AttributeTargets.Property, AllowMultiple = false)] + public class NewGuidAttribute : DictionaryBehaviorAttribute, IDictionaryPropertyGetter + { + private static readonly Guid UnassignedGuid = new Guid(); + + public object GetPropertyValue(IDictionaryAdapter dictionaryAdapter, + string key, object storedValue, PropertyDescriptor property, bool ifExists) + { + if (storedValue == null || storedValue.Equals(UnassignedGuid)) + { + storedValue = Guid.NewGuid(); + property.SetPropertyValue(dictionaryAdapter, key, ref storedValue, dictionaryAdapter.This.Descriptor); + } + + return storedValue; + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Attributes/OnDemandAttribute.cs b/Castle.Core/Components.DictionaryAdapter/Attributes/OnDemandAttribute.cs new file mode 100644 index 0000000..acdad16 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Attributes/OnDemandAttribute.cs @@ -0,0 +1,198 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.ComponentModel; + using System.Linq; + using System.Reflection; + + /// + /// Support for on-demand value resolution. + /// + [AttributeUsage(AttributeTargets.Interface | AttributeTargets.Property, AllowMultiple = false)] + public class OnDemandAttribute : DictionaryBehaviorAttribute, IDictionaryPropertyGetter + { + public OnDemandAttribute() + { + } + + public OnDemandAttribute(Type type) + { + if (type.GetConstructor(Type.EmptyTypes) == null) + { + throw new ArgumentException("On-demand values must have a parameterless constructor"); + } + + Type = type; + } + + public OnDemandAttribute(object value) + { + Value = value; + } + + public Type Type { get; private set; } + + public object Value { get; private set; } + + public object GetPropertyValue(IDictionaryAdapter dictionaryAdapter, string key, + object storedValue, PropertyDescriptor property, bool ifExists) + { + if (storedValue == null && ifExists == false) + { + IValueInitializer initializer = null; + + if (Value != null) + { + storedValue = Value; + } + else + { + var type = Type ?? GetInferredType(dictionaryAdapter, property, out initializer); + + if (IsAcceptedType(type)) + { + if (type.IsInterface) + { + if (property.IsDynamicProperty == false) + { + if (storedValue == null) + { + storedValue = dictionaryAdapter.Create(property.PropertyType); + } + } + } + else if (type.IsArray) + { + storedValue = Array.CreateInstance(type.GetElementType(), 0); + } + else + { + if (storedValue == null) + { + object[] args = null; + ConstructorInfo constructor = null; + + if (property.IsDynamicProperty) + { + constructor = + (from ctor in type.GetConstructors() + let parms = ctor.GetParameters() + where parms.Length == 1 && + parms[0].ParameterType.IsAssignableFrom(dictionaryAdapter.Meta.Type) + select ctor).FirstOrDefault(); + + if (constructor != null) args = new[] { dictionaryAdapter }; + } + + if (constructor == null) + { + constructor = type.GetConstructor(Type.EmptyTypes); + } + + if (constructor != null) + { + storedValue = constructor.Invoke(args); + } + } + } + } + } + + if (storedValue != null) + { + using (dictionaryAdapter.SuppressNotificationsBlock()) + { + if (storedValue is ISupportInitialize) + { + ((ISupportInitialize)storedValue).BeginInit(); + ((ISupportInitialize)storedValue).EndInit(); + } + if (initializer != null) + { + initializer.Initialize(dictionaryAdapter, storedValue); + } + + property.SetPropertyValue(dictionaryAdapter, property.PropertyName, + ref storedValue, dictionaryAdapter.This.Descriptor); + } + } + } + + return storedValue; + } + + private static bool IsAcceptedType(Type type) + { + return type != null && type != typeof(string) && !type.IsPrimitive && !type.IsEnum; + } + + private static Type GetInferredType(IDictionaryAdapter dictionaryAdapter, PropertyDescriptor property, out IValueInitializer initializer) + { + Type type = null; + initializer = null; + + type = property.PropertyType; + if (typeof(IEnumerable).IsAssignableFrom(type) == false) + { + return type; + } + + Type collectionType = null; + + if (type.IsGenericType) + { + var genericDef = type.GetGenericTypeDefinition(); + var genericArg = type.GetGenericArguments()[0]; + bool isBindingList = + genericDef == typeof(System.ComponentModel.BindingList<>); + + if (isBindingList || genericDef == typeof(List<>)) + { + if (dictionaryAdapter.CanEdit) + { + collectionType = isBindingList ? typeof(EditableBindingList<>) : typeof(EditableList<>); + } + + if (isBindingList && genericArg.IsInterface) + { + Func addNew = () => dictionaryAdapter.Create(genericArg); + initializer = (IValueInitializer)Activator.CreateInstance( + typeof(BindingListInitializer<>).MakeGenericType(genericArg), + null, addNew, null, null, null); + } + } + else if (genericDef == typeof(IList<>) || genericDef == typeof(ICollection<>)) + { + collectionType = dictionaryAdapter.CanEdit ? typeof(EditableList<>) : typeof(List<>); + } + + if (collectionType != null) + { + return collectionType.MakeGenericType(genericArg); + } + } + else if (type == typeof(IList) || type == typeof(ICollection)) + { + return dictionaryAdapter.CanEdit ? typeof(EditableList) : typeof(List); + } + + return type; + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Attributes/ReferenceAttribute.cs b/Castle.Core/Components.DictionaryAdapter/Attributes/ReferenceAttribute.cs new file mode 100644 index 0000000..7aa0d54 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Attributes/ReferenceAttribute.cs @@ -0,0 +1,27 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System; + + /// + /// Specifies assignment by reference rather than by copying. + /// + [AttributeUsage(AttributeTargets.Property | AttributeTargets.Interface)] + public class ReferenceAttribute : Attribute + { + // Marker attribute; no functionality + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Attributes/RemoveIfAttribute.cs b/Castle.Core/Components.DictionaryAdapter/Attributes/RemoveIfAttribute.cs new file mode 100644 index 0000000..cf8da72 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Attributes/RemoveIfAttribute.cs @@ -0,0 +1,123 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System; + using System.Linq; + using System.Collections; + using System.Reflection; + + /// + /// Removes a property if matches value. + /// + [AttributeUsage(AttributeTargets.Interface | AttributeTargets.Property, AllowMultiple = true)] + public class RemoveIfAttribute : DictionaryBehaviorAttribute, IDictionaryPropertySetter + { + private ICondition condition; + + public RemoveIfAttribute() + { + ExecutionOrder += 10; + } + + public RemoveIfAttribute(params object[] values) : this() + { + values = values ?? new object[] { null }; + condition = new ValueCondition(values, null); + } + + public RemoveIfAttribute(object[] values, Type comparerType) : this() + { + var comparer = Construct(comparerType, nameof(comparerType)); + condition = new ValueCondition(values, comparer); + } + + protected RemoveIfAttribute(ICondition condition) : this() + { + this.condition = condition; + } + + public Type Condition + { + set { condition = Construct(value, nameof(value)); } + } + + bool IDictionaryPropertySetter.SetPropertyValue(IDictionaryAdapter dictionaryAdapter, + string key, ref object value, PropertyDescriptor property) + { + if (ShouldRemove(value)) + { + dictionaryAdapter.ClearProperty(property, key); + return false; + } + return true; + } + + internal bool ShouldRemove(object value) + { + return condition != null && condition.SatisfiedBy(value); + } + + private static TBase Construct(Type type, string paramName) + where TBase : class + { + if (type == null) + { + throw new ArgumentNullException(paramName); + } + + if (type.IsAbstract == false && typeof(TBase).IsAssignableFrom(type)) + { + var constructor = type.GetConstructor(Type.EmptyTypes); + if (constructor != null) + { + return (TBase)constructor.Invoke(new object[0]); + } + } + + throw new ArgumentException(string.Format( + "{0} is not a concrete type implementing {1} with a default constructor", + type.FullName, typeof(TBase).FullName)); + } + + #region Nested Class: ValueCondition + + class ValueCondition : ICondition + { + private readonly object[] values; + private readonly IEqualityComparer comparer; + + public ValueCondition(object[] values, IEqualityComparer comparer) + { + this.values = values; + this.comparer = comparer; + } + + public bool SatisfiedBy(object value) + { + return values.Any(valueToMatch => + { + if (comparer == null) + { + return Equals(value, valueToMatch); + } + return comparer.Equals(value, valueToMatch); + }); + } + } + + #endregion + } +} \ No newline at end of file diff --git a/Castle.Core/Components.DictionaryAdapter/Attributes/RemoveIfEmptyAttribute.cs b/Castle.Core/Components.DictionaryAdapter/Attributes/RemoveIfEmptyAttribute.cs new file mode 100644 index 0000000..a1343ae --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Attributes/RemoveIfEmptyAttribute.cs @@ -0,0 +1,60 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System; + using System.Collections; + + /// + /// Removes a property if null or empty string, guid or collection. + /// + public class RemoveIfEmptyAttribute : RemoveIfAttribute + { + public RemoveIfEmptyAttribute() + : base(RemoveIfEmptyCondition.Instance) + { + } + + private new Type Condition { get; set; } + + class RemoveIfEmptyCondition : ICondition + { + public static readonly RemoveIfEmptyCondition Instance = new RemoveIfEmptyCondition(); + + public bool SatisfiedBy(object value) + { + return value == null || + IsEmptyString(value) || + IsEmptyGuid(value) || + IsEmptyCollection(value); + } + + private static bool IsEmptyString(object value) + { + return (value is string && ((string)value).Length == 0); + } + + private static bool IsEmptyGuid(object value) + { + return (value is Guid && ((Guid)value) == Guid.Empty); + } + + private static bool IsEmptyCollection(object value) + { + return (value is IEnumerable && ((IEnumerable)value).GetEnumerator().MoveNext() == false); + } + } + } +} \ No newline at end of file diff --git a/Castle.Core/Components.DictionaryAdapter/Attributes/StringFormatAttribute.cs b/Castle.Core/Components.DictionaryAdapter/Attributes/StringFormatAttribute.cs new file mode 100644 index 0000000..309e7cd --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Attributes/StringFormatAttribute.cs @@ -0,0 +1,77 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System; + + /// + /// Provides simple string formatting from existing properties. + /// + [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)] + public class StringFormatAttribute : DictionaryBehaviorAttribute, IDictionaryPropertyGetter + { + private static readonly char[] PropertyDelimeters = new[] { ',', ' ' }; + + public StringFormatAttribute(string format, string properties) + { + if (format == null) + { + throw new ArgumentNullException(nameof(format)); + } + + Format = format; + Properties = properties; + } + + /// + /// Gets the string format. + /// + public string Format { get; private set; } + + /// + /// Gets the format properties. + /// + public string Properties { get; private set; } + + #region IDictionaryPropertyGetter + + object IDictionaryPropertyGetter.GetPropertyValue(IDictionaryAdapter dictionaryAdapter, + string key, object storedValue, PropertyDescriptor property, bool ifExists) + { + return string.Format(Format, GetFormatArguments(dictionaryAdapter, property.Property.Name)).Trim(); + } + + #endregion + + private object[] GetFormatArguments(IDictionaryAdapter dictionaryAdapter, string formattedPropertyName) + { + var properties = Properties.Split(PropertyDelimeters, StringSplitOptions.RemoveEmptyEntries); + var arguments = new object[properties.Length]; + for (int i = 0; i < properties.Length; ++i) + { + var propertyName = properties[i]; + if (propertyName != formattedPropertyName) + { + arguments[i] = dictionaryAdapter.GetProperty(propertyName, false); + } + else + { + arguments[i] = "(recursive)"; + } + } + return arguments; + } + } +} \ No newline at end of file diff --git a/Castle.Core/Components.DictionaryAdapter/Attributes/StringListAttribute.cs b/Castle.Core/Components.DictionaryAdapter/Attributes/StringListAttribute.cs new file mode 100644 index 0000000..bd8e99b --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Attributes/StringListAttribute.cs @@ -0,0 +1,245 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.ComponentModel; + using System.Reflection; + using System.Text; + + /// + /// Identifies a property should be represented as a delimited string value. + /// + [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)] + public class StringListAttribute : DictionaryBehaviorAttribute, IDictionaryPropertyGetter, IDictionaryPropertySetter + { + public StringListAttribute() + { + Separator = ','; + } + + /// + /// Gets the separator. + /// + public char Separator { get; set; } + + #region IDictionaryPropertyGetter + + object IDictionaryPropertyGetter.GetPropertyValue(IDictionaryAdapter dictionaryAdapter, + string key, object storedValue, PropertyDescriptor property, bool ifExists) + { + var propertyType = property.PropertyType; + + if (storedValue == null || !storedValue.GetType().IsInstanceOfType(propertyType)) + { + if (propertyType.IsGenericType) + { + var genericDef = propertyType.GetGenericTypeDefinition(); + + if (genericDef == typeof(IList<>) || genericDef == typeof(ICollection<>) || + genericDef == typeof(List<>) || genericDef == typeof(IEnumerable<>)) + { + var paramType = propertyType.GetGenericArguments()[0]; + var converter = TypeDescriptor.GetConverter(paramType); + + if (converter != null && converter.CanConvertFrom(typeof(string))) + { + var genericList = typeof(StringListWrapper<>).MakeGenericType(new[] { paramType }); + return Activator.CreateInstance(genericList, key, storedValue, Separator, dictionaryAdapter.This.Dictionary); + } + } + } + } + + return storedValue; + } + + #endregion + + #region IDictionaryPropertySetter Members + + bool IDictionaryPropertySetter.SetPropertyValue(IDictionaryAdapter dictionaryAdapter, + string key, ref object value, PropertyDescriptor property) + { + var enumerable = value as IEnumerable; + if (enumerable != null) + { + value = BuildString(enumerable, Separator); + } + return true; + } + + #endregion + + internal static string BuildString(IEnumerable enumerable, char separator) + { + bool first = true; + var builder = new StringBuilder(); + + foreach (object item in enumerable) + { + if (first) + { + first = false; + } + else + { + builder.Append(separator); + } + + builder.Append(item.ToString()); + } + + return builder.ToString(); + } + + #region Nested Class: StringList + + class StringListWrapper : IList + { + private readonly string key; + private readonly char separator; + private readonly IDictionary dictionary; + private readonly List inner; + + public StringListWrapper(string key, string list, char separator, IDictionary dictionary) + { + this.key = key; + this.separator = separator; + this.dictionary = dictionary; + inner = new List(); + + ParseList(list); + } + + #region IList Members + + public int IndexOf(T item) + { + return inner.IndexOf(item); + } + + public void Insert(int index, T item) + { + inner.Insert(index, item); + SynchronizeDictionary(); + } + + public void RemoveAt(int index) + { + inner.RemoveAt(index); + SynchronizeDictionary(); + } + + public T this[int index] + { + get { return inner[index]; } + set + { + inner[index] = value; + SynchronizeDictionary(); + } + } + + #endregion + + #region ICollection Members + + public void Add(T item) + { + inner.Add(item); + SynchronizeDictionary(); + } + + public void Clear() + { + inner.Clear(); + SynchronizeDictionary(); + } + + public bool Contains(T item) + { + return inner.Contains(item); + } + + public void CopyTo(T[] array, int arrayIndex) + { + inner.CopyTo(array, arrayIndex); + } + + public int Count + { + get { return inner.Count; } + } + + public bool IsReadOnly + { + get { return false; } + } + + public bool Remove(T item) + { + if (inner.Remove(item)) + { + SynchronizeDictionary(); + return true; + } + return false; + } + + #endregion + + #region IEnumerable Members + + public IEnumerator GetEnumerator() + { + return inner.GetEnumerator(); + } + + #endregion + + #region IEnumerable Members + + IEnumerator IEnumerable.GetEnumerator() + { + return inner.GetEnumerator(); + } + + #endregion + + private void ParseList(string list) + { + if (list != null) + { + var converter = TypeDescriptor.GetConverter(typeof(T)); + + foreach (var item in list.Split(separator)) + { + inner.Add((T)converter.ConvertFrom(item)); + } + } + } + + private void SynchronizeDictionary() + { + dictionary[key] = StringListAttribute.BuildString(inner, separator); + } + } + } + + #endregion +} \ No newline at end of file diff --git a/Castle.Core/Components.DictionaryAdapter/Attributes/StringStorageAttribute.cs b/Castle.Core/Components.DictionaryAdapter/Attributes/StringStorageAttribute.cs new file mode 100644 index 0000000..32b77c6 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Attributes/StringStorageAttribute.cs @@ -0,0 +1,28 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"; +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System; + + [AttributeUsage(AttributeTargets.Interface | AttributeTargets.Property, AllowMultiple = false)] + public class StringStorageAttribute : DictionaryBehaviorAttribute, IDictionaryPropertySetter + { + public bool SetPropertyValue(IDictionaryAdapter dictionaryAdapter, string key, ref object value, PropertyDescriptor property) + { + value = (value != null) ? value.ToString() : null; + return true; + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Attributes/StringValuesAttribute.cs b/Castle.Core/Components.DictionaryAdapter/Attributes/StringValuesAttribute.cs new file mode 100644 index 0000000..84bb3d6 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Attributes/StringValuesAttribute.cs @@ -0,0 +1,58 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System; + + /// + /// Converts all properties to strings. + /// + [AttributeUsage(AttributeTargets.Interface | AttributeTargets.Property, AllowMultiple = false, Inherited = true)] + public class StringValuesAttribute : DictionaryBehaviorAttribute, IDictionaryPropertySetter + { + /// + /// Gets or sets the format. + /// + /// The format. + public string Format { get; set; } + + bool IDictionaryPropertySetter.SetPropertyValue(IDictionaryAdapter dictionaryAdapter, + string key, ref object value, PropertyDescriptor property) + { + if (value != null) + { + value = GetPropertyAsString(property, value); + } + return true; + } + + private string GetPropertyAsString(PropertyDescriptor property, object value) + { + if (string.IsNullOrEmpty(Format) == false) + { + return string.Format(Format, value); + } + + var converter = property.TypeConverter; + + if (converter != null && converter.CanConvertTo(typeof(string))) + { + return (string) converter.ConvertTo(value, typeof(string)); + } + + return value.ToString(); + } + } +} \ No newline at end of file diff --git a/Castle.Core/Components.DictionaryAdapter/Attributes/SuppressNotificationsAttribute.cs b/Castle.Core/Components.DictionaryAdapter/Attributes/SuppressNotificationsAttribute.cs new file mode 100644 index 0000000..3b9d78f --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Attributes/SuppressNotificationsAttribute.cs @@ -0,0 +1,30 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System; + + /// + /// Suppress property change notifications. + /// + [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] + public class SuppressNotificationsAttribute : DictionaryBehaviorAttribute, IPropertyDescriptorInitializer + { + public void Initialize(PropertyDescriptor propertyDescriptor, object[] behaviors) + { + propertyDescriptor.SuppressNotifications = true; + } + } +} \ No newline at end of file diff --git a/Castle.Core/Components.DictionaryAdapter/Attributes/TypeKeyPrefixAttribute.cs b/Castle.Core/Components.DictionaryAdapter/Attributes/TypeKeyPrefixAttribute.cs new file mode 100644 index 0000000..a0452a2 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Attributes/TypeKeyPrefixAttribute.cs @@ -0,0 +1,30 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System; + + /// + /// Assigns a prefix to the keyed properties using the interface name. + /// + [AttributeUsage(AttributeTargets.Interface, AllowMultiple = false, Inherited = true)] + public class TypeKeyPrefixAttribute : DictionaryBehaviorAttribute, IDictionaryKeyBuilder + { + string IDictionaryKeyBuilder.GetKey(IDictionaryAdapter dictionaryAdapter, string key, PropertyDescriptor property) + { + return string.Format("{0}#{1}", property.Property.DeclaringType.FullName, key); + } + } +} \ No newline at end of file diff --git a/Castle.Core/Components.DictionaryAdapter/Attributes/VolatileAttribute.cs b/Castle.Core/Components.DictionaryAdapter/Attributes/VolatileAttribute.cs new file mode 100644 index 0000000..a7e96ff --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Attributes/VolatileAttribute.cs @@ -0,0 +1,26 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System; + + /// + /// Indicates that underlying values are changeable and should not be cached. + /// + [AttributeUsage(AttributeTargets.Interface | AttributeTargets.Property, AllowMultiple = false)] + public class VolatileAttribute : Attribute + { + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Attributes/XPathAttribute.cs b/Castle.Core/Components.DictionaryAdapter/Attributes/XPathAttribute.cs new file mode 100644 index 0000000..c85ce5c --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Attributes/XPathAttribute.cs @@ -0,0 +1,57 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + + [AttributeUsage(AttributeTargets.Interface | AttributeTargets.Property, AllowMultiple = true)] + public class XPathAttribute : Attribute + { + private readonly CompiledXPath getPath; + private readonly CompiledXPath setPath; + + public XPathAttribute(string path) + { + if (path == null) + throw Error.ArgumentNull(nameof(path)); + + this.getPath = XPathCompiler.Compile(path); + this.setPath = this.getPath; + } + + public XPathAttribute(string get, string set) + { + if (get == null) + throw Error.ArgumentNull(nameof(get)); + if (set == null) + throw Error.ArgumentNull(nameof(set)); + + this.getPath = XPathCompiler.Compile(get); + this.setPath = XPathCompiler.Compile(set); + } + + public CompiledXPath GetPath + { + get { return getPath; } + } + + public CompiledXPath SetPath + { + get { return setPath; } + } + + public bool Nullable { get; set; } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Attributes/XPathFunctionAttribute.cs b/Castle.Core/Components.DictionaryAdapter/Attributes/XPathFunctionAttribute.cs new file mode 100644 index 0000000..19bf1a4 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Attributes/XPathFunctionAttribute.cs @@ -0,0 +1,38 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + using System.Xml.XPath; + using System.Xml.Xsl; + + [AttributeUsage(AttributeTargets.Interface | AttributeTargets.Property, AllowMultiple = true)] + public abstract class XPathFunctionAttribute : Attribute, IXsltContextFunction + { + protected XPathFunctionAttribute() { } + + public abstract XmlName Name { get; } + public abstract XPathResultType ReturnType { get; } + + public virtual XPathResultType[] ArgTypes { get { return NoArgs; } } + public virtual int Maxargs { get { return ArgTypes.Length; } } + public virtual int Minargs { get { return ArgTypes.Length; } } + + public static readonly XPathResultType[] + NoArgs = new XPathResultType[0]; + + public abstract object Invoke(XsltContext context, object[] args, XPathNavigator node); + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Attributes/XPathVariableAttribute.cs b/Castle.Core/Components.DictionaryAdapter/Attributes/XPathVariableAttribute.cs new file mode 100644 index 0000000..b64a53e --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Attributes/XPathVariableAttribute.cs @@ -0,0 +1,34 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + using System.Xml.XPath; + using System.Xml.Xsl; + + [AttributeUsage(AttributeTargets.Interface | AttributeTargets.Property, AllowMultiple = true)] + public abstract class XPathVariableAttribute : Attribute, IXsltContextVariable + { + protected XPathVariableAttribute() { } + + public abstract XmlName Name { get; } + public abstract XPathResultType VariableType { get; } + + bool IXsltContextVariable.IsLocal { get { return false; } } + bool IXsltContextVariable.IsParam { get { return false; } } + + public abstract object Evaluate(XsltContext context); + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Attributes/XmlDefaultsAttribute.cs b/Castle.Core/Components.DictionaryAdapter/Attributes/XmlDefaultsAttribute.cs new file mode 100644 index 0000000..ce5f74f --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Attributes/XmlDefaultsAttribute.cs @@ -0,0 +1,26 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System; + + [AttributeUsage(AttributeTargets.Interface)] + public class XmlDefaultsAttribute : Attribute + { + public bool Qualified { get; set; } + + public bool IsNullable { get; set; } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Attributes/XmlNamespaceAttribute.cs b/Castle.Core/Components.DictionaryAdapter/Attributes/XmlNamespaceAttribute.cs new file mode 100644 index 0000000..5e70e63 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Attributes/XmlNamespaceAttribute.cs @@ -0,0 +1,36 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System; + + [AttributeUsage(AttributeTargets.Interface | AttributeTargets.Property, AllowMultiple = true)] + public class XmlNamespaceAttribute : Attribute + { + public XmlNamespaceAttribute(string namespaceUri, string prefix) + { + NamespaceUri = namespaceUri; + Prefix = prefix; + } + + public bool Root { get; set; } + + public bool Default { get; set; } + + public string NamespaceUri { get; private set; } + + public string Prefix { get; private set; } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/CascadingDictionaryAdapter.cs b/Castle.Core/Components.DictionaryAdapter/CascadingDictionaryAdapter.cs new file mode 100644 index 0000000..d077ca2 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/CascadingDictionaryAdapter.cs @@ -0,0 +1,56 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System.Collections; + + public class CascadingDictionaryAdapter : AbstractDictionaryAdapter + { + private readonly IDictionary primary; + private readonly IDictionary secondary; + + public CascadingDictionaryAdapter(IDictionary primary, IDictionary secondary) + { + this.primary = primary; + this.secondary = secondary; + } + + public IDictionary Primary + { + get { return primary; } + } + + public IDictionary Secondary + { + get { return secondary; } + } + + public override bool IsReadOnly + { + get { return primary.IsReadOnly; } + } + + public override bool Contains(object key) + { + return primary.Contains(key) || secondary.Contains(key); + } + + public override object this[object key] + { + get { return primary[key] ?? secondary[key]; } + set { primary[key] = value; } + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/DefaultPropertyGetter.cs b/Castle.Core/Components.DictionaryAdapter/DefaultPropertyGetter.cs new file mode 100644 index 0000000..9153123 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/DefaultPropertyGetter.cs @@ -0,0 +1,74 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System.ComponentModel; + using System.Reflection; + + /// + /// Manages conversion between property values. + /// + public class DefaultPropertyGetter : IDictionaryPropertyGetter + { + private readonly TypeConverter converter; + + /// + /// Initializes a new instance of the class. + /// + /// The converter. + public DefaultPropertyGetter(TypeConverter converter) + { + this.converter = converter; + } + + /// + /// + /// + public int ExecutionOrder + { + get { return DictionaryBehaviorAttribute.LastExecutionOrder; } + } + + /// + /// Gets the effective dictionary value. + /// + /// The dictionary adapter. + /// The key. + /// The stored value. + /// The property. + /// true if return only existing. + /// The effective property value. + public object GetPropertyValue(IDictionaryAdapter dictionaryAdapter, + string key, object storedValue, PropertyDescriptor property, bool ifExists) + { + var propertyType = property.PropertyType; + + if (storedValue != null && propertyType.IsInstanceOfType(storedValue) == false) + { + if (converter != null && converter.CanConvertFrom(storedValue.GetType())) + { + return converter.ConvertFrom(storedValue); + } + } + + return storedValue; + } + + public IDictionaryBehavior Copy() + { + return this; + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterBase.Coerce.cs b/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterBase.Coerce.cs new file mode 100644 index 0000000..3dc6c92 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterBase.Coerce.cs @@ -0,0 +1,40 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System; + using System.Reflection; + + public abstract partial class DictionaryAdapterBase + { + public T Coerce() where T : class + { + return (T)Coerce(typeof(T)); + } + + public object Coerce(Type type) + { + if (type.IsAssignableFrom(Meta.Type)) + return this; + + if (This.CoerceStrategy != null) + { + var coerced = This.CoerceStrategy.Coerce(this, type); + if (coerced != null) return coerced; + } + return This.Factory.GetAdapter(type, This.Dictionary, This.Descriptor); + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterBase.Copy.cs b/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterBase.Copy.cs new file mode 100644 index 0000000..9ce75f8 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterBase.Copy.cs @@ -0,0 +1,56 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System; + using System.Linq; + using System.Reflection; + + public abstract partial class DictionaryAdapterBase + { + public void CopyTo(IDictionaryAdapter other) + { + CopyTo(other, null); + } + + public void CopyTo(IDictionaryAdapter other, Func selector) + { + if (ReferenceEquals(this, other)) + { + return; + } + + if (other.Meta.Type.IsAssignableFrom(Meta.Type) == false) + { + throw new ArgumentException(string.Format( + "Unable to copy to {0}. The type must be assignable from {1}.", + other.Meta.Type.FullName, Meta.Type.FullName)); + } + + if (This.CopyStrategies.Aggregate(false, (copied, s) => copied | s.Copy(this, other, ref selector))) + { + return; + } + + selector = selector ?? (property => true); + + foreach (var property in This.Properties.Values.Where(property => selector(property))) + { + var propertyValue = GetProperty(property.PropertyName, true); + other.SetProperty(property.PropertyName, ref propertyValue); + } + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterBase.Create.cs b/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterBase.Create.cs new file mode 100644 index 0000000..026689a --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterBase.Create.cs @@ -0,0 +1,61 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System; + using System.Collections; + using System.Collections.Specialized; + + public abstract partial class DictionaryAdapterBase : IDictionaryCreate + { + public T Create() + { + return Create(new HybridDictionary()); + } + + public object Create(Type type) + { + return Create(type, new HybridDictionary()); + } + + public T Create(IDictionary dictionary) + { + return (T)Create(typeof(T), dictionary ?? new HybridDictionary()); + } + + public object Create(Type type, IDictionary dictionary) + { + if (This.CreateStrategy != null) + { + var created = This.CreateStrategy.Create(this, type, dictionary); + if (created != null) return created; + } + dictionary = dictionary ?? new HybridDictionary(); + return This.Factory.GetAdapter(type, dictionary, This.Descriptor); + } + + public T Create(Action init) + { + return Create(new HybridDictionary(), init); + } + + public T Create(IDictionary dictionary, Action init) + { + var adapter = Create(dictionary ?? new HybridDictionary()); + if (init != null) init(adapter); + return adapter; + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterBase.Edit.cs b/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterBase.Edit.cs new file mode 100644 index 0000000..7286aa1 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterBase.Edit.cs @@ -0,0 +1,244 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System; + using System.Collections.Generic; + using System.ComponentModel; + using System.Linq; + using System.Reflection; + + public abstract partial class DictionaryAdapterBase + { + private int suppressEditingCount = 0; + private Stack> updates; + private HashSet editDependencies; + + struct Edit + { + public Edit(PropertyDescriptor property, object propertyValue) + { + Property = property; + PropertyValue = propertyValue; + } + public readonly PropertyDescriptor Property; + public object PropertyValue; + } + + public bool CanEdit + { + get { return suppressEditingCount == 0 && updates != null; } + set { updates = value ? new Stack>() : null; } + } + + public bool IsEditing + { + get { return CanEdit && updates != null && updates.Count > 0; } + } + + public bool SupportsMultiLevelEdit { get; set; } + + public bool IsChanged + { + get + { + if (IsEditing && updates.Any(level => level.Count > 0)) + return true; + + return This.Properties.Values + .Where(prop => typeof(IChangeTracking).IsAssignableFrom(prop.PropertyType)) + .Select(prop => GetProperty(prop.PropertyName, true)) + .Cast().Any(track => track != null && track.IsChanged); + } + } + + public void BeginEdit() + { + if (CanEdit && (IsEditing == false || SupportsMultiLevelEdit)) + { + updates.Push(new Dictionary()); + } + } + + public void CancelEdit() + { + if (IsEditing) + { + if (editDependencies != null) + { + foreach (var editDependency in editDependencies.ToArray()) + { + editDependency.CancelEdit(); + } + editDependencies.Clear(); + } + + using (SuppressEditingBlock()) + { + using (TrackReadonlyPropertyChanges()) + { + var top = updates.Peek(); + + if (top.Count > 0) + { + foreach (var update in top.Values) + { + var existing = update; + existing.PropertyValue = GetProperty(existing.Property.PropertyName, true); + } + + updates.Pop(); + + foreach (var update in top.Values.ToArray()) + { + var oldValue = update.PropertyValue; + var newValue = GetProperty(update.Property.PropertyName, true); + + if (!object.Equals(oldValue, newValue)) + { + + NotifyPropertyChanging(update.Property, oldValue, newValue); + NotifyPropertyChanged(update.Property, oldValue, newValue); + + } + } + } + } + } + } + } + + public void EndEdit() + { + if (IsEditing) + { + using (SuppressEditingBlock()) + { + var top = updates.Pop(); + + if (top.Count > 0) foreach (var update in top.ToArray()) + { + StoreProperty(null, update.Key, update.Value.PropertyValue); + } + } + + if (editDependencies != null) + { + foreach (var editDependency in editDependencies.ToArray()) + { + editDependency.EndEdit(); + } + editDependencies.Clear(); + } + } + } + + public void RejectChanges() + { + CancelEdit(); + } + + public void AcceptChanges() + { + EndEdit(); + } + + public IDisposable SuppressEditingBlock() + { + return new SuppressEditingScope(this); + } + + public void SuppressEditing() + { + ++suppressEditingCount; + } + + public void ResumeEditing() + { + --suppressEditingCount; + } + + protected bool GetEditedProperty(string propertyName, out object propertyValue) + { + if (updates != null) foreach (var level in updates.ToArray()) + { + Edit edit; + if (level.TryGetValue(propertyName, out edit)) + { + propertyValue = edit.PropertyValue; + return true; + } + } + propertyValue = null; + return false; + } + + protected bool EditProperty(PropertyDescriptor property, string key, object propertyValue) + { + if (IsEditing) + { + updates.Peek()[key] = new Edit(property, propertyValue); + return true; + } + return false; + } + + protected bool ClearEditProperty(PropertyDescriptor property, string key) + { + if (IsEditing) + { + updates.Peek().Remove(key); + return true; + } + return false; + } + + protected void AddEditDependency(IEditableObject editDependency) + { + if (IsEditing) + { + if (editDependencies == null) + { + editDependencies = new HashSet(); + } + + if (editDependencies.Add(editDependency)) + { + editDependency.BeginEdit(); + } + } + } + + #region Nested Class: SuppressEditingScope + + class SuppressEditingScope : IDisposable + { + private readonly DictionaryAdapterBase adapter; + + public SuppressEditingScope(DictionaryAdapterBase adapter) + { + this.adapter = adapter; + this.adapter.SuppressEditing(); + } + + public void Dispose() + { + adapter.ResumeEditing(); + } + } + + #endregion + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterBase.Notify.cs b/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterBase.Notify.cs new file mode 100644 index 0000000..2b0262a --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterBase.Notify.cs @@ -0,0 +1,215 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System; + using System.Collections.Generic; + using System.ComponentModel; + using System.Linq; + + public abstract partial class DictionaryAdapterBase + { + [ThreadStatic] + private static TrackPropertyChangeScope readOnlyTrackingScope; + + private int suppressNotificationCount = 0; + + public event PropertyChangingEventHandler PropertyChanging; + public event PropertyChangedEventHandler PropertyChanged; + + public bool CanNotify { get; set; } + + public bool ShouldNotify + { + get { return CanNotify && suppressNotificationCount == 0; } + } + + public IDisposable SuppressNotificationsBlock() + { + return new NotificationSuppressionScope(this); + } + + public void SuppressNotifications() + { + ++suppressNotificationCount; + } + + public void ResumeNotifications() + { + --suppressNotificationCount; + } + + protected bool NotifyPropertyChanging(PropertyDescriptor property, object oldValue, object newValue) + { + if (property.SuppressNotifications || !ShouldNotify) + return true; + + var propertyChanging = PropertyChanging; + if (propertyChanging == null) + return true; + + var args = new PropertyChangingEventArgsEx(property.PropertyName, oldValue, newValue); + propertyChanging(this, args); + return !args.Cancel; + } + + protected void NotifyPropertyChanged(PropertyDescriptor property, object oldValue, object newValue) + { + if (property.SuppressNotifications || !ShouldNotify) + return; + + var propertyChanged = PropertyChanged; + if (propertyChanged == null) + return; + + propertyChanged(this, new PropertyChangedEventArgsEx(property.PropertyName, oldValue, newValue)); + } + + protected void NotifyPropertyChanged(string propertyName) + { + if (!ShouldNotify) + return; + + var propertyChanged = PropertyChanged; + if (propertyChanged == null) + return; + + propertyChanged(this, new PropertyChangedEventArgs(propertyName)); + } + + protected TrackPropertyChangeScope TrackPropertyChange(PropertyDescriptor property, + object oldValue, object newValue) + { + if (!ShouldNotify || property.SuppressNotifications) + return null; + + return new TrackPropertyChangeScope(this, property, oldValue); + } + + protected TrackPropertyChangeScope TrackReadonlyPropertyChanges() + { + if (!ShouldNotify || readOnlyTrackingScope != null) + return null; + + return readOnlyTrackingScope = new TrackPropertyChangeScope(this); + } + + private class NotificationSuppressionScope : IDisposable + { + private readonly DictionaryAdapterBase adapter; + + public NotificationSuppressionScope(DictionaryAdapterBase adapter) + { + this.adapter = adapter; + this.adapter.SuppressNotifications(); + } + + public void Dispose() + { + this.adapter.ResumeNotifications(); + } + } + + public class TrackPropertyChangeScope : IDisposable + { + private readonly DictionaryAdapterBase adapter; + private readonly PropertyDescriptor property; + private readonly object existingValue; + private Dictionary readOnlyProperties; + + public TrackPropertyChangeScope(DictionaryAdapterBase adapter) + { + this.adapter = adapter; + this.readOnlyProperties = adapter.This.Properties.Values + .Where( + pd => !pd.Property.CanWrite || pd.IsDynamicProperty + ) + .ToDictionary( + pd => pd, + pd => GetEffectivePropertyValue(pd) + ); + } + + public TrackPropertyChangeScope(DictionaryAdapterBase adapter, PropertyDescriptor property, object existingValue) + : this(adapter) + { + this.property = property; + this.existingValue = existingValue; + existingValue = adapter.GetProperty(property.PropertyName, true); // TODO: This looks unnecessary + } + + public void Dispose() + { + Notify(); + } + + public bool Notify() + { + if (readOnlyTrackingScope == this) + { + readOnlyTrackingScope = null; + return NotifyReadonly(); + } + + var newValue = GetEffectivePropertyValue(property); + + if (!NotifyIfChanged(property, existingValue, newValue)) + return false; + + if (readOnlyTrackingScope == null) + NotifyReadonly(); + + return true; + } + + private bool NotifyReadonly() + { + var changed = false; + + foreach (var readOnlyProperty in readOnlyProperties) + { + var descriptor = readOnlyProperty.Key; + var currentValue = GetEffectivePropertyValue(descriptor); + changed |= NotifyIfChanged(descriptor, readOnlyProperty.Value, currentValue); + } + + adapter.Invalidate(); + return changed; + } + + private bool NotifyIfChanged(PropertyDescriptor descriptor, object oldValue, object newValue) + { + if (Equals(oldValue, newValue)) + return false; + + adapter.NotifyPropertyChanged(descriptor, oldValue, newValue); + return true; + } + + private object GetEffectivePropertyValue(PropertyDescriptor property) + { + var value = adapter.GetProperty(property.PropertyName, true); + if (value == null || !property.IsDynamicProperty) + return value; + + var dynamicValue = value as IDynamicValue; + if (dynamicValue == null) + return value; + + return dynamicValue.GetValue(); + } + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterBase.Validate.cs b/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterBase.Validate.cs new file mode 100644 index 0000000..e8fb683 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterBase.Validate.cs @@ -0,0 +1,105 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System; + using System.Collections.Generic; + using System.Linq; + + public partial class DictionaryAdapterBase : IDictionaryValidate + { + private ICollection validators; + + public bool CanValidate { get; set; } + + public bool IsValid + { + get + { + if (CanValidate && validators != null) + { + return !validators.Any(v => !v.IsValid(this)); + } + return !CanValidate; + } + } + + public string Error + { + get + { + if (CanValidate && validators != null) + { + return string.Join(Environment.NewLine, validators.Select( + v => v.Validate(this)).Where(e => !string.IsNullOrEmpty(e)).ToArray()); + } + return string.Empty; + } + } + + public string this[string columnName] + { + get + { + if (CanValidate && validators != null) + { + PropertyDescriptor property; + if (This.Properties.TryGetValue(columnName, out property)) + { + return string.Join(Environment.NewLine, validators.Select( + v => v.Validate(this, property)).Where(e => !string.IsNullOrEmpty(e)) + .ToArray()); + } + } + return string.Empty; + } + } + + public DictionaryValidateGroup ValidateGroups(params object[] groups) + { + return new DictionaryValidateGroup(groups, this); + } + + public IEnumerable Validators + { + get + { + return validators ?? Enumerable.Empty(); + } + } + + public void AddValidator(IDictionaryValidator validator) + { + if (validators == null) + { + validators = new HashSet(); + } + validators.Add(validator); + } + + protected internal void Invalidate() + { + if (CanValidate) + { + if (validators != null) foreach (var validator in validators) + { + validator.Invalidate(this); + } + + NotifyPropertyChanged("IsValid"); + } + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterBase.cs b/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterBase.cs new file mode 100644 index 0000000..184f4e6 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterBase.cs @@ -0,0 +1,216 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System.Collections; + using System.ComponentModel; + using System.Linq; + using System.Reflection; + + public abstract partial class DictionaryAdapterBase : IDictionaryAdapter + { + public DictionaryAdapterBase(DictionaryAdapterInstance instance) + { + This = instance; + + CanEdit = typeof(IEditableObject).IsAssignableFrom(Meta.Type); + CanNotify = typeof(INotifyPropertyChanged).IsAssignableFrom(Meta.Type); + CanValidate = typeof(IDataErrorInfo).IsAssignableFrom(Meta.Type); + + Initialize(); + } + + public abstract DictionaryAdapterMeta Meta { get; } + + public DictionaryAdapterInstance This { get; private set; } + + public string GetKey(string propertyName) + { + PropertyDescriptor descriptor; + if (This.Properties.TryGetValue(propertyName, out descriptor)) + { + return descriptor.GetKey(this, propertyName, This.Descriptor); + } + return null; + } + + public virtual object GetProperty(string propertyName, bool ifExists) + { + PropertyDescriptor descriptor; + if (This.Properties.TryGetValue(propertyName, out descriptor)) + { + var propertyValue = descriptor.GetPropertyValue(this, propertyName, null, This.Descriptor, ifExists); + if (propertyValue is IEditableObject) + { + AddEditDependency((IEditableObject)propertyValue); + } + return propertyValue; + } + return null; + } + + public T GetPropertyOfType(string propertyName) + { + var propertyValue = GetProperty(propertyName, false); + return propertyValue != null ? (T)propertyValue : default(T); + } + + public object ReadProperty(string key) + { + object propertyValue = null; + if (GetEditedProperty(key, out propertyValue) == false) + { + var dictionary = GetDictionary(This.Dictionary, ref key); + if (dictionary != null) propertyValue = dictionary[key]; + } + return propertyValue; + } + + public virtual bool SetProperty(string propertyName, ref object value) + { + bool stored = false; + + PropertyDescriptor descriptor; + if (This.Properties.TryGetValue(propertyName, out descriptor)) + { + if (ShouldNotify == false) + { + stored = descriptor.SetPropertyValue(this, propertyName, ref value, This.Descriptor); + Invalidate(); + return stored; + } + + var existingValue = GetProperty(propertyName, true); + if (NotifyPropertyChanging(descriptor, existingValue, value) == false) + { + return false; + } + + var trackPropertyChange = TrackPropertyChange(descriptor, existingValue, value); + + stored = descriptor.SetPropertyValue(this, propertyName, ref value, This.Descriptor); + + if (stored && trackPropertyChange != null) + { + trackPropertyChange.Notify(); + } + } + + return stored; + } + + public void StoreProperty(PropertyDescriptor property, string key, object value) + { + if (property == null || EditProperty(property, key, value) == false) + { + var dictionary = GetDictionary(This.Dictionary, ref key); + if (dictionary != null) dictionary[key] = value; + } + } + + public void ClearProperty(PropertyDescriptor property, string key) + { + key = key ?? GetKey(property.PropertyName); + if (property == null || ClearEditProperty(property, key) == false) + { + var dictionary = GetDictionary(This.Dictionary, ref key); + if (dictionary != null) dictionary.Remove(key); + } + } + + public bool ShouldClearProperty(PropertyDescriptor property, object value) + { + return property == null || + property.Setters.OfType().Where(remove => remove.ShouldRemove(value)).Any(); + } + + public override bool Equals(object obj) + { + var other = obj as IDictionaryAdapter; + + if (other == null) + { + return false; + } + + if (ReferenceEquals(this, obj)) + { + return true; + } + + if (Meta.Type != other.Meta.Type) + { + return false; + } + + if (This.EqualityHashCodeStrategy != null) + { + return This.EqualityHashCodeStrategy.Equals(this, other); + } + + return base.Equals(obj); + } + + public override int GetHashCode() + { + if (This.OldHashCode.HasValue) + { + return This.OldHashCode.Value; + } + + int hashCode; + if (This.EqualityHashCodeStrategy == null || + This.EqualityHashCodeStrategy.GetHashCode(this, out hashCode) == false) + { + hashCode = base.GetHashCode(); + } + + This.OldHashCode = hashCode; + return hashCode; + } + + protected void Initialize() + { + var metaBehaviors = Meta.Behaviors; + var initializers = This.Initializers; + + foreach (var initializer in initializers) + { + initializer.Initialize(this, metaBehaviors); + } + + foreach (var property in This.Properties.Values) + { + if (property.Fetch) + GetProperty(property.PropertyName, false); + } + } + + private static IDictionary GetDictionary(IDictionary dictionary, ref string key) + { + if (key.StartsWith("!") == false) + { + var parts = key.Split(','); + for (var i = 0; i < parts.Length - 1; ++i) + { + dictionary = dictionary[parts[i]] as IDictionary; + if (dictionary == null) return null; + } + key = parts[parts.Length - 1]; + } + return dictionary; + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterExtensions.cs b/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterExtensions.cs new file mode 100644 index 0000000..3a977fb --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterExtensions.cs @@ -0,0 +1,29 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System.Linq; + + public static class DictionaryAdapterExtensions + { + public static IVirtual AsVirtual(this IDictionaryAdapter dictionaryAdapter) + { + var descriptor = dictionaryAdapter.This.Descriptor; + return descriptor != null + ? descriptor.Getters.OfType().FirstOrDefault() + : null; + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterFactory.cs b/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterFactory.cs new file mode 100644 index 0000000..a2cb08a --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterFactory.cs @@ -0,0 +1,495 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.Collections.Specialized; + using System.ComponentModel; + using System.Linq; + using System.Reflection; + using System.Reflection.Emit; + using System.Threading; + using System.Diagnostics; + + using Castle.Components.DictionaryAdapter.Xml; + using Castle.Core.Internal; + + /// + /// Uses Reflection.Emit to expose the properties of a dictionary + /// through a dynamic implementation of a typed interface. + /// + public class DictionaryAdapterFactory : IDictionaryAdapterFactory + { + private readonly SynchronizedDictionary interfaceToMeta = + new SynchronizedDictionary(); + + #region IDictionaryAdapterFactory + + /// + public T GetAdapter(IDictionary dictionary) + { + return (T) GetAdapter(typeof(T), dictionary); + } + + /// + public object GetAdapter(Type type, IDictionary dictionary) + { + return InternalGetAdapter(type, dictionary, null); + } + + /// + public object GetAdapter(Type type, IDictionary dictionary, PropertyDescriptor descriptor) + { + return InternalGetAdapter(type, dictionary, descriptor); + } + + /// + public T GetAdapter(IDictionary dictionary) + { + return (T) GetAdapter(typeof(T), dictionary); + } + + /// + public object GetAdapter(Type type, IDictionary dictionary) + { + var adapter = new GenericDictionaryAdapter(dictionary); + return InternalGetAdapter(type, adapter, null); + } + + /// + public T GetAdapter(NameValueCollection nameValues) + { + return GetAdapter(new NameValueCollectionAdapter(nameValues)); + } + + /// + public object GetAdapter(Type type, NameValueCollection nameValues) + { + return GetAdapter(type, new NameValueCollectionAdapter(nameValues)); + } + + /// + public T GetAdapter(System.Xml.XmlNode xmlNode) + { + return (T)GetAdapter(typeof(T), xmlNode); + } + + /// + public object GetAdapter(Type type, System.Xml.XmlNode xmlNode) + { + var xml = new XmlAdapter(xmlNode); + return GetAdapter(type, new Hashtable(), new PropertyDescriptor() + .AddBehavior(XmlMetadataBehavior.Default) + .AddBehavior(xml)); + } + + /// + public DictionaryAdapterMeta GetAdapterMeta(Type type) + { + return GetAdapterMeta(type, null as PropertyDescriptor); + } + + /// + public DictionaryAdapterMeta GetAdapterMeta(Type type, PropertyDescriptor descriptor) + { + return InternalGetAdapterMeta(type, descriptor, null); + } + + /// + public DictionaryAdapterMeta GetAdapterMeta(Type type, DictionaryAdapterMeta other) + { + return InternalGetAdapterMeta(type, null, other); + } + + #endregion + + private DictionaryAdapterMeta InternalGetAdapterMeta(Type type, + PropertyDescriptor descriptor, DictionaryAdapterMeta other) + { + if (type == null) + throw new ArgumentNullException(nameof(type)); + if (type.IsInterface == false) + throw new ArgumentException("Only interfaces can be adapted to a dictionary", nameof(type)); + + return interfaceToMeta.GetOrAdd(type, t => + { + if (descriptor == null && other != null) + { + descriptor = other.CreateDescriptor(); + } + + var typeBuilder = CreateTypeBuilder(type); + return CreateAdapterMeta(type, typeBuilder, descriptor); + }); + } + + private object InternalGetAdapter(Type type, IDictionary dictionary, PropertyDescriptor descriptor) + { + var meta = InternalGetAdapterMeta(type, descriptor, null); + return meta.CreateInstance(dictionary, descriptor); + } + + #region Type Builders + + private static TypeBuilder CreateTypeBuilder(Type type) + { + var assemblyName = new AssemblyName("CastleDictionaryAdapterAssembly"); + var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); + var moduleBuilder = assemblyBuilder.DefineDynamicModule("CastleDictionaryAdapterModule"); + return CreateAdapterType(type, moduleBuilder); + } + + private static TypeBuilder CreateAdapterType(Type type, ModuleBuilder moduleBuilder) + { + var typeBuilder = moduleBuilder.DefineType("CastleDictionaryAdapterType", + TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.BeforeFieldInit); + typeBuilder.AddInterfaceImplementation(type); + typeBuilder.SetParent(typeof(DictionaryAdapterBase)); + + var attribCtorParams = new[] { typeof(Type) }; + var attribCtorInfo = typeof(DictionaryAdapterAttribute).GetConstructor(attribCtorParams); + var attribBuilder = new CustomAttributeBuilder(attribCtorInfo, new[] { type }); + typeBuilder.SetCustomAttribute(attribBuilder); + + var debugAttribCtorParams = new[] { typeof(string) }; + var debugAttribCtorInfo = typeof(DebuggerDisplayAttribute).GetConstructor(debugAttribCtorParams); + var debugAttribBuilder = new CustomAttributeBuilder(debugAttribCtorInfo, new[] { "Type: {Meta.Type.FullName,nq}" }); + typeBuilder.SetCustomAttribute(debugAttribBuilder); + return typeBuilder; + } + + private DictionaryAdapterMeta CreateAdapterMeta(Type type, TypeBuilder typeBuilder, PropertyDescriptor descriptor) + { + var binding = FieldAttributes.Public | FieldAttributes.Static; + var metaField = typeBuilder.DefineField("__meta", typeof(DictionaryAdapterMeta), binding); + var constructor = CreateAdapterConstructor(typeBuilder); + CreateAdapterFactoryMethod(typeBuilder, constructor); + + object[] typeBehaviors; + var initializers = new PropertyDescriptor(); + var propertyMap = GetPropertyDescriptors(type, initializers, out typeBehaviors); + + if (descriptor != null) + { + initializers.AddBehaviors(descriptor.MetaInitializers); + typeBehaviors = typeBehaviors.Union(descriptor.Annotations).ToArray(); + } + + CreateMetaProperty(typeBuilder, AdapterGetMeta, metaField); + + foreach (var property in propertyMap) + { + CreateAdapterProperty(typeBuilder, property.Value); + } + + var implementation = typeBuilder.CreateTypeInfo(); + var creator = (Func)implementation + .GetDeclaredMethod("__Create") + .CreateDelegate(typeof(Func)); + + var meta = new DictionaryAdapterMeta(type, implementation, typeBehaviors, + initializers.MetaInitializers.ToArray(), initializers.Initializers.ToArray(), + propertyMap, this, creator); + + const BindingFlags metaBindings = BindingFlags.Public | BindingFlags.Static; + var field = implementation.GetField("__meta", metaBindings); + field.SetValue(implementation, meta); + return meta; + } + + private static readonly PropertyInfo AdapterGetMeta = typeof(IDictionaryAdapter).GetProperty("Meta"); + + #endregion + + #region Constructors + + private static ConstructorInfo CreateAdapterConstructor(TypeBuilder typeBuilder) + { + var constructorBuilder = typeBuilder.DefineConstructor( + MethodAttributes.Public | MethodAttributes.HideBySig, CallingConventions.Standard, + ConstructorParameterTypes + ); + + var ilGenerator = constructorBuilder.GetILGenerator(); + + ilGenerator.Emit(OpCodes.Ldarg_0); + ilGenerator.Emit(OpCodes.Ldarg_1); + ilGenerator.Emit(OpCodes.Call, BaseCtor); + ilGenerator.Emit(OpCodes.Ret); + + return constructorBuilder; + } + + private static void CreateAdapterFactoryMethod(TypeBuilder typeBuilder, ConstructorInfo constructor) + { + var factoryBuilder = typeBuilder.DefineMethod + ( + "__Create", + MethodAttributes.Public | MethodAttributes.Static | MethodAttributes.HideBySig, + typeof(IDictionaryAdapter), + ConstructorParameterTypes + ); + + var ilGenerator = factoryBuilder.GetILGenerator(); + ilGenerator.Emit(OpCodes.Ldarg_0); + ilGenerator.Emit(OpCodes.Newobj, constructor); + ilGenerator.Emit(OpCodes.Ret); + } + + private static readonly ConstructorInfo BaseCtor = typeof(DictionaryAdapterBase).GetConstructors()[0]; + private static readonly Type[] ConstructorParameterTypes = { typeof(DictionaryAdapterInstance) }; + + #endregion + + #region Properties + + private static void CreateMetaProperty(TypeBuilder typeBuilder, PropertyInfo prop, FieldInfo field) + { + const MethodAttributes propAttribs = MethodAttributes.Public | MethodAttributes.SpecialName | + MethodAttributes.HideBySig | MethodAttributes.ReuseSlot | + MethodAttributes.Virtual | MethodAttributes.Final; + + var getMethodBuilder = typeBuilder.DefineMethod("get_" + prop.Name, propAttribs, prop.PropertyType, null); + + var getILGenerator = getMethodBuilder.GetILGenerator(); + if (field.IsStatic) + { + getILGenerator.Emit(OpCodes.Ldsfld, field); + } + else + { + getILGenerator.Emit(OpCodes.Ldarg_0); + getILGenerator.Emit(OpCodes.Ldfld, field); + } + getILGenerator.Emit(OpCodes.Ret); + + typeBuilder.DefineMethodOverride(getMethodBuilder, prop.GetGetMethod()); + } + + private static void CreateAdapterProperty(TypeBuilder typeBuilder, PropertyDescriptor descriptor) + { + var property = descriptor.Property; + var propertyBuilder = typeBuilder.DefineProperty(property.Name, property.Attributes, property.PropertyType, null); + const MethodAttributes propAttribs = MethodAttributes.Public | MethodAttributes.SpecialName | + MethodAttributes.HideBySig | MethodAttributes.Virtual; + + if (property.CanRead) + { + CreatePropertyGetMethod(typeBuilder, propertyBuilder, descriptor, propAttribs); + } + + if (property.CanWrite) + { + CreatePropertySetMethod(typeBuilder, propertyBuilder, descriptor, propAttribs); + } + } + + private static void PreparePropertyMethod(PropertyDescriptor descriptor, ILGenerator propILGenerator) + { + propILGenerator.DeclareLocal(typeof(string)); + propILGenerator.DeclareLocal(typeof(object)); + + // key = propertyInfo.Name + propILGenerator.Emit(OpCodes.Ldstr, descriptor.PropertyName); + propILGenerator.Emit(OpCodes.Stloc_0); + } + + #endregion + + #region Getters + + private static void CreatePropertyGetMethod(TypeBuilder typeBuilder, PropertyBuilder propertyBuilder, + PropertyDescriptor descriptor, MethodAttributes propAttribs) + { + var getMethodBuilder = typeBuilder.DefineMethod("get_" + descriptor.PropertyName, propAttribs, descriptor.PropertyType, null); + var getILGenerator = getMethodBuilder.GetILGenerator(); + var returnDefault = getILGenerator.DefineLabel(); + var storeResult = getILGenerator.DefineLabel(); + var loadResult = getILGenerator.DefineLabel(); + + PreparePropertyMethod(descriptor, getILGenerator); + + var result = getILGenerator.DeclareLocal(descriptor.PropertyType); + + // value = GetProperty(key, false) + getILGenerator.Emit(OpCodes.Ldarg_0); + getILGenerator.Emit(OpCodes.Ldloc_0); + getILGenerator.Emit(OpCodes.Ldc_I4_0); + getILGenerator.Emit(OpCodes.Callvirt, AdapterGetProperty); + getILGenerator.Emit(OpCodes.Stloc_1); + + // if (value == null) return null + getILGenerator.Emit(OpCodes.Ldloc_1); + getILGenerator.Emit(OpCodes.Brfalse_S, returnDefault); + + // return (propertyInfo.PropertyType) value + getILGenerator.Emit(OpCodes.Ldloc_1); + getILGenerator.Emit(OpCodes.Unbox_Any, descriptor.PropertyType); + getILGenerator.Emit(OpCodes.Br_S, storeResult); + + getILGenerator.MarkLabel(returnDefault); + getILGenerator.Emit(OpCodes.Ldloca_S, result); + getILGenerator.Emit(OpCodes.Initobj, descriptor.PropertyType); + getILGenerator.Emit(OpCodes.Br_S, loadResult); + + getILGenerator.MarkLabel(storeResult); + getILGenerator.Emit(OpCodes.Stloc_S, result); + + getILGenerator.MarkLabel(loadResult); + getILGenerator.Emit(OpCodes.Ldloc_S, result); + getILGenerator.Emit(OpCodes.Ret); + + propertyBuilder.SetGetMethod(getMethodBuilder); + } + + private static readonly MethodInfo AdapterGetProperty = typeof(IDictionaryAdapter).GetMethod("GetProperty"); + + #endregion + + #region Setters + + private static void CreatePropertySetMethod(TypeBuilder typeBuilder, PropertyBuilder propertyBuilder, + PropertyDescriptor descriptor, MethodAttributes propAttribs) + { + var setMethodBuilder = typeBuilder.DefineMethod("set_" + descriptor.PropertyName, propAttribs, null, new[] {descriptor.PropertyType}); + var setILGenerator = setMethodBuilder.GetILGenerator(); + PreparePropertyMethod(descriptor, setILGenerator); + + setILGenerator.Emit(OpCodes.Ldarg_1); + if (descriptor.PropertyType.IsValueType) + { + setILGenerator.Emit(OpCodes.Box, descriptor.PropertyType); + } + setILGenerator.Emit(OpCodes.Stloc_1); + + // ignore = SetProperty(key, ref value) + setILGenerator.Emit(OpCodes.Ldarg_0); + setILGenerator.Emit(OpCodes.Ldloc_0); + setILGenerator.Emit(OpCodes.Ldloca_S, 1); + setILGenerator.Emit(OpCodes.Callvirt, AdapterSetProperty); + setILGenerator.Emit(OpCodes.Pop); + setILGenerator.Emit(OpCodes.Ret); + + propertyBuilder.SetSetMethod(setMethodBuilder); + } + + private static readonly MethodInfo AdapterSetProperty = typeof(IDictionaryAdapter).GetMethod("SetProperty"); + + #endregion + + #region Descriptors + + private static Dictionary GetPropertyDescriptors(Type type, PropertyDescriptor initializers, out object[] typeBehaviors) + { + var propertyMap = new Dictionary(); + var interfaceBehaviors = typeBehaviors = ExpandBehaviors(InterfaceAttributeUtil.GetAttributes(type, true)).ToArray(); + var defaultFetch = typeBehaviors.OfType().Select(b => (bool?)b.Fetch).FirstOrDefault().GetValueOrDefault(); + + initializers.AddBehaviors(typeBehaviors.OfType()) + .AddBehaviors(typeBehaviors.OfType()); + + CollectProperties(type, (property, reflectedType) => + { + var propertyBehaviors = ExpandBehaviors(property.GetCustomAttributes(false)).ToArray(); + var propertyDescriptor = new PropertyDescriptor(property, propertyBehaviors) + .AddBehaviors(propertyBehaviors.OfType()) + .AddBehaviors(interfaceBehaviors.OfType().Where(b => b is IDictionaryKeyBuilder == false)); + var expandedBehaviors = ExpandBehaviors(InterfaceAttributeUtil + .GetAttributes(reflectedType, true)) + .OfType(); + propertyDescriptor = propertyDescriptor.AddBehaviors(expandedBehaviors); + + AddDefaultGetter(propertyDescriptor); + + var propertyFetch = propertyBehaviors.OfType().Select(b => (bool?)b.Fetch).FirstOrDefault(); + propertyDescriptor.IfExists = propertyBehaviors.OfType().Any(); + propertyDescriptor.Fetch = propertyFetch.GetValueOrDefault(defaultFetch); + + foreach (var descriptorInitializer in propertyDescriptor.Behaviors.OfType()) + { + descriptorInitializer.Initialize(propertyDescriptor, propertyBehaviors); + } + + initializers.AddBehaviors(propertyBehaviors.OfType()); + + PropertyDescriptor existingDescriptor; + if (propertyMap.TryGetValue(property.Name, out existingDescriptor)) + { + var existingProperty = existingDescriptor.Property; + if (existingProperty.PropertyType == property.PropertyType) + { + if (property.CanRead && property.CanWrite) + { + propertyMap[property.Name] = propertyDescriptor; + } + return; + } + } + + propertyMap.Add(property.Name, propertyDescriptor); + }); + + return propertyMap; + } + + private static IEnumerable ExpandBehaviors(IEnumerable behaviors) + { + foreach (var behavior in behaviors) + { + if (behavior is IDictionaryBehaviorBuilder) + { + foreach (var build in ((IDictionaryBehaviorBuilder)behavior).BuildBehaviors()) + yield return build; + } + else + { + yield return behavior; + } + } + } + + private static void CollectProperties(Type currentType, Action onProperty) + { + var types = new List(); + types.Add(currentType); + types.AddRange(currentType.GetInterfaces()); + const BindingFlags publicBindings = BindingFlags.Public | BindingFlags.Instance; + + foreach (var reflectedType in types.Where(t => InfrastructureTypes.Contains(t) == false)) + foreach (var property in reflectedType.GetProperties(publicBindings)) + { + onProperty(property, reflectedType); + } + } + + private static void AddDefaultGetter(PropertyDescriptor descriptor) + { + if (descriptor.TypeConverter != null) + descriptor.AddBehavior(new DefaultPropertyGetter(descriptor.TypeConverter)); + } + + private static readonly HashSet InfrastructureTypes = new HashSet + { + typeof (IEditableObject), typeof (IDictionaryEdit), typeof (IChangeTracking), + typeof (IRevertibleChangeTracking), typeof (IDictionaryNotify), + typeof (IDataErrorInfo), + typeof (IDictionaryValidate), typeof (IDictionaryAdapter) + }; + + #endregion + } +} \ No newline at end of file diff --git a/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterInstance.cs b/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterInstance.cs new file mode 100644 index 0000000..e97b08a --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterInstance.cs @@ -0,0 +1,154 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.Linq; + using Castle.Core; + + public class DictionaryAdapterInstance + { + private IDictionary extendedProperties; + private List copyStrategies; + + public DictionaryAdapterInstance(IDictionary dictionary, DictionaryAdapterMeta meta, + PropertyDescriptor descriptor, IDictionaryAdapterFactory factory) + { + Dictionary = dictionary; + Descriptor = descriptor; + Factory = factory; + + List behaviors; + + if (null == descriptor || null == (behaviors = descriptor.BehaviorsInternal)) + { + Initializers = meta.Initializers; + Properties = MergeProperties(meta.Properties); + } + else + { + Initializers = MergeInitializers(meta.Initializers, behaviors); + Properties = MergeProperties(meta.Properties, behaviors); + } + } + + internal int? OldHashCode { get; set; } + + public IDictionary Dictionary { get; private set; } + + public PropertyDescriptor Descriptor { get; private set; } + + public IDictionaryAdapterFactory Factory { get; private set; } + + public IDictionaryInitializer[] Initializers { get; private set; } + + public IDictionary Properties { get; private set; } + + public IDictionaryEqualityHashCodeStrategy EqualityHashCodeStrategy { get; set; } + + public IDictionaryCreateStrategy CreateStrategy { get; set; } + + public IDictionaryCoerceStrategy CoerceStrategy { get; set; } + + public IEnumerable CopyStrategies + { + get + { + return copyStrategies ?? Enumerable.Empty(); + } + } + + public void AddCopyStrategy(IDictionaryCopyStrategy copyStrategy) + { + if (copyStrategy == null) + throw new ArgumentNullException(nameof(copyStrategy)); + + if (copyStrategies == null) + copyStrategies = new List(); + + copyStrategies.Add(copyStrategy); + } + + public IDictionary ExtendedProperties + { + get + { + if (extendedProperties == null) + { + extendedProperties = new Dictionary(); + } + return extendedProperties; + } + } + + private static IDictionaryInitializer[] MergeInitializers( + IDictionaryInitializer[] source, List behaviors) + { + int index, count; + IDictionaryInitializer initializer; + var result = null as List; + + count = source.Length; + for (index = 0; index < count; index++) + PropertyDescriptor.MergeBehavior(ref result, source[index]); + + count = behaviors.Count; + for (index = 0; index < count; index++) + if (null != (initializer = behaviors[index] as IDictionaryInitializer)) + PropertyDescriptor.MergeBehavior(ref result, initializer); + + return result == null + ? NoInitializers + : result.ToArray(); + } + + private static IDictionary MergeProperties( + IDictionary source) + { + var properties = new Dictionary(); + + foreach (var sourceProperty in source) + { + properties[sourceProperty.Key] = new PropertyDescriptor(sourceProperty.Value, true); + } + + return properties; + } + + private static IDictionary MergeProperties( + IDictionary source, List behaviors) + { + int index, count = behaviors.Count; + var properties = new Dictionary(); + + foreach (var sourceProperty in source) + { + var property = new PropertyDescriptor(sourceProperty.Value, true); + + for (index = 0; index < count; index++) + property.AddBehavior(behaviors[index]); + + properties[sourceProperty.Key] = property; + } + + return properties; + } + + private static readonly IDictionaryInitializer[] + NoInitializers = { }; + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterMeta.cs b/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterMeta.cs new file mode 100644 index 0000000..1953393 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterMeta.cs @@ -0,0 +1,130 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.Linq; + using System.Diagnostics; + + [DebuggerDisplay("Type: {Type.FullName,nq}")] + public class DictionaryAdapterMeta + { + private IDictionary extendedProperties; + private readonly Func creator; + + public DictionaryAdapterMeta(Type type, Type implementation, object[] behaviors, IDictionaryMetaInitializer[] metaInitializers, + IDictionaryInitializer[] initializers, IDictionary properties, + IDictionaryAdapterFactory factory, Func creator) + { + Type = type; + Implementation = implementation; + Behaviors = behaviors; + MetaInitializers = metaInitializers; + Initializers = initializers; + Properties = properties; + Factory = factory; + this.creator = creator; + + InitializeMeta(); + } + + public Type Type { get; private set; } + + public Type Implementation { get; private set; } + + public object[] Behaviors { get; private set; } + + public IDictionaryAdapterFactory Factory { get; private set; } + + public IDictionary Properties { get; private set; } + + public IDictionaryMetaInitializer[] MetaInitializers { get; private set; } + + public IDictionaryInitializer[] Initializers { get; private set; } + + public IDictionary ExtendedProperties + { + get + { + if (extendedProperties == null) + { + extendedProperties = new Dictionary(); + } + return extendedProperties; + } + } + + public PropertyDescriptor CreateDescriptor() + { + var metaInitializers = MetaInitializers; + var sharedAnnotations = CollectSharedBehaviors(Behaviors, metaInitializers); + var sharedInitializers = CollectSharedBehaviors(Initializers, metaInitializers); + + var descriptor = (sharedAnnotations != null) + ? new PropertyDescriptor(sharedAnnotations.ToArray()) + : new PropertyDescriptor(); + + descriptor.AddBehaviors(metaInitializers); + + if (sharedInitializers != null) + descriptor.AddBehaviors(sharedInitializers); + + return descriptor; + } + + private static List CollectSharedBehaviors(T[] source, IDictionaryMetaInitializer[] predicates) + { + var results = null as List; + + foreach (var candidate in source) + { + foreach (var predicate in predicates) + { + if (predicate.ShouldHaveBehavior(candidate)) + { + if (results == null) + results = new List(source.Length); + + results.Add(candidate); + break; // next candidate + } + } + } + + return results; + } + + public DictionaryAdapterMeta GetAdapterMeta(Type type) + { + return Factory.GetAdapterMeta(type, this); + } + + public object CreateInstance(IDictionary dictionary, PropertyDescriptor descriptor) + { + var instance = new DictionaryAdapterInstance(dictionary, this, descriptor, Factory); + return creator(instance); + } + + private void InitializeMeta() + { + foreach (var metaInitializer in MetaInitializers) + { + metaInitializer.Initialize(Factory, this); + } + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/DictionaryValidateGroup.cs b/Castle.Core/Components.DictionaryAdapter/DictionaryValidateGroup.cs new file mode 100644 index 0000000..14d71a2 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/DictionaryValidateGroup.cs @@ -0,0 +1,106 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System; + using System.Collections.Generic; + using System.ComponentModel; + using System.Linq; + + public class DictionaryValidateGroup : IDictionaryValidate, INotifyPropertyChanged, IDisposable + { + private readonly object[] groups; + private readonly IDictionaryAdapter adapter; + private readonly string[] propertyNames; + private readonly PropertyChangedEventHandler propertyChanged; + + public DictionaryValidateGroup(object[] groups, IDictionaryAdapter adapter) + { + this.groups = groups; + this.adapter = adapter; + + propertyNames = (from property in this.adapter.This.Properties.Values + from groupings in property.Annotations.OfType() + where this.groups.Intersect(groupings.Group).Any() + select property.PropertyName).Distinct().ToArray(); + + if (propertyNames.Length > 0 && adapter.CanNotify) + { + propertyChanged += (sender, args) => + { + if (PropertyChanged != null) + PropertyChanged(this, args); + }; + this.adapter.PropertyChanged += propertyChanged; + } + } + + public event PropertyChangedEventHandler PropertyChanged; + + public bool CanValidate + { + get { return adapter.CanValidate; } + set { adapter.CanValidate = value; } + } + + public bool IsValid + { + get { return string.IsNullOrEmpty(Error); } + } + + public string Error + { + get + { + return string.Join(Environment.NewLine, + propertyNames.Select(propertyName => adapter[propertyName]) + .Where(errors => !string.IsNullOrEmpty(errors)).ToArray()); + } + } + + public string this[string columnName] + { + get + { + if (Array.IndexOf(propertyNames, columnName) >= 0) + { + return adapter[columnName]; + } + return string.Empty; + } + } + + public DictionaryValidateGroup ValidateGroups(params object[] groups) + { + groups = this.groups.Union(groups).ToArray(); + return new DictionaryValidateGroup(groups, adapter); + } + + public IEnumerable Validators + { + get { return adapter.Validators; } + } + + public void AddValidator(IDictionaryValidator validator) + { + throw new NotSupportedException(); + } + + public void Dispose() + { + adapter.PropertyChanged -= propertyChanged; + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/DynamicDictionary.cs b/Castle.Core/Components.DictionaryAdapter/DynamicDictionary.cs new file mode 100644 index 0000000..c88cff9 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/DynamicDictionary.cs @@ -0,0 +1,52 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System.Collections; + using System.Collections.Generic; + using System.Dynamic; + using System.Linq; + + /// + /// Wraps a with a dynamic object to expose a bit better looking API. + /// The implementation is trivial and assumes keys are s. + /// + public class DynamicDictionary : DynamicObject + { + private readonly IDictionary dictionary; + + public DynamicDictionary(IDictionary dictionary) + { + this.dictionary = dictionary; + } + + public override IEnumerable GetDynamicMemberNames() + { + return from object key in dictionary.Keys select key.ToString(); + } + + public override bool TryGetMember(GetMemberBinder binder, out object result) + { + result = dictionary[binder.Name]; + return true; + } + + public override bool TrySetMember(SetMemberBinder binder, object value) + { + dictionary[binder.Name] = value; + return true; + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/GenericDictionaryAdapter.cs b/Castle.Core/Components.DictionaryAdapter/GenericDictionaryAdapter.cs new file mode 100644 index 0000000..9780395 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/GenericDictionaryAdapter.cs @@ -0,0 +1,66 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"; +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System; + using System.Collections.Generic; + + public class GenericDictionaryAdapter : AbstractDictionaryAdapter + { + private readonly IDictionary dictionary; + + public GenericDictionaryAdapter(IDictionary dictionary) + { + this.dictionary = dictionary; + } + + public override bool IsReadOnly + { + get { return dictionary.IsReadOnly; } + } + + public override bool Contains(object key) + { + return dictionary.Keys.Contains(GetKey(key)); + } + + public override object this[object key] + { + get + { + TValue value; + return dictionary.TryGetValue(GetKey(key), out value) ? value : default(TValue); + } + set { dictionary[GetKey(key)] = (TValue)value; } + } + + private static string GetKey(object key) + { + if (key == null) + { + throw new ArgumentNullException(nameof(key)); + } + return key.ToString(); + } + } + + public static class GenericDictionaryAdapter + { + public static GenericDictionaryAdapter ForDictionaryAdapter(this IDictionary dictionary) + { + return new GenericDictionaryAdapter(dictionary); + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/IDictionaryAdapter.cs b/Castle.Core/Components.DictionaryAdapter/IDictionaryAdapter.cs new file mode 100644 index 0000000..4dc2619 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/IDictionaryAdapter.cs @@ -0,0 +1,52 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System; + + /// + /// Contract for manipulating the Dictionary adapter. + /// + public interface IDictionaryAdapter : IDictionaryEdit, IDictionaryNotify, IDictionaryValidate, IDictionaryCreate + { + DictionaryAdapterMeta Meta { get; } + + DictionaryAdapterInstance This { get; } + + string GetKey(string propertyName); + + object GetProperty(string propertyName, bool ifExists); + + object ReadProperty(string key); + + T GetPropertyOfType(string propertyName); + + bool SetProperty(string propertyName, ref object value); + + void StoreProperty(PropertyDescriptor property, string key, object value); + + void ClearProperty(PropertyDescriptor property, string key); + + bool ShouldClearProperty(PropertyDescriptor property, object value); + + void CopyTo(IDictionaryAdapter other); + + void CopyTo(IDictionaryAdapter other, Func selector); + + T Coerce() where T : class; + + object Coerce(Type type); + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/IDictionaryAdapterFactory.cs b/Castle.Core/Components.DictionaryAdapter/IDictionaryAdapterFactory.cs new file mode 100644 index 0000000..bed7883 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/IDictionaryAdapterFactory.cs @@ -0,0 +1,128 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + +namespace Castle.Components.DictionaryAdapter +{ + using System; + using System.Collections; + using System.Collections.Specialized; + + /// + /// Defines the contract for building typed dictionary adapters. + /// + public interface IDictionaryAdapterFactory + { + /// + /// Gets a typed adapter bound to the . + /// + /// The typed interface. + /// The underlying source of properties. + /// An implementation of the typed interface bound to the dictionary. + /// + /// The type represented by T must be an interface with properties. + /// + T GetAdapter(IDictionary dictionary); + + /// + /// Gets a typed adapter bound to the . + /// + /// The typed interface. + /// The underlying source of properties. + /// An implementation of the typed interface bound to the dictionary. + /// + /// The type represented by T must be an interface with properties. + /// + object GetAdapter(Type type, IDictionary dictionary); + + /// + /// Gets a typed adapter bound to the . + /// + /// The typed interface. + /// The underlying source of properties. + /// The property descriptor. + /// An implementation of the typed interface bound to the dictionary. + /// + /// The type represented by T must be an interface with properties. + /// + object GetAdapter(Type type, IDictionary dictionary, PropertyDescriptor descriptor); + + /// + /// Gets a typed adapter bound to the . + /// + /// The typed interface. + /// The underlying source of properties. + /// An implementation of the typed interface bound to the namedValues. + /// + /// The type represented by T must be an interface with properties. + /// + T GetAdapter(NameValueCollection nameValues); + + /// + /// Gets a typed adapter bound to the . + /// + /// The typed interface. + /// The underlying source of properties. + /// An implementation of the typed interface bound to the namedValues. + /// + /// The type represented by T must be an interface with properties. + /// + object GetAdapter(Type type, NameValueCollection nameValues); + + /// + /// Gets a typed adapter bound to the . + /// + /// The typed interface. + /// The underlying source of properties. + /// An implementation of the typed interface bound to the . + /// + /// The type represented by T must be an interface with properties. + /// + T GetAdapter(System.Xml.XmlNode xmlNode); + + /// + /// Gets a typed adapter bound to the . + /// + /// The typed interface. + /// The underlying source of properties. + /// An implementation of the typed interface bound to the . + /// + /// The type represented by T must be an interface with properties. + /// + object GetAdapter(Type type, System.Xml.XmlNode xmlNode); + + /// + /// Gets the associated with the type. + /// + /// The typed interface. + /// The adapter meta-data. + DictionaryAdapterMeta GetAdapterMeta(Type type); + + /// + /// Gets the associated with the type. + /// + /// The typed interface. + /// The property descriptor. + /// The adapter meta-data. + DictionaryAdapterMeta GetAdapterMeta(Type type, PropertyDescriptor descriptor); + + /// + /// Gets the associated with the type. + /// + /// The typed interface. + /// Another from which to copy behaviors. + /// The adapter meta-data. + DictionaryAdapterMeta GetAdapterMeta(Type type, DictionaryAdapterMeta other); + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/IDictionaryAdapterVisitor.cs b/Castle.Core/Components.DictionaryAdapter/IDictionaryAdapterVisitor.cs new file mode 100644 index 0000000..99d547d --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/IDictionaryAdapterVisitor.cs @@ -0,0 +1,34 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System; + + /// + /// Contract for traversing a . + /// + public interface IDictionaryAdapterVisitor + { + bool VisitDictionaryAdapter(IDictionaryAdapter dictionaryAdapter, object state); + + bool VisitDictionaryAdapter(IDictionaryAdapter dictionaryAdapter, Func selector, object state); + + void VisitProperty(IDictionaryAdapter dictionaryAdapter, PropertyDescriptor property, object state); + + void VisitInterface(IDictionaryAdapter dictionaryAdapter, PropertyDescriptor property, object state); + + void VisitCollection(IDictionaryAdapter dictionaryAdapter, PropertyDescriptor property, Type collectionItemType, object state); + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/IDictionaryBehavior.cs b/Castle.Core/Components.DictionaryAdapter/IDictionaryBehavior.cs new file mode 100644 index 0000000..770fd41 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/IDictionaryBehavior.cs @@ -0,0 +1,33 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + /// + /// Defines the contract for customizing dictionary access. + /// + public interface IDictionaryBehavior + { + /// + /// Determines relative order to apply related behaviors. + /// + int ExecutionOrder { get; } + + /// + /// Copies the dictionary behavior. + /// + /// null if should not be copied. Otherwise copy. + IDictionaryBehavior Copy(); + } +} \ No newline at end of file diff --git a/Castle.Core/Components.DictionaryAdapter/IDictionaryBehaviorBuilder.cs b/Castle.Core/Components.DictionaryAdapter/IDictionaryBehaviorBuilder.cs new file mode 100644 index 0000000..4d53162 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/IDictionaryBehaviorBuilder.cs @@ -0,0 +1,29 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System.Collections.Generic; + + /// + /// Defines the contract for building s. + /// + public interface IDictionaryBehaviorBuilder + { + /// + /// Builds the dictionary behaviors. + /// + object[] BuildBehaviors(); + } +} \ No newline at end of file diff --git a/Castle.Core/Components.DictionaryAdapter/IDictionaryCoerceStrategy.cs b/Castle.Core/Components.DictionaryAdapter/IDictionaryCoerceStrategy.cs new file mode 100644 index 0000000..57c5cea --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/IDictionaryCoerceStrategy.cs @@ -0,0 +1,23 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System; + + public interface IDictionaryCoerceStrategy + { + object Coerce(IDictionaryAdapter adapter, Type type); + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/IDictionaryCopyStrategy.cs b/Castle.Core/Components.DictionaryAdapter/IDictionaryCopyStrategy.cs new file mode 100644 index 0000000..54898a2 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/IDictionaryCopyStrategy.cs @@ -0,0 +1,23 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System; + + public interface IDictionaryCopyStrategy + { + bool Copy(IDictionaryAdapter source, IDictionaryAdapter target, ref Func selector); + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/IDictionaryCreate.cs b/Castle.Core/Components.DictionaryAdapter/IDictionaryCreate.cs new file mode 100644 index 0000000..17544a8 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/IDictionaryCreate.cs @@ -0,0 +1,37 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System; + using System.Collections; + + /// + /// Contract for creating additional Dictionary adapters. + /// + public interface IDictionaryCreate + { + T Create(); + + object Create(Type type); + + T Create(IDictionary dictionary); + + object Create(Type type, IDictionary dictionary); + + T Create(Action init); + + T Create(IDictionary dictionary, Action init); + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/IDictionaryCreateStrategy.cs b/Castle.Core/Components.DictionaryAdapter/IDictionaryCreateStrategy.cs new file mode 100644 index 0000000..f84f187 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/IDictionaryCreateStrategy.cs @@ -0,0 +1,24 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System; + using System.Collections; + + public interface IDictionaryCreateStrategy + { + object Create(IDictionaryAdapter adapter, Type type, IDictionary dictionary); + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/IDictionaryEdit.cs b/Castle.Core/Components.DictionaryAdapter/IDictionaryEdit.cs new file mode 100644 index 0000000..fc0c1d9 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/IDictionaryEdit.cs @@ -0,0 +1,37 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System; + using System.ComponentModel; + + /// + /// Contract for editing the Dictionary adapter. + /// + public interface IDictionaryEdit : IEditableObject, IRevertibleChangeTracking + { + bool CanEdit { get; } + + bool IsEditing { get; } + + bool SupportsMultiLevelEdit { get; set; } + + IDisposable SuppressEditingBlock(); + + void SuppressEditing(); + + void ResumeEditing(); + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/IDictionaryEqualityHashCodeStrategy.cs b/Castle.Core/Components.DictionaryAdapter/IDictionaryEqualityHashCodeStrategy.cs new file mode 100644 index 0000000..3937c0e --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/IDictionaryEqualityHashCodeStrategy.cs @@ -0,0 +1,23 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + public interface IDictionaryEqualityHashCodeStrategy + { + bool Equals(IDictionaryAdapter adapter1, IDictionaryAdapter adapter2); + + bool GetHashCode(IDictionaryAdapter adapter, out int hashCode); + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/IDictionaryInitializer.cs b/Castle.Core/Components.DictionaryAdapter/IDictionaryInitializer.cs new file mode 100644 index 0000000..8bb0d21 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/IDictionaryInitializer.cs @@ -0,0 +1,29 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + /// + /// Contract for dictionary initialization. + /// + public interface IDictionaryInitializer : IDictionaryBehavior + { + /// + /// Performs any initialization of the + /// + /// The dictionary adapter. + /// The dictionary behaviors. + void Initialize(IDictionaryAdapter dictionaryAdapter, object[] behaviors); + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/IDictionaryKeyBuilder.cs b/Castle.Core/Components.DictionaryAdapter/IDictionaryKeyBuilder.cs new file mode 100644 index 0000000..2132739 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/IDictionaryKeyBuilder.cs @@ -0,0 +1,34 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System; + using System.Collections; + + /// + /// Defines the contract for building typed dictionary keys. + /// + public interface IDictionaryKeyBuilder : IDictionaryBehavior + { + /// + /// Builds the specified key. + /// + /// The dictionary adapter. + /// The current key. + /// The property. + /// The updated key + string GetKey(IDictionaryAdapter dictionaryAdapter, string key, PropertyDescriptor property); + } +} \ No newline at end of file diff --git a/Castle.Core/Components.DictionaryAdapter/IDictionaryMetaInitializer.cs b/Castle.Core/Components.DictionaryAdapter/IDictionaryMetaInitializer.cs new file mode 100644 index 0000000..479ec91 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/IDictionaryMetaInitializer.cs @@ -0,0 +1,43 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + /// + /// Contract for dictionary meta-data initialization. + /// + public interface IDictionaryMetaInitializer : IDictionaryBehavior + { + /// + /// Initializes the given object. + /// + /// The dictionary adapter factory. + /// The dictionary adapter meta. + /// + void Initialize(IDictionaryAdapterFactory factory, DictionaryAdapterMeta dictionaryMeta); + + /// + /// Determines whether the given behavior should be included in a new + /// object. + /// + /// A dictionary behavior or annotation. + /// True if the behavior should be included; otherwise, false. + /// + /// behaviors are always included, + /// regardless of the result of this method. + /// + /// + bool ShouldHaveBehavior(object behavior); + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/IDictionaryNotify.cs b/Castle.Core/Components.DictionaryAdapter/IDictionaryNotify.cs new file mode 100644 index 0000000..06a2ecf --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/IDictionaryNotify.cs @@ -0,0 +1,37 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System; + using System.ComponentModel; + + /// + /// Contract for managing Dictionary adapter notifications. + /// + public interface IDictionaryNotify : + INotifyPropertyChanging, + INotifyPropertyChanged + { + bool CanNotify { get; } + + bool ShouldNotify { get; } + + IDisposable SuppressNotificationsBlock(); + + void SuppressNotifications(); + + void ResumeNotifications(); + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/IDictionaryPropertyGetter.cs b/Castle.Core/Components.DictionaryAdapter/IDictionaryPropertyGetter.cs new file mode 100644 index 0000000..1ab17b6 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/IDictionaryPropertyGetter.cs @@ -0,0 +1,36 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System.Collections; + + /// + /// Defines the contract for retrieving dictionary values. + /// + public interface IDictionaryPropertyGetter : IDictionaryBehavior + { + /// + /// Gets the effective dictionary value. + /// + /// The dictionary adapter. + /// The key. + /// The stored value. + /// The property. + /// true if return only existing. + /// The effective property value. + object GetPropertyValue(IDictionaryAdapter dictionaryAdapter, string key, + object storedValue, PropertyDescriptor property, bool ifExists); + } +} \ No newline at end of file diff --git a/Castle.Core/Components.DictionaryAdapter/IDictionaryPropertySetter.cs b/Castle.Core/Components.DictionaryAdapter/IDictionaryPropertySetter.cs new file mode 100644 index 0000000..bbdbd94 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/IDictionaryPropertySetter.cs @@ -0,0 +1,34 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + + /// + /// Defines the contract for updating dictionary values. + /// + public interface IDictionaryPropertySetter : IDictionaryBehavior + { + /// + /// Sets the stored dictionary value. + /// + /// The dictionary adapter. + /// The key. + /// The stored value. + /// The property. + /// true if the property should be stored. + bool SetPropertyValue(IDictionaryAdapter dictionaryAdapter, string key, ref object value, + PropertyDescriptor property); + } +} \ No newline at end of file diff --git a/Castle.Core/Components.DictionaryAdapter/IDictionaryReferenceManager.cs b/Castle.Core/Components.DictionaryAdapter/IDictionaryReferenceManager.cs new file mode 100644 index 0000000..ef37790 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/IDictionaryReferenceManager.cs @@ -0,0 +1,26 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System; + + public interface IDictionaryReferenceManager + { + bool IsReferenceProperty(IDictionaryAdapter dictionaryAdapter, string propertyName); + + bool TryGetReference(object keyObject, out object inGraphObject); + void AddReference(object keyObject, object relatedObject, bool isInGraph); + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/IDictionaryValidate.cs b/Castle.Core/Components.DictionaryAdapter/IDictionaryValidate.cs new file mode 100644 index 0000000..b6eabc0 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/IDictionaryValidate.cs @@ -0,0 +1,35 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System.Collections.Generic; + using System.ComponentModel; + + /// + /// Contract for validating Dictionary adapter. + /// + public interface IDictionaryValidate : IDataErrorInfo + { + bool CanValidate { get; set; } + + bool IsValid { get; } + + DictionaryValidateGroup ValidateGroups(params object[] groups); + + IEnumerable Validators { get; } + + void AddValidator(IDictionaryValidator validator); + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/IDictionaryValidator.cs b/Castle.Core/Components.DictionaryAdapter/IDictionaryValidator.cs new file mode 100644 index 0000000..f8dfa2e --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/IDictionaryValidator.cs @@ -0,0 +1,50 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + /// + /// Contract for dictionary validation. + /// + public interface IDictionaryValidator + { + /// + /// Determines if is valid. + /// + /// The dictionary adapter. + /// true if valid. + bool IsValid(IDictionaryAdapter dictionaryAdapter); + + /// + /// Validates the . + /// + /// The dictionary adapter. + /// The error summary information. + string Validate(IDictionaryAdapter dictionaryAdapter); + + /// + /// Validates the for a property. + /// + /// The dictionary adapter. + /// The property to validate. + /// The property summary information. + string Validate(IDictionaryAdapter dictionaryAdapter, PropertyDescriptor property); + + /// + /// Invalidates any results cached by the validator. + /// + /// The dictionary adapter. + void Invalidate(IDictionaryAdapter dictionaryAdapter); + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/IPropertyDescriptorInitializer.cs b/Castle.Core/Components.DictionaryAdapter/IPropertyDescriptorInitializer.cs new file mode 100644 index 0000000..1175673 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/IPropertyDescriptorInitializer.cs @@ -0,0 +1,29 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + /// + /// Contract for property descriptor initialization. + /// + public interface IPropertyDescriptorInitializer : IDictionaryBehavior + { + /// + /// Performs any initialization of the + /// + /// The property descriptor. + /// The property behaviors. + void Initialize(PropertyDescriptor propertyDescriptor, object[] behaviors); + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/MemberwiseEqualityHashCodeStrategy.cs b/Castle.Core/Components.DictionaryAdapter/MemberwiseEqualityHashCodeStrategy.cs new file mode 100644 index 0000000..ebfe611 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/MemberwiseEqualityHashCodeStrategy.cs @@ -0,0 +1,152 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System; + using System.Collections; + using System.Collections.Generic; + + public class MemberwiseEqualityHashCodeStrategy : DictionaryBehaviorAttribute, + IDictionaryEqualityHashCodeStrategy, IDictionaryInitializer, IEqualityComparer + { + class HashCodeVisitor : AbstractDictionaryAdapterVisitor + { + private int hashCode; + + public int CalculateHashCode(IDictionaryAdapter dictionaryAdapter) + { + if (dictionaryAdapter == null) + return 0; + + hashCode = 27; + return VisitDictionaryAdapter(dictionaryAdapter, null) ? hashCode : 0; + } + + protected override void VisitProperty(IDictionaryAdapter dictionaryAdapter, PropertyDescriptor property, object state) + { + var value = dictionaryAdapter.GetProperty(property.PropertyName, true); + CollectHashCode(property, GetValueHashCode(value)); + } + + protected override void VisitInterface(IDictionaryAdapter dictionaryAdapter, PropertyDescriptor property, object state) + { + var nested = (IDictionaryAdapter)dictionaryAdapter.GetProperty(property.PropertyName, true); + CollectHashCode(property, GetNestedHashCode(nested)); + } + + protected override void VisitCollection(IDictionaryAdapter dictionaryAdapter, PropertyDescriptor property, Type collectionItemType, object state) + { + var collection = (IEnumerable)dictionaryAdapter.GetProperty(property.PropertyName, true); + CollectHashCode(property, GetCollectionHashcode(collection)); + } + + private int GetValueHashCode(object value) + { + if (value == null) + { + return 0; + } + + if (value is IDictionaryAdapter) + { + return GetNestedHashCode((IDictionaryAdapter)value); + } + + if ((value is IEnumerable) && (value is string) == false) + { + return GetCollectionHashcode((IEnumerable)value); + } + + return value.GetHashCode(); + } + + private int GetNestedHashCode(IDictionaryAdapter nested) + { + var currentHashCode = hashCode; + var nestedHashCode = CalculateHashCode(nested); + hashCode = currentHashCode; + return nestedHashCode; + } + + private int GetCollectionHashcode(IEnumerable collection) + { + if (collection == null) + { + return 0; + } + + var collectionHashCode = 0; + + foreach (var value in collection) + { + var valueHashCode = GetValueHashCode(value); + unchecked + { + collectionHashCode = (13 * collectionHashCode) + valueHashCode; + } + } + + return collectionHashCode; + } + + private void CollectHashCode(PropertyDescriptor property, int valueHashCode) + { + unchecked + { + hashCode = (13 * hashCode) + property.PropertyName.GetHashCode(); + hashCode = (13 * hashCode) + valueHashCode; + } + } + } + + public bool Equals(IDictionaryAdapter adapter1, IDictionaryAdapter adapter2) + { + if (ReferenceEquals(adapter1, adapter2)) + { + return true; + } + + if ((adapter1 == null) ^ (adapter2 == null)) + { + return false; + } + + if (adapter1.Meta.Type != adapter2.Meta.Type) + { + return false; + } + + return GetHashCode(adapter1) == GetHashCode(adapter2); + } + + public int GetHashCode(IDictionaryAdapter adapter) + { + int hashCode; + GetHashCode(adapter, out hashCode); + return hashCode; + } + + public bool GetHashCode(IDictionaryAdapter adapter, out int hashCode) + { + hashCode = new HashCodeVisitor().CalculateHashCode(adapter); + return true; + } + + void IDictionaryInitializer.Initialize(IDictionaryAdapter dictionaryAdapter, object[] behaviors) + { + dictionaryAdapter.This.EqualityHashCodeStrategy = this; + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/NameValueCollectionAdapter.cs b/Castle.Core/Components.DictionaryAdapter/NameValueCollectionAdapter.cs new file mode 100644 index 0000000..f22a2df --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/NameValueCollectionAdapter.cs @@ -0,0 +1,93 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System; + using System.Collections.Specialized; + using System.Linq; + + /// + /// + /// + public class NameValueCollectionAdapter : AbstractDictionaryAdapter + { + private readonly NameValueCollection nameValues; + + /// + /// Initializes a new instance of the class. + /// + /// The name values. + public NameValueCollectionAdapter(NameValueCollection nameValues) + { + this.nameValues = nameValues; + } + + /// + /// Gets a value indicating whether the object is read-only. + /// + /// true if the object is read-only; otherwise, false. + public override bool IsReadOnly + { + get { return false; } + } + + /// + /// Determines whether the object contains an element with the specified key. + /// + /// The key to locate in the object. + /// + /// true if the contains an element with the key; otherwise, false. + /// + /// key is null. + public override bool Contains(object key) + { + if (key == null) + { + throw new ArgumentNullException(nameof(key)); + } + + //Getting a value out is O(1), so in the case that the collection contains a non-null value for this key + //we can skip the O(n) key lookup. + if (this[key] != null) + { + return true; + } + + return nameValues.AllKeys.Contains(key.ToString(), StringComparer.OrdinalIgnoreCase); + } + + /// + /// Gets or sets the with the specified key. + /// + public override object this[object key] + { + get { return nameValues[key.ToString()]; } + set + { + string val = (value != null) ? value.ToString() : null; + nameValues[key.ToString()] = val; + } + } + + /// + /// Adapts the specified name values. + /// + /// The name values. + public static NameValueCollectionAdapter Adapt(NameValueCollection nameValues) + { + return new NameValueCollectionAdapter(nameValues); + } + } +} \ No newline at end of file diff --git a/Castle.Core/Components.DictionaryAdapter/PropertyChangedEventArgsEx.cs b/Castle.Core/Components.DictionaryAdapter/PropertyChangedEventArgsEx.cs new file mode 100644 index 0000000..165cd58 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/PropertyChangedEventArgsEx.cs @@ -0,0 +1,41 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System.ComponentModel; + + public class PropertyChangedEventArgsEx : PropertyChangedEventArgs + { + private readonly object oldValue; + private readonly object newValue; + + public PropertyChangedEventArgsEx(string propertyName, object oldValue, object newValue) + : base(propertyName) + { + this.oldValue = oldValue; + this.newValue = newValue; + } + + public object OldValue + { + get { return oldValue; } + } + + public object NewValue + { + get { return newValue; } + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/PropertyChangingEventArgsEx.cs b/Castle.Core/Components.DictionaryAdapter/PropertyChangingEventArgsEx.cs new file mode 100644 index 0000000..617e7e6 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/PropertyChangingEventArgsEx.cs @@ -0,0 +1,48 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System.ComponentModel; + + public class PropertyChangingEventArgsEx : PropertyChangingEventArgs + { + private readonly object oldValue; + private readonly object newValue; + private bool cancel; + + public PropertyChangingEventArgsEx(string propertyName, object oldValue, object newValue) + : base(propertyName) + { + this.oldValue = oldValue; + this.newValue = newValue; + } + + public object OldValue + { + get { return oldValue; } + } + + public object NewValue + { + get { return newValue; } + } + + public bool Cancel + { + get { return cancel; } + set { cancel = value; } + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/PropertyDescriptor.cs b/Castle.Core/Components.DictionaryAdapter/PropertyDescriptor.cs new file mode 100644 index 0000000..33055ce --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/PropertyDescriptor.cs @@ -0,0 +1,471 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.ComponentModel; + using System.Diagnostics; + using System.Linq; + using System.Reflection; + using Castle.Core.Internal; + + /// + /// Describes a dictionary property. + /// + [DebuggerDisplay("{Property.DeclaringType.FullName,nq}.{PropertyName,nq}")] + public class PropertyDescriptor : IDictionaryKeyBuilder, IDictionaryPropertyGetter, IDictionaryPropertySetter + { + private IDictionary state; + private Dictionary extendedProperties; + protected List dictionaryBehaviors; + + private static readonly object[] NoAnnotations = new object[0]; + + /// + /// Initializes an empty class. + /// + public PropertyDescriptor() + { + Annotations = NoAnnotations; + } + + /// + /// Initializes a new instance of the class. + /// + /// The property. + /// The annotations. + public PropertyDescriptor(PropertyInfo property, object[] annotations) : this() + { + Property = property; + Annotations = annotations ?? NoAnnotations; + IsDynamicProperty = typeof(IDynamicValue).IsAssignableFrom(property.PropertyType); + ObtainTypeConverter(); + } + + /// + /// Initializes a new instance class. + /// + public PropertyDescriptor(object[] annotations) + { + Annotations = annotations ?? NoAnnotations; + } + + /// + /// Copies an existing instance of the class. + /// + public PropertyDescriptor(PropertyDescriptor source, bool copyBehaviors) + { + Property = source.Property; + Annotations = source.Annotations; + IsDynamicProperty = source.IsDynamicProperty; + TypeConverter = source.TypeConverter; + SuppressNotifications = source.SuppressNotifications; + state = source.state; + IfExists = source.IfExists; + Fetch = source.Fetch; + + if (source.extendedProperties != null) + extendedProperties = new Dictionary(source.extendedProperties); + + if (copyBehaviors && source.dictionaryBehaviors != null) + dictionaryBehaviors = new List(source.dictionaryBehaviors); + } + + /// + /// + /// + public int ExecutionOrder + { + get { return 0; } + } + + /// + /// Gets the property name. + /// + public string PropertyName + { + get { return (Property != null) ? Property.Name : null; } + } + + /// + /// Gets the property type. + /// + public Type PropertyType + { + get { return (Property != null) ? Property.PropertyType : null; } + } + + /// + /// Gets the property. + /// + /// The property. + public PropertyInfo Property { get; private set; } + + /// + /// Returns true if the property is dynamic. + /// + public bool IsDynamicProperty { get; private set; } + + /// + /// Gets additional state. + /// + public IDictionary State + { + get { return state ?? (state = new Dictionary()); } + } + + /// + /// Determines if property should be fetched. + /// + public bool Fetch { get; set; } + + /// + /// Determines if property must exist first. + /// + public bool IfExists { get; set; } + + /// + /// Determines if notifications should occur. + /// + public bool SuppressNotifications { get; set; } + + /// + /// Gets the property behaviors. + /// + public object[] Annotations { get; private set; } + + /// + /// Gets the type converter. + /// + /// The type converter. + public TypeConverter TypeConverter { get; private set; } + + /// + /// Gets the extended properties. + /// + public IDictionary ExtendedProperties + { + get { return extendedProperties ?? (extendedProperties = new Dictionary()); } + } + + /// + /// Gets the setter. + /// + /// The setter. + public IEnumerable Behaviors + { + get + { + return dictionaryBehaviors ?? Enumerable.Empty(); + } + } + + internal List BehaviorsInternal + { + get { return dictionaryBehaviors; } + } + + /// + /// Gets the key builders. + /// + /// The key builders. + public IEnumerable KeyBuilders + { + get + { + return (dictionaryBehaviors != null) + ? dictionaryBehaviors.OfType() + : Enumerable.Empty(); + } + } + + /// + /// Gets the setter. + /// + /// The setter. + public IEnumerable Setters + { + get + { + return (dictionaryBehaviors != null) + ? dictionaryBehaviors.OfType() + : Enumerable.Empty(); + } + } + + /// + /// Gets the getter. + /// + /// The getter. + public IEnumerable Getters + { + get + { + return (dictionaryBehaviors != null) + ? dictionaryBehaviors.OfType() + : Enumerable.Empty(); + } + } + + /// + /// Gets the initializers. + /// + /// The initializers. + public IEnumerable Initializers + { + get + { + return (dictionaryBehaviors != null) + ? dictionaryBehaviors.OfType() + : Enumerable.Empty(); + } + } + + /// + /// Gets the meta-data initializers. + /// + /// The meta-data initializers. + public IEnumerable MetaInitializers + { + get + { + return (dictionaryBehaviors != null) + ? dictionaryBehaviors.OfType() + : Enumerable.Empty(); + } + } + + /// + /// Gets the key. + /// + /// The dictionary adapter. + /// The key. + /// The descriptor. + public string GetKey(IDictionaryAdapter dictionaryAdapter, string key, PropertyDescriptor descriptor) + { + var behaviors = dictionaryBehaviors; + if (behaviors != null) + { + var count = behaviors.Count; + for (int i = 0; i < count; i++) + { + var builder = behaviors[i] as IDictionaryKeyBuilder; + if (builder != null) + key = builder.GetKey(dictionaryAdapter, key, this); + } + } + return key; + } + + /// + /// Gets the property value. + /// + /// The dictionary adapter. + /// The key. + /// The stored value. + /// The descriptor. + /// true if return only existing. + public object GetPropertyValue(IDictionaryAdapter dictionaryAdapter, string key, object storedValue, PropertyDescriptor descriptor, bool ifExists) + { + key = GetKey(dictionaryAdapter, key, descriptor); + storedValue = storedValue ?? dictionaryAdapter.ReadProperty(key); + + var behaviors = dictionaryBehaviors; + if (behaviors != null) + { + var count = behaviors.Count; + for (int i = 0; i < count; i++) + { + var getter = behaviors[i] as IDictionaryPropertyGetter; + if (getter != null) + storedValue = getter.GetPropertyValue(dictionaryAdapter, key, storedValue, this, IfExists || ifExists); + } + } + + return storedValue; + } + + /// + /// Sets the property value. + /// + /// The dictionary adapter. + /// The key. + /// The value. + /// The descriptor. + public bool SetPropertyValue(IDictionaryAdapter dictionaryAdapter, string key, ref object value, PropertyDescriptor descriptor) + { + key = GetKey(dictionaryAdapter, key, descriptor); + + var behaviors = dictionaryBehaviors; + if (behaviors != null) + { + var count = behaviors.Count; + for (int i = 0; i < count; i++) + { + var setter = behaviors[i] as IDictionaryPropertySetter; + if (setter != null) + if (setter.SetPropertyValue(dictionaryAdapter, key, ref value, this) == false) + return false; + } + } + + dictionaryAdapter.StoreProperty(this, key, value); + return true; + } + + /// + /// Adds a single behavior. + /// + /// The behavior. + public PropertyDescriptor AddBehavior(IDictionaryBehavior behavior) + { + if (behavior == null) + return this; + + var builder = behavior as IDictionaryBehaviorBuilder; + if (builder == null) + MergeBehavior(ref dictionaryBehaviors, behavior); + else + foreach (var item in builder.BuildBehaviors()) + AddBehavior(item as IDictionaryBehavior); + + return this; + } + + public static void MergeBehavior(ref List dictionaryBehaviors, T behavior) + where T : class, IDictionaryBehavior + { + var behaviors = dictionaryBehaviors; + if (behaviors == null) + { + behaviors = new List(); + behaviors.Add(behavior); + dictionaryBehaviors = behaviors; + return; + } + + // The following is ugly but supposedly optimized + + // Locals using ldloc.# + var index = 0; + int candidatePriority; + var targetOrder = behavior.ExecutionOrder; + // Locals using ldloc.s + var count = behaviors.Count; + IDictionaryBehavior candidateBehavior; + + // Skip while order < behavior.ExecutionOrder + for (;;) + { + candidateBehavior = behaviors[index]; + candidatePriority = candidateBehavior.ExecutionOrder; + + if (candidatePriority >= targetOrder) + break; + + if (++index == count) + { + behaviors.Add(behavior); + return; + } + } + + // Skip while order == behavior.ExecutionOrder + for (;;) + { + if (candidatePriority != targetOrder) + break; + + if (candidateBehavior == behavior) + return; // Duplicate + + if (++index == count) + { + behaviors.Add(behavior); + return; + } + + candidateBehavior = behaviors[index]; + candidatePriority = candidateBehavior.ExecutionOrder; + } + + // Insert at found index + behaviors.Insert(index, behavior); + return; + } + + /// + /// Adds the behaviors. + /// + /// The behaviors. + public PropertyDescriptor AddBehaviors(params IDictionaryBehavior[] behaviors) + { + // DO NOT REFACTOR. Compiler will emit optimized iterator here. + foreach (var behavior in behaviors) + AddBehavior(behavior); + return this; + } + + /// + /// Adds the behaviors. + /// + /// The behaviors. + public PropertyDescriptor AddBehaviors(IEnumerable behaviors) + { + if (behaviors != null) + foreach (var behavior in behaviors) + AddBehavior(behavior); + return this; + } + + /// + /// Copies the behaviors to the other + /// + public PropertyDescriptor CopyBehaviors(PropertyDescriptor other) + { + var behaviors = dictionaryBehaviors; + if (behaviors != null) + { + var count = behaviors.Count; + for (var i = 0; i < count; i++) + { + var behavior = behaviors[i].Copy(); + if (behavior != null) + other.AddBehavior(behavior); + } + } + return this; + } + + /// + /// Copies the + /// + public IDictionaryBehavior Copy() + { + return new PropertyDescriptor(this, true); + } + + private void ObtainTypeConverter() + { + var converterType = AttributesUtil.GetTypeConverter(Property); + + TypeConverter = (converterType != null) + ? (TypeConverter) Activator.CreateInstance(converterType) + : TypeDescriptor.GetConverter(PropertyType); + } + } +} \ No newline at end of file diff --git a/Castle.Core/Components.DictionaryAdapter/Util/BindingList.cs b/Castle.Core/Components.DictionaryAdapter/Util/BindingList.cs new file mode 100644 index 0000000..d8b9aae --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Util/BindingList.cs @@ -0,0 +1,325 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System; + using System.Collections; + using System.Collections.Generic; + using SCM = System.ComponentModel; + + /// + /// Provides a generic collection that supports data binding. + /// + /// + /// This class wraps the CLR + /// in order to implement the Castle-specific . + /// + /// The type of elements in the list. + public class BindingList : IBindingList, IList + { + private readonly SCM.BindingList list; + + /// + /// Initializes a new instance of the class + /// using default values. + /// + public BindingList() + { + this.list = new SCM.BindingList(); + } + + /// + /// Initializes a new instance of the class + /// with the specified list. + /// + /// + /// An of items + /// to be contained in the . + /// + public BindingList(IList list) + { + this.list = new SCM.BindingList(list); + } + + /// + /// Initializes a new instance of the class + /// wrapping the specified instance. + /// + /// + /// A + /// to be wrapped by the . + /// + public BindingList(SCM.BindingList list) + { + if (list == null) + throw new ArgumentNullException(nameof(list)); + + this.list = list; + } + + public SCM.BindingList InnerList + { + get { return list; } + } + + public SCM.IBindingList AsBindingList + { + get { return list; } + } + + public int Count + { + get { return list.Count; } + } + + bool ICollection.IsReadOnly + { + get { return ((ICollection) list).IsReadOnly; } + } + + bool IList.IsReadOnly + { + get { return ((IList) list).IsReadOnly; } + } + + bool IList.IsFixedSize + { + get { return ((IList) list).IsFixedSize; } + } + + bool ICollection.IsSynchronized + { + get { return ((ICollection) list).IsSynchronized; } + } + + object ICollection.SyncRoot + { + get { return ((ICollection) list).SyncRoot; } + } + + public bool AllowNew + { + get { return list.AllowNew; } + set { list.AllowNew = value; } + } + + public bool AllowEdit + { + get { return list.AllowEdit; } + set { list.AllowEdit = value; } + } + + public bool AllowRemove + { + get { return list.AllowRemove; } + set { list.AllowRemove = value; } + } + + public bool RaiseListChangedEvents + { + get { return list.RaiseListChangedEvents; } + set { list.RaiseListChangedEvents = value; } + } + + bool SCM.IRaiseItemChangedEvents.RaisesItemChangedEvents + { + get { return ((SCM.IRaiseItemChangedEvents) list).RaisesItemChangedEvents; } + } + + bool IBindingList.SupportsChangeNotification + { + get { return AsBindingList.SupportsChangeNotification; } + } + + bool IBindingList.SupportsSearching + { + get { return AsBindingList.SupportsSearching; } + } + + bool IBindingList.SupportsSorting + { + get { return AsBindingList.SupportsSorting; } + } + + bool IBindingList.IsSorted + { + get { return AsBindingList.IsSorted; } + } + + SCM.PropertyDescriptor IBindingList.SortProperty + { + get { return AsBindingList.SortProperty; } + } + + SCM.ListSortDirection IBindingList.SortDirection + { + get { return AsBindingList.SortDirection; } + } + + int IBindingList.Find(SCM.PropertyDescriptor property, object key) + { + return AsBindingList.Find(property, key); + } + + void IBindingList.AddIndex(SCM.PropertyDescriptor property) + { + AsBindingList.AddIndex(property); + } + + void IBindingList.RemoveIndex(SCM.PropertyDescriptor property) + { + AsBindingList.RemoveIndex(property); + } + + void IBindingList.ApplySort(SCM.PropertyDescriptor property, SCM.ListSortDirection direction) + { + AsBindingList.ApplySort(property, direction); + } + + void IBindingList.RemoveSort() + { + AsBindingList.RemoveSort(); + } + + public event SCM.AddingNewEventHandler AddingNew + { + add { list.AddingNew += value; } + remove { list.AddingNew -= value; } + } + + public event SCM.ListChangedEventHandler ListChanged + { + add { list.ListChanged += value; } + remove { list.ListChanged -= value; } + } + + public T this[int index] + { + get { return list[index]; } + set { list[index] = value; } + } + + object IList.this[int index] + { + get { return ((IList) list)[index]; } + set { ((IList) list)[index] = value; } + } + + public bool Contains(T item) + { + return list.Contains(item); + } + + bool IList.Contains(object value) + { + return ((IList) list).Contains(value); + } + + public int IndexOf(T item) + { + return list.IndexOf(item); + } + + int IList.IndexOf(object value) + { + return ((IList) list).IndexOf(value); + } + + public void CopyTo(T[] array, int index) + { + list.CopyTo(array, index); + } + + void ICollection.CopyTo(Array array, int index) + { + ((IList) list).CopyTo(array, index); + } + + public IEnumerator GetEnumerator() + { + return list.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return list.GetEnumerator(); + } + + public T AddNew() + { + return list.AddNew(); + } + + public void CancelNew(int index) + { + list.CancelNew(index); + } + + public void EndNew(int index) + { + list.EndNew(index); + } + + public void Add(T item) + { + list.Add(item); + } + + int IList.Add(object item) + { + return ((IList) list).Add(item); + } + + public void Insert(int index, T item) + { + list.Insert(index, item); + } + + void IList.Insert(int index, object item) + { + ((IList) list).Insert(index, item); + } + + public void RemoveAt(int index) + { + list.RemoveAt(index); + } + + public bool Remove(T item) + { + return list.Remove(item); + } + + void IList.Remove(object item) + { + ((IList) list).Remove(item); + } + + public void Clear() + { + list.Clear(); + } + + public void ResetBindings() + { + list.ResetBindings(); + } + + public void ResetItem(int index) + { + list.ResetItem(index); + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Util/BindingListInitializer.cs b/Castle.Core/Components.DictionaryAdapter/Util/BindingListInitializer.cs new file mode 100644 index 0000000..aba8754 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Util/BindingListInitializer.cs @@ -0,0 +1,114 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System; + using System.ComponentModel; + + public class BindingListInitializer : IValueInitializer + { + private readonly Func addNew; + private readonly Func addAt; + private readonly Func setAt; + private readonly Action removeAt; + private readonly Action reset; + + private bool addingNew; + + public BindingListInitializer(Func addAt, Func addNew, Func setAt, Action removeAt, Action reset) + { + this.addAt = addAt; + this.addNew = addNew; + this.setAt = setAt; + this.removeAt = removeAt; + this.reset = reset; + } + + public void Initialize(IDictionaryAdapter dictionaryAdapter, object value) + { + var bindingList = (System.ComponentModel.BindingList)value; + if (addNew != null) + { + bindingList.AddingNew += (sender, args) => + { + args.NewObject = addNew(); + addingNew = true; + }; + } + bindingList.ListChanged += (sender, args) => + { + switch (args.ListChangedType) + { + case ListChangedType.ItemAdded: + if (addingNew == false && addAt != null) + { + var item = addAt(args.NewIndex, bindingList[args.NewIndex]); + if (item != null) + { + using (new SuppressListChangedEvents(bindingList)) + { + bindingList[args.NewIndex] = (T)item; + } + } + } + addingNew = false; + break; + + case ListChangedType.ItemChanged: + if (setAt != null) + { + var item = setAt(args.NewIndex, bindingList[args.NewIndex]); + if (item != null) + { + using (new SuppressListChangedEvents(bindingList)) + { + bindingList[args.NewIndex] = (T)item; + } + } + } + break; + + case ListChangedType.ItemDeleted: + if (removeAt != null) + removeAt(args.NewIndex); + break; + + case ListChangedType.Reset: + if (reset != null) + reset(); + break; + } + }; + } + + class SuppressListChangedEvents : IDisposable + { + private readonly bool raiseEvents; + private readonly System.ComponentModel.BindingList bindingList; + + public SuppressListChangedEvents(System.ComponentModel.BindingList bindingList) + { + this.bindingList = bindingList; + raiseEvents = this.bindingList.RaiseListChangedEvents; + this.bindingList.RaiseListChangedEvents = false; + } + + public void Dispose() + { + bindingList.RaiseListChangedEvents = raiseEvents; + } + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Util/DynamicValue.cs b/Castle.Core/Components.DictionaryAdapter/Util/DynamicValue.cs new file mode 100644 index 0000000..9a20b4f --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Util/DynamicValue.cs @@ -0,0 +1,36 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + public abstract class DynamicValue : IDynamicValue + { + object IDynamicValue.GetValue() + { + return Value; + } + + public abstract T Value { get; } + + public override string ToString() + { + var value = Value; + if (value != null) + { + return value.ToString(); + } + return base.ToString(); + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Util/DynamicValueDelegate.cs b/Castle.Core/Components.DictionaryAdapter/Util/DynamicValueDelegate.cs new file mode 100644 index 0000000..9135b76 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Util/DynamicValueDelegate.cs @@ -0,0 +1,33 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System; + + public class DynamicValueDelegate : DynamicValue + { + private readonly Func dynamicDelegate; + + public DynamicValueDelegate(Func dynamicDelegate) + { + this.dynamicDelegate = dynamicDelegate; + } + + public override T Value + { + get { return dynamicDelegate(); } + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Util/EditableBindingList.cs b/Castle.Core/Components.DictionaryAdapter/Util/EditableBindingList.cs new file mode 100644 index 0000000..5155361 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Util/EditableBindingList.cs @@ -0,0 +1,94 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System.Collections.Generic; + using System.ComponentModel; + + public class EditableBindingList : System.ComponentModel.BindingList, IList, IEditableObject, IRevertibleChangeTracking + { + private bool isEditing; + private List snapshot; + + public EditableBindingList() + { + } + + public EditableBindingList(IList initial) + : base(initial) + { + } + + public bool IsChanged + { + get + { + if (snapshot == null || snapshot.Count != Count) + return false; + + var items = GetEnumerator(); + var snapshotItems = snapshot.GetEnumerator(); + + while (items.MoveNext() && snapshotItems.MoveNext()) + { + if (ReferenceEquals(items.Current, snapshotItems.Current) == false) + return false; + + var tracked = items.Current as IChangeTracking; + if (tracked != null && tracked.IsChanged) + return true; + } + + return false; + } + } + + public void BeginEdit() + { + if (isEditing == false) + { + snapshot = new List(this); + isEditing = true; + } + } + + public void EndEdit() + { + isEditing = false; + snapshot = null; + } + + public void CancelEdit() + { + if (isEditing) + { + Clear(); + foreach (var item in snapshot) Add(item); + snapshot = null; + isEditing = false; + } + } + + public void AcceptChanges() + { + BeginEdit(); + } + + public void RejectChanges() + { + CancelEdit(); + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Util/EditableList.cs b/Castle.Core/Components.DictionaryAdapter/Util/EditableList.cs new file mode 100644 index 0000000..07f5f10 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Util/EditableList.cs @@ -0,0 +1,107 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System.Collections; + using System.Collections.Generic; + using System.ComponentModel; + + public class EditableList : List, IEditableObject, IRevertibleChangeTracking + { + private bool isEditing; + private List snapshot; + + public EditableList() + { + } + + public EditableList(IEnumerable collection) + : base(collection) + { + } + + public void BeginEdit() + { + if (isEditing == false) + { + snapshot = new List(this); + isEditing = true; + } + } + + public bool IsChanged + { + get + { + if (snapshot == null || snapshot.Count != Count) + return false; + + var items = GetEnumerator(); + var snapshotItems = snapshot.GetEnumerator(); + + while (items.MoveNext() && snapshotItems.MoveNext()) + { + if (ReferenceEquals(items.Current, snapshotItems.Current) == false) + return false; + + var tracked = items.Current as IChangeTracking; + if (tracked != null && tracked.IsChanged) + return true; + } + + return false; + } + } + + public void EndEdit() + { + isEditing = false; + snapshot = null; + } + + public void CancelEdit() + { + if (isEditing) + { + Clear(); + AddRange(snapshot); + snapshot = null; + isEditing = false; + } + } + + public void AcceptChanges() + { + BeginEdit(); + } + + public void RejectChanges() + { + CancelEdit(); + } + } + + public class EditableList : EditableList, IList + { + public EditableList() + { + } + + public EditableList(IEnumerable collection) + : base(collection) + { + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Util/IBindingList.cs b/Castle.Core/Components.DictionaryAdapter/Util/IBindingList.cs new file mode 100644 index 0000000..25bb96a --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Util/IBindingList.cs @@ -0,0 +1,42 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System.Collections.Generic; + using System.ComponentModel; + using SysPropertyDescriptor = System.ComponentModel.PropertyDescriptor; + + public interface IBindingList : IList, IBindingListSource, ICancelAddNew, IRaiseItemChangedEvents + { + bool AllowNew { get; } + bool AllowEdit { get; } + bool AllowRemove { get; } + bool SupportsChangeNotification { get; } + bool SupportsSearching { get; } + bool SupportsSorting { get; } + bool IsSorted { get; } + SysPropertyDescriptor SortProperty { get; } + ListSortDirection SortDirection { get; } + + event ListChangedEventHandler ListChanged; + + T AddNew (); + int Find (SysPropertyDescriptor property, object key); + void AddIndex (SysPropertyDescriptor property); + void RemoveIndex(SysPropertyDescriptor property); + void ApplySort (SysPropertyDescriptor property, ListSortDirection direction); + void RemoveSort (); + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Util/IBindingListSource.cs b/Castle.Core/Components.DictionaryAdapter/Util/IBindingListSource.cs new file mode 100644 index 0000000..77f42d9 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Util/IBindingListSource.cs @@ -0,0 +1,23 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System.ComponentModel; + + public interface IBindingListSource + { + IBindingList AsBindingList { get; } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Util/ICollectionAdapter.cs b/Castle.Core/Components.DictionaryAdapter/Util/ICollectionAdapter.cs new file mode 100644 index 0000000..d8cc6de --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Util/ICollectionAdapter.cs @@ -0,0 +1,45 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System.ComponentModel; + using System.Collections.Generic; + + public interface ICollectionAdapter + { + // Configuration + void Initialize(ICollectionAdapterObserver advisor); + IEqualityComparer Comparer { get; } + + // Collection Access + int Count { get; } + T this [int index] { get; set; } + T AddNew (); + bool Add (T value); + bool Insert (int index, T value); + void Remove (int index); + void Clear (); + void ClearReferences(); // A bit of a hack. Make this nicer in a future version. + + // Snapshot Support + bool HasSnapshot { get; } + int SnapshotCount { get; } + T GetCurrentItem (int index); + T GetSnapshotItem (int index); + void SaveSnapshot (); + void LoadSnapshot (); + void DropSnapshot (); + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Util/ICollectionAdapterObserver.cs b/Castle.Core/Components.DictionaryAdapter/Util/ICollectionAdapterObserver.cs new file mode 100644 index 0000000..a228cdd --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Util/ICollectionAdapterObserver.cs @@ -0,0 +1,27 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + public interface ICollectionAdapterObserver + { + bool OnInserting ( T newValue); + bool OnReplacing (T oldValue, T newValue); + void OnRemoving (T oldValue ); + + void OnInserted ( T newValue, int index); + void OnReplaced (T oldValue, T newValue, int index); + void OnRemoved (T oldValue, int index); + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Util/ICollectionProjection.cs b/Castle.Core/Components.DictionaryAdapter/Util/ICollectionProjection.cs new file mode 100644 index 0000000..b33fd75 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Util/ICollectionProjection.cs @@ -0,0 +1,25 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System.Collections; + + public interface ICollectionProjection : ICollection + { + void Replace(IEnumerable source); + void Clear(); + void ClearReferences(); + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Util/ICondition.cs b/Castle.Core/Components.DictionaryAdapter/Util/ICondition.cs new file mode 100644 index 0000000..f2faf0c --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Util/ICondition.cs @@ -0,0 +1,24 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + /// + /// Contract for value matching. + /// + public interface ICondition + { + bool SatisfiedBy(object value); + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Util/IDynamicValue.cs b/Castle.Core/Components.DictionaryAdapter/Util/IDynamicValue.cs new file mode 100644 index 0000000..a32ffc6 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Util/IDynamicValue.cs @@ -0,0 +1,33 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + /// + /// Contract for dynamic value resolution. + /// + public interface IDynamicValue + { + object GetValue(); + } + + /// + /// Contract for typed dynamic value resolution. + /// + /// + public interface IDynamicValue : IDynamicValue + { + T Value { get; } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Util/IValueInitializer.cs b/Castle.Core/Components.DictionaryAdapter/Util/IValueInitializer.cs new file mode 100644 index 0000000..c135856 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Util/IValueInitializer.cs @@ -0,0 +1,21 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + public interface IValueInitializer + { + void Initialize(IDictionaryAdapter dictionaryAdapter, object value); + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Util/IVirtual.cs b/Castle.Core/Components.DictionaryAdapter/Util/IVirtual.cs new file mode 100644 index 0000000..55f2628 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Util/IVirtual.cs @@ -0,0 +1,36 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System; + + public interface IVirtual + { + bool IsReal { get; } + + void Realize(); + + event EventHandler Realized; + } + + public interface IVirtual : IVirtual + { + new T Realize(); + + void AddSite(IVirtualSite site); + + void RemoveSite(IVirtualSite site); + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Util/IVirtualSite.cs b/Castle.Core/Components.DictionaryAdapter/Util/IVirtualSite.cs new file mode 100644 index 0000000..32c66d2 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Util/IVirtualSite.cs @@ -0,0 +1,21 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + public interface IVirtualSite + { + void OnRealizing(T node); + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Util/IVirtualTarget.cs b/Castle.Core/Components.DictionaryAdapter/Util/IVirtualTarget.cs new file mode 100644 index 0000000..257b627 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Util/IVirtualTarget.cs @@ -0,0 +1,21 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + public interface IVirtualTarget + { + void OnRealizing(TNode node, TMember member); + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Util/ListProjection.cs b/Castle.Core/Components.DictionaryAdapter/Util/ListProjection.cs new file mode 100644 index 0000000..6a6f25f --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Util/ListProjection.cs @@ -0,0 +1,603 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.ComponentModel; + using System.Diagnostics; + using System.Reflection; + + using SysPropertyDescriptor = System.ComponentModel.PropertyDescriptor; + + [DebuggerDisplay("Count = {Count}, Adapter = {Adapter}")] + [DebuggerTypeProxy(typeof(ListProjectionDebugView<>))] + public class ListProjection : + IBindingList, // Castle + IBindingList, // System + IEditableObject, + IRevertibleChangeTracking, + ICollectionProjection, + ICollectionAdapterObserver + { + private readonly ICollectionAdapter adapter; + private int addNewIndex = NoIndex; + private int addedIndex = NoIndex; + private int suspendLevel = 0; + private int changedIndex = NoIndex; + private PropertyChangedEventHandler propertyHandler; + private static PropertyDescriptorCollection itemProperties; + private const int NoIndex = -1; + + public ListProjection(ICollectionAdapter adapter) + { + if (adapter == null) + throw new ArgumentNullException(nameof(adapter)); + + this.adapter = adapter; + adapter.Initialize(this); + } + + public int Count + { + get { return adapter.Count; } + } + + public IBindingList AsBindingList + { + get { return this; } + } + + public ICollectionAdapter Adapter + { + get { return adapter; } + } + + public IEqualityComparer Comparer + { + get { return adapter.Comparer ?? EqualityComparer.Default; } + } + + // Generic IBindingList Properties + bool IBindingList.AllowEdit { get { return true; } } + bool IBindingList.AllowNew { get { return true; } } + bool IBindingList.AllowRemove { get { return true; } } + bool IBindingList.SupportsChangeNotification { get { return true; } } + bool IBindingList.SupportsSearching { get { return false; } } + bool IBindingList.SupportsSorting { get { return false; } } + bool IBindingList.IsSorted { get { return false; } } + SysPropertyDescriptor IBindingList.SortProperty { get { return null; } } + ListSortDirection IBindingList.SortDirection { get { return ListSortDirection.Ascending; } } + + // System IBindingList Properties + bool IBindingList.AllowEdit { get { return true; } } + bool IBindingList.AllowNew { get { return true; } } + bool IBindingList.AllowRemove { get { return true; } } + bool IBindingList.SupportsChangeNotification { get { return true; } } + bool IBindingList.SupportsSearching { get { return false; } } + bool IBindingList.SupportsSorting { get { return false; } } + bool IBindingList.IsSorted { get { return false; } } + SysPropertyDescriptor IBindingList.SortProperty { get { return null; } } + ListSortDirection IBindingList.SortDirection { get { return ListSortDirection.Ascending; } } + + // Other Binding Properties + bool IRaiseItemChangedEvents.RaisesItemChangedEvents { get { return true; } } + + // IList Properties + bool IList.IsFixedSize { get { return false; } } + bool IList.IsReadOnly { get { return false; } } + bool ICollection.IsReadOnly { get { return false; } } + bool ICollection.IsSynchronized { get { return false; } } + object ICollection.SyncRoot { get { return this; } } + + public virtual bool Contains(T item) + { + return IndexOf(item) >= 0; + } + + bool IList.Contains(object item) + { + return Contains((T) item); + } + + public int IndexOf(T item) + { + var count = Count; + var comparer = Comparer; + + for (var i = 0; i < count; i++) + if (comparer.Equals(this[i], item)) + return i; + + return -1; + } + + int IList.IndexOf(object item) + { + return IndexOf((T) item); + } + + public void CopyTo(T[] array, int index) + { + var count = Count; + + for (int i = 0, j = index; i < count; i++, j++) + array[j] = this[i]; + } + + void ICollection.CopyTo(Array array, int index) + { + CopyTo((T[]) array, index); + } + + public IEnumerator GetEnumerator() + { + var count = Count; + + for (var i = 0; i < count; i++) + yield return this[i]; + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public T this[int index] + { + get { return adapter[index]; } + set { adapter[index] = value; } + } + + object IList.this[int index] + { + get { return this[index]; } + set { this[index] = (T) value; } + } + + public void Replace(IEnumerable items) + { + (this as ICollectionProjection).Replace(items); + } + + void ICollectionProjection.Replace(IEnumerable items) + { + SuspendEvents(); + try + { + Clear(); + foreach (T item in items) + Add(item); + } + finally + { + ResumeEvents(); + } + } + + protected virtual bool OnReplacing(T oldValue, T newValue) + { + return true; + } + + bool ICollectionAdapterObserver.OnReplacing(T oldValue, T newValue) + { + return OnReplacing(oldValue, newValue); + } + + protected virtual void OnReplaced(T oldValue, T newValue, int index) + { + DetachPropertyChanged(oldValue); + AttachPropertyChanged(newValue); + NotifyListChanged(ListChangedType.ItemChanged, index); + } + + void ICollectionAdapterObserver.OnReplaced(T oldValue, T newValue, int index) + { + OnReplaced(oldValue, newValue, index); + } + + public virtual T AddNew() + { + var item = (T) adapter.AddNew(); + addNewIndex = addedIndex; + return item; + } + + object IBindingList.AddNew() + { + return AddNew(); + } + + public bool IsNew(int index) + { + return index == addNewIndex + && index >= 0; + } + + public virtual void EndNew(int index) + { + if (IsNew(index)) + addNewIndex = NoIndex; + } + + public virtual void CancelNew(int index) + { + if (IsNew(index)) + { + RemoveAt(addNewIndex); + addNewIndex = NoIndex; + } + } + + public virtual bool Add(T item) + { + return adapter.Add(item); + } + + void ICollection.Add(T item) + { + Add(item); + } + + int IList.Add(object item) + { + Add((T) item); + return addedIndex; + } + + public void Insert(int index, T item) + { + if (index < 0) + throw new ArgumentOutOfRangeException(nameof(index)); + + var count = Count; + if (index > count) + throw new ArgumentOutOfRangeException(nameof(index)); + + EndNew(addNewIndex); + if (index == count) + adapter.Add(item); + else + adapter.Insert(index, item); + } + + void IList.Insert(int index, object item) + { + Insert(index, (T) item); + } + + protected virtual bool OnInserting(T value) + { + return true; + } + + bool ICollectionAdapterObserver.OnInserting(T value) + { + return OnInserting(value); + } + + protected virtual void OnInserted(T newValue, int index) + { + addedIndex = index; + AttachPropertyChanged(newValue); + NotifyListChanged(ListChangedType.ItemAdded, index); + } + + void ICollectionAdapterObserver.OnInserted(T newValue, int index) + { + OnInserted(newValue, index); + } + + public virtual bool Remove(T item) + { + var index = IndexOf(item); + if (index < 0) return false; + RemoveAt(index); + return true; + } + + void IList.Remove(object value) + { + Remove((T) value); + } + + public virtual void RemoveAt(int index) + { + EndNew(addNewIndex); + adapter.Remove(index); + } + + public virtual void Clear() + { + EndNew(addNewIndex); + adapter.Clear(); + NotifyListReset(); + } + + void ICollectionProjection.ClearReferences() + { + adapter.ClearReferences(); + } + + protected virtual void OnRemoving(T oldValue) + { + DetachPropertyChanged(oldValue); + } + + void ICollectionAdapterObserver.OnRemoving(T oldValue) + { + OnRemoving(oldValue); + } + + protected virtual void OnRemoved(T oldValue, int index) + { + NotifyListChanged(ListChangedType.ItemDeleted, index); + } + + void ICollectionAdapterObserver.OnRemoved(T oldValue, int index) + { + OnRemoved(oldValue, index); + } + + public bool IsChanged + { + get + { + if (adapter.HasSnapshot == false) + return false; + + var count = Count; + if (adapter.SnapshotCount != count) + return true; + + var comparer = Comparer; + for (var i = 0; i < count; i++) + { + var currentItem = adapter.GetCurrentItem (i); + var snapshotItem = adapter.GetSnapshotItem(i); + + if (comparer.Equals(currentItem, snapshotItem) == false) + return true; + + var tracked = currentItem as IChangeTracking; + if (tracked != null && tracked.IsChanged) + return true; + } + + return false; + } + } + + public void BeginEdit() + { + if (!adapter.HasSnapshot) + adapter.SaveSnapshot(); + } + + public void EndEdit() + { + adapter.DropSnapshot(); + } + + public void CancelEdit() + { + if (adapter.HasSnapshot) + { + adapter.LoadSnapshot(); + adapter.DropSnapshot(); + NotifyListReset(); + } + } + + public void AcceptChanges() + { + BeginEdit(); + } + + public void RejectChanges() + { + CancelEdit(); + } + + private void AttachPropertyChanged(T value) + { + if (typeof(T).IsValueType) + return; + + var notifier = value as INotifyPropertyChanged; + if (notifier == null) + return; + + if (propertyHandler == null) + propertyHandler = HandlePropertyChanged; + + notifier.PropertyChanged += propertyHandler; + } + + private void DetachPropertyChanged(T value) + { + if (typeof(T).IsValueType) + return; + + var notifier = value as INotifyPropertyChanged; + if (notifier == null || propertyHandler == null) + return; + + notifier.PropertyChanged -= propertyHandler; + } + + private void HandlePropertyChanged(object sender, PropertyChangedEventArgs e) + { + T item; + var notify + = EventsEnabled + && CanHandle(sender, e) + && TryGetChangedItem(sender, out item) + && TryGetChangedIndex(item); + + if (notify) + { + var property = GetChangedProperty(e); + var change = new ListChangedEventArgs(ListChangedType.ItemChanged, changedIndex, property); + OnListChanged(change); + } + } + + private bool CanHandle(object sender, PropertyChangedEventArgs e) + { + if (sender == null || e == null || string.IsNullOrEmpty(e.PropertyName)) + { + NotifyListReset(); + return false; + } + return true; + } + + private bool TryGetChangedItem(object sender, out T item) + { + try + { + item = (T) sender; + return true; + } + catch (InvalidCastException) + { + NotifyListReset(); + item = default(T); + return false; + } + } + + private bool TryGetChangedIndex(T item) + { + var isSameItem + = changedIndex >= 0 + && changedIndex < Count + && Comparer.Equals(this[changedIndex], item); + if (isSameItem) + return true; + + changedIndex = IndexOf(item); + if (changedIndex >= 0) + return true; + + DetachPropertyChanged(item); + NotifyListReset(); + return false; + } + + private static SysPropertyDescriptor GetChangedProperty(PropertyChangedEventArgs e) + { + if (itemProperties == null) + itemProperties = TypeDescriptor.GetProperties(typeof(T)); + + return itemProperties.Find(e.PropertyName, true); + } + + public event ListChangedEventHandler ListChanged; + protected virtual void OnListChanged(ListChangedEventArgs args) + { + var handler = ListChanged; + if (handler != null) + handler(this, args); + } + + protected void NotifyListChanged(ListChangedType type, int index) + { + if (EventsEnabled) + OnListChanged(new ListChangedEventArgs(type, index)); + } + + protected void NotifyListReset() + { + if (EventsEnabled) + OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1)); + } + + public bool EventsEnabled + { + get { return suspendLevel == 0; } + } + + public void SuspendEvents() + { + suspendLevel++; + } + + public bool ResumeEvents() + { + var enabled + = suspendLevel == 0 + || --suspendLevel == 0; + + if (enabled) + NotifyListReset(); + + return enabled; + } + + void IBindingList.AddIndex(SysPropertyDescriptor property) + { + // Do nothing + } + + void IBindingList.AddIndex(SysPropertyDescriptor property) + { + // Do nothing + } + + void IBindingList.RemoveIndex(SysPropertyDescriptor property) + { + // Do nothing + } + + void IBindingList.RemoveIndex(SysPropertyDescriptor property) + { + // Do nothing + } + + int IBindingList.Find(SysPropertyDescriptor property, object key) + { + throw new NotSupportedException(); + } + + int IBindingList.Find(SysPropertyDescriptor property, object key) + { + throw new NotSupportedException(); + } + + void IBindingList.ApplySort(SysPropertyDescriptor property, ListSortDirection direction) + { + throw new NotSupportedException(); + } + + void IBindingList.ApplySort(SysPropertyDescriptor property, ListSortDirection direction) + { + throw new NotSupportedException(); + } + + void IBindingList.RemoveSort() + { + throw new NotSupportedException(); + } + + void IBindingList.RemoveSort() + { + throw new NotSupportedException(); + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Util/ListProjectionDebugView.cs b/Castle.Core/Components.DictionaryAdapter/Util/ListProjectionDebugView.cs new file mode 100644 index 0000000..31b75c3 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Util/ListProjectionDebugView.cs @@ -0,0 +1,48 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System; + using System.Diagnostics; + + internal sealed class ListProjectionDebugView + { + private readonly ListProjection projection; + + public ListProjectionDebugView(ListProjection projection) + { + if (projection == null) + throw new ArgumentNullException(nameof(projection)); + + this.projection = projection; + } + + [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] + public T[] Items + { + get + { + T[] array = new T[projection.Count]; + projection.CopyTo(array, 0); + return array; + } + } + + public ICollectionAdapter Adapter + { + get { return projection.Adapter; } + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Util/SetProjection.cs b/Castle.Core/Components.DictionaryAdapter/Util/SetProjection.cs new file mode 100644 index 0000000..f8c7e1a --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Util/SetProjection.cs @@ -0,0 +1,159 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System.Collections.Generic; + using System.Diagnostics; + using System.Linq; + + public class SetProjection : ListProjection, ISet + { + private readonly HashSet set; + + public SetProjection(ICollectionAdapter adapter) + : base(adapter) + { + set = new HashSet(); + Repopulate(); + } + + public override bool Contains(T item) + { + return set.Contains(item); + } + + public bool IsSubsetOf(IEnumerable other) + { + return set.IsSubsetOf(other); + } + + public bool IsSupersetOf(IEnumerable other) + { + return set.IsSupersetOf(other); + } + + public bool IsProperSubsetOf(IEnumerable other) + { + return set.IsProperSubsetOf(other); + } + + public bool IsProperSupersetOf(IEnumerable other) + { + return set.IsProperSupersetOf(other); + } + + public bool Overlaps(IEnumerable other) + { + return set.Overlaps(other); + } + + public bool SetEquals(IEnumerable other) + { + return set.SetEquals(other); + } + + private void Repopulate() + { + SuspendEvents(); + + var count = Count; + for (var index = 0; index < count;) + { + var value = this[index]; + + if (!set.Add(value)) + { RemoveAt(index); count--; } + else + index++; + } + + ResumeEvents(); + } + + public override void EndNew(int index) + { + if (IsNew(index) && OnInserting(this[index])) + base.EndNew(index); + else + CancelNew(index); + } + + public override bool Add(T item) + { + return !set.Contains(item) + && base.Add(item); + } + + protected override bool OnInserting(T value) + { + return set.Add(value); + } + + protected override bool OnReplacing(T oldValue, T newValue) + { + if (!set.Add(newValue)) + return false; + + set.Remove(oldValue); + return true; + } + + public override bool Remove(T item) + { + return set .Remove(item) + && base.Remove(item); + } + + public override void RemoveAt(int index) + { + set .Remove (this[index]); + base.RemoveAt(index); + } + + public override void Clear() + { + set .Clear(); + base.Clear(); + } + + public void UnionWith(IEnumerable other) + { + foreach (var value in other) + Add(value); + } + + public void ExceptWith(IEnumerable other) + { + foreach (var value in other) + Remove(value); + } + + public void IntersectWith(IEnumerable other) + { + var removals = set.Except(other).ToArray(); + + ExceptWith(removals); + } + + public void SymmetricExceptWith(IEnumerable other) + { + var removals = set.Intersect(other).ToArray(); + var additions = other.Except(removals); + + ExceptWith(removals); + UnionWith(additions); + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Util/VirtualObject.cs b/Castle.Core/Components.DictionaryAdapter/Util/VirtualObject.cs new file mode 100644 index 0000000..c17a015 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Util/VirtualObject.cs @@ -0,0 +1,97 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System; + using System.Collections.Generic; + + public abstract class VirtualObject : IVirtual + { + private List> sites; + + protected VirtualObject() { } + + protected VirtualObject(IVirtualSite site) + { + sites = new List> { site }; + } + + public abstract bool IsReal { get; } + + protected void AddSite(IVirtualSite site) + { + if (sites != null) + { + sites.Add(site); + } + } + + void IVirtual.AddSite(IVirtualSite site) + { + AddSite(site); + } + + protected void RemoveSite(IVirtualSite site) + { + if (sites != null) + { + var index = sites.IndexOf(site); + if (index != -1) + sites.RemoveAt(index); + } + } + + void IVirtual.RemoveSite(IVirtualSite site) + { + RemoveSite(site); + } + + public TNode Realize() + { + TNode node; + if (TryRealize(out node)) + { + if (sites != null) + { + var count = sites.Count; + for (var i = 0; i < count; i++) + sites[i].OnRealizing(node); + sites = null; + } + + OnRealized(); + } + return node; + } + + void IVirtual.Realize() + { + Realize(); + } + + protected abstract bool TryRealize(out TNode node); + + public event EventHandler Realized; + protected virtual void OnRealized() + { + var handler = Realized; + if (handler != null) + { + handler(this, EventArgs.Empty); + Realized = null; + } + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Util/VirtualSite.cs b/Castle.Core/Components.DictionaryAdapter/Util/VirtualSite.cs new file mode 100644 index 0000000..918dc70 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Util/VirtualSite.cs @@ -0,0 +1,74 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System; + using System.Collections.Generic; + using Castle.Core; + + public sealed class VirtualSite : + IVirtualSite, + IEquatable> + { + private readonly IVirtualTarget target; + private readonly TMember member; + + public VirtualSite(IVirtualTarget target, TMember member) + { + this.target = target; + this.member = member; + } + + public IVirtualTarget Target + { + get { return target; } + } + + public TMember Member + { + get { return member; } + } + + public void OnRealizing(TNode node) + { + target.OnRealizing(node, member); + } + + public override bool Equals(object obj) + { + return Equals(obj as VirtualSite); + } + + public bool Equals(VirtualSite other) + { + return other != null + && TargetComparer.Equals(target, other.target) + && MemberComparer.Equals(member, other.member); + } + + public override int GetHashCode() + { + return 0x72F10A3D + + 37 * TargetComparer.GetHashCode(target) + + 37 * MemberComparer.GetHashCode(member); + } + + private static readonly IEqualityComparer> + TargetComparer = ReferenceEqualityComparer>.Instance; + + private static readonly IEqualityComparer + MemberComparer = EqualityComparer.Default; + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Core/DefaultXmlReferenceFormat.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Core/DefaultXmlReferenceFormat.cs new file mode 100644 index 0000000..c175dce --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Core/DefaultXmlReferenceFormat.cs @@ -0,0 +1,65 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + using System.Globalization; + + public sealed class DefaultXmlReferenceFormat : IXmlReferenceFormat + { + public static readonly DefaultXmlReferenceFormat + Instance = new DefaultXmlReferenceFormat(); + + private DefaultXmlReferenceFormat() { } + + public bool TryGetIdentity(IXmlNode node, out int id) + { + var text = node.GetAttribute(XRef.Id); + return int.TryParse(text, IntegerStyle, Culture, out id); + } + + public bool TryGetReference(IXmlNode node, out int id) + { + var text = node.GetAttribute(XRef.Ref); + return int.TryParse(text, IntegerStyle, Culture, out id); + } + + public void SetIdentity(IXmlNode node, int id) + { + node.SetAttribute(XRef.Id, id.ToString(Culture)); + } + + public void SetReference(IXmlNode node, int id) + { + node.SetAttribute(XRef.Ref, id.ToString(Culture)); + } + + public void ClearIdentity(IXmlNode node) + { + node.SetAttribute(XRef.Id, null); + } + + public void ClearReference(IXmlNode node) + { + node.SetAttribute(XRef.Ref, null); + } + + private const NumberStyles + IntegerStyle = NumberStyles.Integer; + + private static readonly IFormatProvider + Culture = CultureInfo.InvariantCulture; + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Core/IXmlReferenceFormat.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Core/IXmlReferenceFormat.cs new file mode 100644 index 0000000..e7478e3 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Core/IXmlReferenceFormat.cs @@ -0,0 +1,28 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + public interface IXmlReferenceFormat + { + bool TryGetIdentity (IXmlNode node, out int id); + bool TryGetReference (IXmlNode node, out int id); + + void SetIdentity (IXmlNode node, int id); + void SetReference (IXmlNode node, int id); + + void ClearIdentity (IXmlNode node); + void ClearReference (IXmlNode node); + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Core/XmlAdapter.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Core/XmlAdapter.cs new file mode 100644 index 0000000..5f500c4 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Core/XmlAdapter.cs @@ -0,0 +1,504 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.Linq; + using System.Xml; + using System.Xml.Serialization; + using IBindingList = System.ComponentModel.IBindingList; + using ListChangedEventArgs = System.ComponentModel.ListChangedEventArgs; + using ListChangedType = System.ComponentModel.ListChangedType; + + public class XmlAdapter : DictionaryBehaviorAttribute, + IDictionaryInitializer, + IDictionaryPropertyGetter, + IDictionaryPropertySetter, + IDictionaryCreateStrategy, + IDictionaryCopyStrategy, + IDictionaryReferenceManager, + IVirtual, + IXmlNodeSource + { + private IXmlNode node; + private object source; + private XmlReferenceManager references; + private XmlMetadata primaryXmlMeta; + private Dictionary secondaryXmlMetas; + private readonly bool isRoot; + + public XmlAdapter() + : this(new XmlDocument()) { } + + public XmlAdapter(XmlNode node) + { + if (node == null) + throw Error.ArgumentNull(nameof(node)); + + this.source = node; + this.isRoot = true; + } + + /// + /// Initializes a new instance of the class + /// that represents a child object in a larger object graph. + /// + public XmlAdapter(IXmlNode node, XmlReferenceManager references) + { + if (node == null) + throw Error.ArgumentNull(nameof(node)); + if (references == null) + throw Error.ArgumentNull(nameof(references)); + + this.node = node; + this.references = references; + } + + public bool IsReal + { + get { return node != null && node.IsReal; } + } + + public IXmlNode Node + { + get { return node; } + } + + internal XmlReferenceManager References + { + get { return references; } + } + + object IDictionaryCreateStrategy.Create(IDictionaryAdapter parent, Type type, IDictionary dictionary) + { + var adapter = new XmlAdapter(new XmlDocument()); + return parent.CreateChildAdapter(type, adapter, dictionary); + } + + void IDictionaryInitializer.Initialize(IDictionaryAdapter dictionaryAdapter, object[] behaviors) + { + var meta = dictionaryAdapter.Meta; + + if (primaryXmlMeta == null) + InitializePrimary (meta, dictionaryAdapter); + else + InitializeSecondary(meta); + + InitializeBaseTypes (meta); + InitializeStrategies(dictionaryAdapter); + InitializeReference (dictionaryAdapter); + } + + private void InitializePrimary(DictionaryAdapterMeta meta, IDictionaryAdapter dictionaryAdapter) + { + RequireXmlMeta(meta); + primaryXmlMeta = meta.GetXmlMeta(); + + if (node == null) + node = GetBaseNode(); + if (!node.IsReal) + node.Realized += HandleNodeRealized; + + if (references == null) + references = new XmlReferenceManager(node, DefaultXmlReferenceFormat.Instance); + InitializeReference(this); + } + + private void InitializeSecondary(DictionaryAdapterMeta meta) + { + AddSecondaryXmlMeta(meta); + } + + private void InitializeBaseTypes(DictionaryAdapterMeta meta) + { + foreach (var type in meta.Type.GetInterfaces()) + { + var ns = type.Namespace; + var ignore + = ns == "Castle.Components.DictionaryAdapter" + || ns == "System.ComponentModel"; + if (ignore) continue; + + var baseMeta = meta.GetAdapterMeta(type); + AddSecondaryXmlMeta(baseMeta); + } + } + + private void InitializeStrategies(IDictionaryAdapter dictionaryAdapter) + { + var instance = dictionaryAdapter.This; + if (instance.CreateStrategy == null) + { + instance.CreateStrategy = this; + instance.AddCopyStrategy(this); + } + } + + private void InitializeReference(object value) + { + if (isRoot) + // If this is a root XmlAdapter, we must pre-populate the reference manager with + // this XmlAdapter and its IDictionaryAdapters. This enables child objects in the + // graph to reference the root object. + references.Add(node, this, value, true); + } + + private void AddSecondaryXmlMeta(DictionaryAdapterMeta meta) + { + if (secondaryXmlMetas == null) + secondaryXmlMetas = new Dictionary(); + else if (secondaryXmlMetas.ContainsKey(meta.Type)) + return; + + RequireXmlMeta(meta); + secondaryXmlMetas[meta.Type] = meta.GetXmlMeta(); + } + + private static void RequireXmlMeta(DictionaryAdapterMeta meta) + { + if (!meta.HasXmlMeta()) + throw Error.XmlMetadataNotAvailable(meta.Type); + } + + bool IDictionaryCopyStrategy.Copy(IDictionaryAdapter source, IDictionaryAdapter target, ref Func selector) + { + if (selector == null) + selector = property => HasProperty(property.PropertyName, source); + return false; + } + + object IDictionaryPropertyGetter.GetPropertyValue(IDictionaryAdapter dictionaryAdapter, + string key, object storedValue, PropertyDescriptor property, bool ifExists) + { + XmlAccessor accessor; + if (TryGetAccessor(key, property, null != storedValue, out accessor)) + { + storedValue = accessor.GetPropertyValue(node, dictionaryAdapter, references, !ifExists); + if (null != storedValue) + { + AttachObservers(storedValue, dictionaryAdapter, property); + dictionaryAdapter.StoreProperty(property, key, storedValue); + } + } + return storedValue; + } + + bool IDictionaryPropertySetter.SetPropertyValue(IDictionaryAdapter dictionaryAdapter, + string key, ref object value, PropertyDescriptor property) + { + XmlAccessor accessor; + if (TryGetAccessor(key, property, false, out accessor)) + { + if (value != null && dictionaryAdapter.ShouldClearProperty(property, value)) + value = null; + var oldValue = dictionaryAdapter.ReadProperty(key); + accessor.SetPropertyValue(node, dictionaryAdapter, references, oldValue, ref value); + } + return true; + } + + private static string EnsureKey(string key, PropertyDescriptor property) + { + return string.IsNullOrEmpty(key) + ? property.PropertyName + : key; + } + + private IXmlNode GetBaseNode() + { + var node = GetSourceNode(); + + if (node.IsElement) + return node; + if (node.IsAttribute) + throw Error.NotSupported(); + // must be root + + var cursor = primaryXmlMeta.SelectBase(node); + return cursor.MoveNext() + ? cursor.Save() + : cursor; + } + + private IXmlNode GetSourceNode() + { + var xmlNode = source as XmlNode; + if (xmlNode != null) + return new SysXmlNode(xmlNode, primaryXmlMeta.ClrType, primaryXmlMeta.Context); + + throw Error.NotSupported(); + } + + private bool TryGetAccessor(string key, PropertyDescriptor property, bool requireVolatile, out XmlAccessor accessor) + { + accessor = property.HasAccessor() + ? property.GetAccessor() + : CreateAccessor(key, property); + + if (accessor.IsIgnored) + return Try.Failure(out accessor); + if (requireVolatile && !accessor.IsVolatile) + return Try.Failure(out accessor); + return true; + } + + private XmlAccessor CreateAccessor(string key, PropertyDescriptor property) + { + var accessor = null as XmlAccessor; + var isVolatile = false; + var isReference = false; + + if (string.IsNullOrEmpty(key)) + accessor = CreateAccessor(key, property, XmlSelfAccessor.Factory); + + foreach (var behavior in property.Annotations) + { + if (IsIgnoreBehavior(behavior)) + return XmlIgnoreBehaviorAccessor.Instance; + else if (IsVolatileBehavior(behavior)) + isVolatile = true; + else if (IsReferenceBehavior(behavior)) + isReference = true; + else + TryApplyBehavior(key, property, behavior, ref accessor); + } + + if (accessor == null) + accessor = CreateAccessor(key, property, XmlDefaultBehaviorAccessor.Factory); + + accessor.ConfigureVolatile (isVolatile); + accessor.ConfigureReference(isReference); + accessor.Prepare(); + property.SetAccessor(accessor); + return accessor; + } + + private bool TryApplyBehavior(string key, PropertyDescriptor property, object behavior, ref XmlAccessor accessor) + { + return + TryApplyBehavior + (key, property, behavior, ref accessor, XmlElementBehaviorAccessor.Factory) + || + TryApplyBehavior + (key, property, behavior, ref accessor, XmlArrayBehaviorAccessor.Factory) + || + TryApplyBehavior + (key, property, behavior, ref accessor, XmlArrayBehaviorAccessor.Factory) + || + TryApplyBehavior + (key, property, behavior, ref accessor, XmlAttributeBehaviorAccessor.Factory) + || + TryApplyBehavior + (key, property, behavior, ref accessor, XPathBehaviorAccessor.Factory) + || + TryApplyBehavior + (key, property, behavior, ref accessor, XPathBehaviorAccessor.Factory) + || + TryApplyBehavior + (key, property, behavior, ref accessor, XPathBehaviorAccessor.Factory) + ; + } + + private bool TryApplyBehavior(string key, PropertyDescriptor property, object behavior, + ref XmlAccessor accessor, XmlAccessorFactory factory) + where TBehavior : class + where TAccessor : XmlAccessor, IConfigurable + { + var typedBehavior = behavior as TBehavior; + if (typedBehavior == null) + return false; + + if (accessor == null) + accessor = CreateAccessor(key, property, factory); + + var typedAccessor = accessor as TAccessor; + if (typedAccessor == null) + throw Error.AttributeConflict(key); + + typedAccessor.Configure(typedBehavior); + return true; + } + + private TAccessor CreateAccessor(string key, PropertyDescriptor property, XmlAccessorFactory factory) + where TAccessor : XmlAccessor + { + var xmlMeta = GetXmlMetadata(property.Property.DeclaringType); + var accessor = factory(key, property.PropertyType, xmlMeta.Context); + if (xmlMeta.IsNullable.HasValue) + accessor.ConfigureNillable(xmlMeta.IsNullable.Value); + if (xmlMeta.IsReference.HasValue) + accessor.ConfigureReference(xmlMeta.IsReference.Value); + return accessor; + } + + private XmlMetadata GetXmlMetadata(Type type) + { + if (type == primaryXmlMeta.ClrType) + return primaryXmlMeta; + + XmlMetadata xmlMeta; + if (secondaryXmlMetas.TryGetValue(type, out xmlMeta)) + return xmlMeta; + + throw Error.XmlMetadataNotAvailable(type); + } + + private static bool IsIgnoreBehavior(object behavior) + { + return behavior is XmlIgnoreAttribute; + } + + private static bool IsVolatileBehavior(object behavior) + { + return behavior is VolatileAttribute; + } + + private static bool IsReferenceBehavior(object behavior) + { + return behavior is ReferenceAttribute; + } + + void IVirtual.Realize() + { + throw new NotSupportedException("XmlAdapter does not support realization via IVirtual.Realize()."); + } + + public event EventHandler Realized; + protected virtual void OnRealized() + { + if (Realized != null) + Realized(this, EventArgs.Empty); + } + + private void HandleNodeRealized(object sender, EventArgs e) + { + OnRealized(); + } + + private void AttachObservers(object value, IDictionaryAdapter dictionaryAdapter, PropertyDescriptor property) + { + var bindingList = value as IBindingList; + if (bindingList != null) + bindingList.ListChanged += (s,e) => HandleListChanged(s, e, dictionaryAdapter, property); + } + + private void HandleListChanged(object value, ListChangedEventArgs args, IDictionaryAdapter dictionaryAdapter, PropertyDescriptor property) + { + var change = args.ListChangedType; + var changed + = change == ListChangedType.ItemAdded + || change == ListChangedType.ItemDeleted + || change == ListChangedType.ItemMoved + || change == ListChangedType.Reset; + + if (changed && dictionaryAdapter.ShouldClearProperty(property, value)) + { + value = null; + dictionaryAdapter.SetProperty(property.PropertyName, ref value); + } + } + + bool IDictionaryReferenceManager.IsReferenceProperty(IDictionaryAdapter dictionaryAdapter, string propertyName) + { + var xmlAdapter = XmlAdapter.For(dictionaryAdapter, false); + if (xmlAdapter == null) + return false; + + var instance = dictionaryAdapter.This; + + PropertyDescriptor property; + if (!instance.Properties.TryGetValue(propertyName, out property)) + return false; + + var key = property.GetKey(dictionaryAdapter, propertyName, instance.Descriptor); + + XmlAccessor accessor; + return xmlAdapter.TryGetAccessor(key, property, false, out accessor) + && accessor.IsReference; + } + + bool IDictionaryReferenceManager.TryGetReference(object keyObject, out object inGraphObject) + { + return references.TryGet(keyObject, out inGraphObject); + } + + void IDictionaryReferenceManager.AddReference(object keyObject, object relatedObject, bool isInGraph) + { + references.Add(null, keyObject, relatedObject, isInGraph); + } + + public override IDictionaryBehavior Copy() + { + return null; + } + + public static XmlAdapter For(object obj) + { + return For(obj, true); + } + + public static XmlAdapter For(object obj, bool required) + { + if (obj == null) + if (!required) return null; + else throw Error.ArgumentNull(nameof(obj)); + + var dictionaryAdapter = obj as IDictionaryAdapter; + if (dictionaryAdapter == null) + if (!required) return null; + else throw Error.NotDictionaryAdapter(nameof(obj)); + + var descriptor = dictionaryAdapter.This.Descriptor; + if (descriptor == null) + if (!required) return null; + else throw Error.NoInstanceDescriptor(nameof(obj)); + + var getters = descriptor.Getters; + if (getters == null) + if (!required) return null; + else throw Error.NoXmlAdapter(nameof(obj)); + + XmlAdapter xmlAdapter; + foreach (var getter in getters) + if (null != (xmlAdapter = getter as XmlAdapter)) + return xmlAdapter; + + if (!required) return null; + else throw Error.NoXmlAdapter(nameof(obj)); + } + + public static bool IsPropertyDefined(string propertyName, IDictionaryAdapter dictionaryAdapter) + { + var xmlAdapter = XmlAdapter.For(dictionaryAdapter, true); + return xmlAdapter != null + && xmlAdapter.HasProperty(propertyName, dictionaryAdapter); + } + + public bool HasProperty(string propertyName, IDictionaryAdapter dictionaryAdapter) + { + var key = dictionaryAdapter.GetKey(propertyName); + if (key == null) + return false; + + PropertyDescriptor property; + XmlAccessor accessor; + return dictionaryAdapter.This.Properties.TryGetValue(propertyName, out property) + && TryGetAccessor(key, property, false, out accessor) + && accessor.IsPropertyDefined(node); + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Core/XmlMetadata.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Core/XmlMetadata.cs new file mode 100644 index 0000000..f8919fe --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Core/XmlMetadata.cs @@ -0,0 +1,385 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Reflection; + using System.Xml; + using System.Xml.Serialization; + + public class XmlMetadata : IXmlKnownType, IXmlKnownTypeMap, IXmlIncludedType, IXmlIncludedTypeMap + { + private readonly Type clrType; + private readonly bool? qualified; + private readonly bool? isNullable; + private readonly bool? isReference; + private readonly string rootLocalName; + private readonly string rootNamespaceUri; + private readonly string childNamespaceUri; + private readonly string typeLocalName; + private readonly string typeNamespaceUri; + + private readonly HashSet reservedNamespaceUris; + private List pendingIncludes; + private readonly XmlIncludedTypeSet includedTypes; + private readonly XmlContext context; + private readonly DictionaryAdapterMeta source; + private readonly CompiledXPath path; + + public XmlMetadata(DictionaryAdapterMeta meta, IEnumerable reservedNamespaceUris) + { + if (meta == null) + throw Error.ArgumentNull(nameof(meta)); + if (reservedNamespaceUris == null) + throw Error.ArgumentNull(nameof(reservedNamespaceUris)); + + source = meta; + clrType = meta.Type; + context = new XmlContext(this); + includedTypes = new XmlIncludedTypeSet(); + + this.reservedNamespaceUris + = reservedNamespaceUris as HashSet + ?? new HashSet(reservedNamespaceUris); + + var xmlRoot = null as XmlRootAttribute; + var xmlType = null as XmlTypeAttribute; + var xmlDefaults = null as XmlDefaultsAttribute; + var xmlInclude = null as XmlIncludeAttribute; + var xmlNamespace = null as XmlNamespaceAttribute; + var reference = null as ReferenceAttribute; + var xPath = null as XPathAttribute; + var xPathVariable = null as XPathVariableAttribute; + var xPathFunction = null as XPathFunctionAttribute; + + foreach (var behavior in meta.Behaviors) + { + if (TryCast(behavior, ref xmlRoot )) { } + else if (TryCast(behavior, ref xmlType )) { } + else if (TryCast(behavior, ref xmlDefaults )) { } + else if (TryCast(behavior, ref xmlInclude )) { AddPendingInclude(xmlInclude); } + else if (TryCast(behavior, ref xmlNamespace )) { context.AddNamespace(xmlNamespace ); } + else if (TryCast(behavior, ref reference )) { } + else if (TryCast(behavior, ref xPath )) { } + else if (TryCast(behavior, ref xPathVariable)) { context.AddVariable (xPathVariable); } + else if (TryCast(behavior, ref xPathFunction)) { context.AddFunction (xPathFunction); } + } + + if (xmlDefaults != null) + { + qualified = xmlDefaults.Qualified; + isNullable = xmlDefaults.IsNullable; + } + + if (reference != null) + { + isReference = true; + } + + typeLocalName = XmlConvert.EncodeLocalName + ( + (!meta.HasXmlType() ? null : meta.GetXmlType().NonEmpty()) ?? + (xmlType == null ? null : xmlType.TypeName .NonEmpty()) ?? + GetDefaultTypeLocalName(clrType) + ); + + rootLocalName = XmlConvert.EncodeLocalName + ( + (xmlRoot == null ? null : xmlRoot.ElementName.NonEmpty()) ?? + typeLocalName + ); + + typeNamespaceUri = + ( + (xmlType == null ? null : xmlType.Namespace) + ); + + rootNamespaceUri = + ( + (xmlRoot == null ? null : xmlRoot.Namespace) + ); + + childNamespaceUri = + ( + typeNamespaceUri ?? + rootNamespaceUri + ); + + if (xPath != null) + { + path = xPath.GetPath; + path.SetContext(context); + } + } + + public Type ClrType + { + get { return clrType; } + } + + public bool? Qualified + { + get { return qualified; } + } + + public bool? IsNullable + { + get { return isNullable; } + } + + public bool? IsReference + { + get { return isReference; } + } + + public XmlName Name + { + get { return new XmlName(rootLocalName, rootNamespaceUri); } + } + + public XmlName XsiType + { + get { return new XmlName(typeLocalName, typeNamespaceUri); } + } + + XmlName IXmlIdentity.XsiType + { + get { return XmlName.Empty; } + } + + public string ChildNamespaceUri + { + get { return childNamespaceUri; } + } + + public IEnumerable ReservedNamespaceUris + { + get { return reservedNamespaceUris.ToArray(); } + } + + public XmlIncludedTypeSet IncludedTypes + { + get { ProcessPendingIncludes(); return includedTypes; } + } + + public IXmlContext Context + { + get { return context; } + } + + public CompiledXPath Path + { + get { return path; } + } + + IXmlKnownType IXmlKnownTypeMap.Default + { + get { return this; } + } + + IXmlIncludedType IXmlIncludedTypeMap.Default + { + get { return this; } + } + + public bool IsReservedNamespaceUri(string namespaceUri) + { + return reservedNamespaceUris.Contains(namespaceUri); + } + + public IXmlCursor SelectBase(IXmlNode node) // node is root + { + if (path != null) + return node.Select(path, this, context, RootFlags); + + return node.SelectChildren(this, context, RootFlags); + } + + private bool IsMatch(IXmlIdentity xmlIdentity) + { + var name = xmlIdentity.Name; + + return NameComparer.Equals(rootLocalName, name.LocalName) + && (rootNamespaceUri == null || NameComparer.Equals(rootNamespaceUri, name.NamespaceUri)); + } + + private bool IsMatch(Type clrType) + { + return clrType == this.clrType; + } + + public bool TryGet(IXmlIdentity xmlIdentity, out IXmlKnownType knownType) + { + return IsMatch(xmlIdentity) + ? Try.Success(out knownType, this) + : Try.Failure(out knownType); + } + + public bool TryGet(Type clrType, out IXmlKnownType knownType) + { + return IsMatch(clrType) + ? Try.Success(out knownType, this) + : Try.Failure(out knownType); + } + + public bool TryGet(XmlName xsiType, out IXmlIncludedType includedType) + { + return xsiType == XmlName.Empty || xsiType == this.XsiType + ? Try.Success(out includedType, this) + : Try.Failure(out includedType); + } + + public bool TryGet(Type clrType, out IXmlIncludedType includedType) + { + return clrType == this.clrType + ? Try.Success(out includedType, this) + : Try.Failure(out includedType); + } + + private void AddPendingInclude(XmlIncludeAttribute attribute) + { + if (pendingIncludes == null) + pendingIncludes = new List(); + pendingIncludes.Add(attribute.Type); + } + + private void ProcessPendingIncludes() + { + var clrTypes = pendingIncludes; + pendingIncludes = null; + if (clrTypes == null) return; + + foreach (var clrType in clrTypes) + { + var xsiType = GetDefaultXsiType(clrType); + var includedType = new XmlIncludedType(xsiType, clrType); + includedTypes.Add(includedType); + } + } + + public XmlName GetDefaultXsiType(Type clrType) + { + if (clrType == this.clrType) + return this.XsiType; + + IXmlIncludedType include; + if (includedTypes.TryGet(clrType, out include)) + return include.XsiType; + + var kind = XmlTypeSerializer.For(clrType).Kind; + switch (kind) + { + case XmlTypeKind.Complex: + if (!clrType.IsInterface) goto default; + return GetXmlMetadata(clrType).XsiType; + + case XmlTypeKind.Collection: + var itemClrType = clrType.GetCollectionItemType(); + var itemXsiType = GetDefaultXsiType(itemClrType); + return new XmlName("ArrayOf" + itemXsiType.LocalName, null); + + default: + return new XmlName(clrType.Name, null); + } + } + + public IEnumerable GetIncludedTypes(Type baseType) + { + var queue = new Queue(); + var visited = new HashSet(); + XmlMetadata metadata; + + visited.Add(baseType); + if (TryGetXmlMetadata(baseType, out metadata)) + queue.Enqueue(metadata); + metadata = this; + + for (;;) + { + foreach (var includedType in metadata.IncludedTypes) + { + var clrType = includedType.ClrType; + var relevant + = baseType != clrType + && baseType.IsAssignableFrom(clrType) + && visited.Add(clrType); + + if (!relevant) + continue; + + yield return includedType; + + if (TryGetXmlMetadata(clrType, out metadata)) + queue.Enqueue(metadata); + } + + if (queue.Count == 0) + yield break; + + metadata = queue.Dequeue(); + } + } + + private bool TryGetXmlMetadata(Type clrType, out XmlMetadata metadata) + { + var kind = XmlTypeSerializer.For(clrType).Kind; + + return kind == XmlTypeKind.Complex && clrType.IsInterface + ? Try.Success(out metadata, GetXmlMetadata(clrType)) + : Try.Failure(out metadata); + } + + private XmlMetadata GetXmlMetadata(Type clrType) + { + return source + .GetAdapterMeta(clrType) + .GetXmlMeta(); + } + + private string GetDefaultTypeLocalName(Type clrType) + { + var name = clrType.Name; + return IsInterfaceName(name) + ? name.Substring(1) + : name; + } + + private static bool IsInterfaceName(string name) + { + return name.Length > 1 + && name[0] == 'I' + && char.IsUpper(name, 1); + } + + private static bool TryCast(object obj, ref T result) + where T : class + { + var value = obj as T; + if (null == value) return false; + + result = value; + return true; + } + + protected static readonly StringComparer + NameComparer = StringComparer.OrdinalIgnoreCase; + + private const CursorFlags RootFlags + = CursorFlags.Elements + | CursorFlags.Mutable; + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Core/XmlMetadataBehavior.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Core/XmlMetadataBehavior.cs new file mode 100644 index 0000000..93306ba --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Core/XmlMetadataBehavior.cs @@ -0,0 +1,56 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System.Collections.Generic; + using System.Linq; + + public class XmlMetadataBehavior : DictionaryBehaviorAttribute, IDictionaryMetaInitializer + { + public static readonly XmlMetadataBehavior + Default = new XmlMetadataBehavior(); + + private readonly HashSet reservedNamespaceUris = new HashSet + { + Xmlns.NamespaceUri, + Xsi .NamespaceUri, + XRef .NamespaceUri + }; + + public IEnumerable ReservedNamespaceUris + { + get { return reservedNamespaceUris.ToArray(); } + } + + public XmlMetadataBehavior AddReservedNamespaceUri(string uri) + { + reservedNamespaceUris.Add(uri); + return this; + } + + void IDictionaryMetaInitializer.Initialize(IDictionaryAdapterFactory factory, DictionaryAdapterMeta meta) + { + meta.SetXmlMeta(new XmlMetadata(meta, reservedNamespaceUris)); + } + + bool IDictionaryMetaInitializer.ShouldHaveBehavior(object behavior) + { + return behavior is XmlDefaultsAttribute + || behavior is XmlNamespaceAttribute + || behavior is XPathVariableAttribute + || behavior is XPathFunctionAttribute; + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Core/XmlReferenceManager.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Core/XmlReferenceManager.cs new file mode 100644 index 0000000..c325e7e --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Core/XmlReferenceManager.cs @@ -0,0 +1,584 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Reflection; + + using Castle.Core; + using Castle.Core.Internal; + + public class XmlReferenceManager + { + private readonly Dictionary entriesById; + private readonly WeakKeyDictionary entriesByValue; + private readonly IXmlReferenceFormat format; + private int nextId; + + public XmlReferenceManager(IXmlNode root, IXmlReferenceFormat format) + { + entriesById = new Dictionary(); + entriesByValue = new WeakKeyDictionary(ReferenceEqualityComparer.Instance); + this.format = format; + this.nextId = 1; + + Populate(root); + } + + #region Populate + + private void Populate(IXmlNode node) + { + var references = new List(); + var iterator = node.SelectSubtree(); + + while (iterator.MoveNext()) + PopulateFromNode(iterator, references); + + PopulateDeferredReferences(references); + } + + private void PopulateFromNode(IXmlIterator node, ICollection references) + { + int id; + if (format.TryGetIdentity(node, out id)) + PopulateIdentity(id, node.Save()); + else if (format.TryGetReference(node, out id)) + PopulateReference(id, node.Save(), references); + } + + private void PopulateIdentity(int id, IXmlNode node) + { + Entry entry; + if (!entriesById.TryGetValue(id, out entry)) + entriesById.Add(id, new Entry(id, node)); + if (nextId <= id) + nextId = ++id; + } + + private void PopulateReference(int id, IXmlNode node, ICollection references) + { + Entry entry; + if (entriesById.TryGetValue(id, out entry)) + entry.AddReference(node); + else + references.Add(new Reference(id, node)); + } + + private void PopulateDeferredReferences(ICollection references) + { + foreach (var reference in references) + { + Entry entry; + if (entriesById.TryGetValue(reference.Id, out entry)) + entry.AddReference(reference.Node); + } + } + + #endregion + + public bool TryGet(object keyObject, out object inGraphObject) + { + Entry entry; + if (entriesByValue.TryGetValue(keyObject, out entry)) + { + inGraphObject = keyObject; + TryGetCompatibleValue(entry, keyObject.GetComponentType(), ref inGraphObject); + return true; + } + else + { + inGraphObject = null; + return false; + } + } + + public void Add(IXmlNode node, object keyValue, object newValue, bool isInGraph) + { + if (keyValue == null) + throw Error.ArgumentNull(nameof(keyValue)); + if (newValue == null) + throw Error.ArgumentNull(nameof(newValue)); + + var type = newValue.GetComponentType(); + if (ShouldExclude(type)) + return; + if (entriesByValue.ContainsKey(newValue)) + return; + + Entry entry; + if (entriesByValue.TryGetValue(keyValue, out entry)) + { + if (newValue == keyValue) + return; + } + else if (node != null) + { + bool reference; + if (!TryGetEntry(node, out entry, out reference)) + entry = new Entry(node); + } + else return; + + AddValueCore(entry, type, newValue, isInGraph); + } + + public bool OnGetStarting(ref IXmlNode node, ref object value, out object token) + { + Entry entry; + bool isReference; + + var type = node.ClrType; + if (ShouldExclude(type)) + { token = null; return true; } + + if (!TryGetEntry(node, out entry, out isReference)) + { token = CreateEntryToken; return true; } + + if (isReference) + RedirectNode(ref node, entry); + + var proceed = ! TryGetCompatibleValue(entry, node.ClrType, ref value); + + token = proceed ? entry : null; + return proceed; + } + + public void OnGetCompleted(IXmlNode node, object value, object token) + { + if (value == null) + return; + + var type = node.ClrType; + if (ShouldExclude(type)) + return; + + if (entriesByValue.ContainsKey(value)) + return; + + var entry = (token == CreateEntryToken) + ? new Entry(node) + : token as Entry; + if (entry == null) + return; + + AddValue(entry, type, value, null); + } + + public bool OnAssigningNull(IXmlNode node, object oldValue) + { + object token, newValue = null; + return OnAssigningValue(node, oldValue, ref newValue, out token); + } + + public bool OnAssigningValue(IXmlNode node, object oldValue, ref object newValue, out object token) + { + if (newValue == oldValue && newValue != null) + { token = null; return false; } + + var oldEntry = OnReplacingValue(node, oldValue); + + if (newValue == null) + return ShouldAssignmentProceed(oldEntry, null, token = null); + + var type = newValue.GetComponentType(); + if (ShouldExclude(type)) + return ShouldAssignmentProceed(oldEntry, null, token = null); + + var xmlAdapter = XmlAdapter.For(newValue, false); + + Entry newEntry; + if (entriesByValue.TryGetValue(xmlAdapter ?? newValue, out newEntry)) + { + // Value already present in graph; add reference + TryGetCompatibleValue(newEntry, type, ref newValue); + AddReference(node, newEntry); + token = null; + } + else + { + // Value not present in graph; add as primary + newEntry = oldEntry ?? new Entry(node); + AddValue(newEntry, type, newValue, xmlAdapter); + format.ClearIdentity (node); + format.ClearReference(node); + token = newEntry; + } + return ShouldAssignmentProceed(oldEntry, newEntry, token); + } + + private bool ShouldAssignmentProceed(Entry oldEntry, Entry newEntry, object token) + { + if (oldEntry != null && oldEntry != newEntry && oldEntry.Id > 0) + entriesById.Remove(oldEntry.Id); // Didn't reuse old entry; delete it + + return token != null // Expecting callback with a token, so proceed with set + || newEntry == null; // No reference tracking for this value; don't prevent assignment + } + + private Entry OnReplacingValue(IXmlNode node, object oldValue) + { + Entry entry; + bool isReference; + + if (oldValue == null) + { + if (!TryGetEntry(node, out entry, out isReference)) + return null; + } + else + { + if (!entriesByValue.TryGetValue(oldValue, out entry)) + return null; + isReference = !entry.Node.PositionEquals(node); + } + + if (isReference) + { + // Replacing reference + entry.RemoveReference(node); + ClearReference(entry, node); + return null; + } + else if (entry.References != null) + { + // Replacing primary that has references + // Relocate content to a referencing node (making it a new primary) + node = entry.RemoveReference(0); + ClearReference(entry, node); + entry.Node.CopyTo(node); + entry.Node.Clear(); + entry.Node = node; + return null; + } + else + { + // Replacing primary with no references; reuse entry + PrepareForReuse(entry); + return entry; + } + } + + public void OnAssignedValue(IXmlNode node, object givenValue, object storedValue, object token) + { + var entry = token as Entry; + if (entry == null) + return; + + if (ReferenceEquals(givenValue, storedValue)) + return; + + SetNotInGraph(entry, givenValue); + + if (entriesByValue.ContainsKey(storedValue)) + return; + + AddValue(entry, node.ClrType, storedValue, null); + } + + private void AddReference(IXmlNode node, Entry entry) + { + if (!entry.Node.PositionEquals(node)) + { + if (entry.References == null) + { + GenerateId(entry); + format.SetIdentity(entry.Node, entry.Id); + } + node.Clear(); + entry.AddReference(node); + format.SetReference(node, entry.Id); + } + } + + private void GenerateId(Entry entry) + { + if (entry.Id == 0) + { + entry.Id = nextId++; + entriesById.Add(entry.Id, entry); + } + } + + private void AddValue(Entry entry, Type type, object value, XmlAdapter xmlAdapter) + { + if (xmlAdapter == null) + xmlAdapter = XmlAdapter.For(value, false); + + AddValueCore(entry, type, value, true); + + if (xmlAdapter != null) + AddValueCore(entry, typeof(XmlAdapter), xmlAdapter, true); + } + + private void AddValueCore(Entry entry, Type type, object value, bool isInGraph) + { + entry.AddValue(type, value, isInGraph); + entriesByValue.Add(value, entry); + } + + private void ClearReference(Entry entry, IXmlNode node) + { + format.ClearReference(node); + + if (entry.References == null) + format.ClearIdentity(entry.Node); + } + + private void PrepareForReuse(Entry entry) + { + foreach (var item in entry.Values) + { + var value = item.Value.Target; + if (null != value) + entriesByValue.Remove(value); + } + entry.Values.Clear(); + + format.ClearIdentity(entry.Node); + } + + private bool TryGetEntry(IXmlNode node, out Entry entry, out bool reference) + { + int id; + + if (format.TryGetIdentity(node, out id)) + reference = false; + else if (format.TryGetReference(node, out id)) + reference = true; + else + { + reference = false; + entry = null; + return false; + } + + if (!entriesById.TryGetValue(id, out entry)) + throw IdNotFoundError(id); + return true; + } + + private bool TryGetCompatibleValue(Entry entry, Type type, ref object value) + { + var values = entry.Values; + if (values == null) + return false; + + var dictionaryAdapter = null as IDictionaryAdapter; + + // Try to find in the graph a directly assignable value + foreach (var item in values) + { + if (!item.IsInGraph) + continue; + + var candidate = item.Value.Target; + if (candidate == null) + continue; + + if (type.IsAssignableFrom(item.Type)) + if (null != candidate) + return Try.Success(out value, candidate); + + if (dictionaryAdapter == null) + dictionaryAdapter = candidate as IDictionaryAdapter; + } + + // Fall back to coercing a DA found in the graph + if (dictionaryAdapter != null) + { + value = dictionaryAdapter.Coerce(type); + entry.AddValue(type, value, true); + return true; + } + + return false; + } + + private static void SetNotInGraph(Entry entry, object value) + { + var xmlAdapter = XmlAdapter.For(value, false); + + SetNotInGraphCore(entry, value); + + if (xmlAdapter != null) + SetNotInGraphCore(entry, xmlAdapter); + } + + private static bool ShouldExclude(Type type) + { + return type.IsValueType + || type == StringType; + } + + private static void SetNotInGraphCore(Entry entry, object value) + { + var values = entry.Values; + for (int index = 0; index < values.Count; index++) + { + var item = values[index]; + var candidate = item.Value.Target; + + if (ReferenceEquals(candidate, value)) + { + item = new EntryValue(item.Type, item.Value, false); + values[index] = item; + return; + } + } + } + + private static IXmlNode RedirectNode(ref IXmlNode node, Entry entry) + { + var cursor = entry.Node.SelectSelf(node.ClrType); + cursor.MoveNext(); + return node = cursor; + } + + public void UnionWith(XmlReferenceManager other) + { + var visited = null as HashSet; + + foreach (var otherEntry in other.entriesByValue) + { + Entry thisEntry; + if (entriesByValue.TryGetValue(otherEntry.Key, out thisEntry)) + { + if (visited == null) + visited = new HashSet(ReferenceEqualityComparer.Instance); + else if (visited.Contains(thisEntry)) + continue; + visited.Add(thisEntry); + + foreach (var otherValue in otherEntry.Value.Values) + { + var otherTarget = otherValue.Value.Target; + if (otherTarget == null || + otherTarget == otherEntry.Key || + entriesByValue.ContainsKey(otherTarget)) + { continue; } + AddValueCore(thisEntry, otherValue.Type, otherTarget, false); + } + } + } + } + + private static readonly Type + StringType = typeof(string); + + private static readonly object + CreateEntryToken = new object(); + + private class Entry + { + public int Id; + public IXmlNode Node; + private List references; + private List values; + + public Entry(IXmlNode node) + { + Node = node.Save(); + } + + public Entry(int id, IXmlNode node) : this(node) + { + Id = id; + } + + public void AddReference(IXmlNode node) + { + if (references == null) + references = new List(); + references.Add(node); + } + + public IXmlNode RemoveReference(IXmlNode node) + { + for (var index = 0; index < references.Count; index++) + if (references[index].PositionEquals(node)) + return RemoveReference(index); + return node; + } + + public IXmlNode RemoveReference(int index) + { + var node = references[index]; + references.RemoveAt(index); + if (references.Count == 0) + references = null; + return node; + } + + public void AddValue(Type type, object value, bool isInGraph) + { + if (values == null) + values = new List(); + values.Add(new EntryValue(type, value, isInGraph)); + } + + public List References + { + get { return references; } + } + + public List Values + { + get { return values; } + } + } + + private struct Reference + { + public readonly int Id; + public readonly IXmlNode Node; + + public Reference(int id, IXmlNode node) + { + Id = id; + Node = node; + } + } + + private struct EntryValue + { + public readonly Type Type; + public readonly WeakReference Value; + public readonly bool IsInGraph; + + public EntryValue(Type type, object value, bool isInGraph) + : this(type, new WeakReference(value), isInGraph) { } + + public EntryValue(Type type, WeakReference value, bool isInGraph) + { + Type = type; + Value = value; + IsInGraph = isInGraph; + } + } + + private static Exception IdNotFoundError(int id) + { + var message = string.Format + ( + "The given ID ({0}) was not present in the underlying data.", + id + ); + return new KeyNotFoundException(message); + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/IXmlAccessor.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/IXmlAccessor.cs new file mode 100644 index 0000000..37683f0 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/IXmlAccessor.cs @@ -0,0 +1,32 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + + public interface IXmlAccessor + { + Type ClrType { get; } + XmlTypeSerializer Serializer { get; } + IXmlContext Context { get; } + bool IsNillable { get; } + bool IsReference { get; } + + object GetValue(IXmlNode node, IDictionaryAdapter parentObject, XmlReferenceManager references, bool nodeExists, bool orStub); + void SetValue(IXmlCursor cursor, IDictionaryAdapter parentObject, XmlReferenceManager references, bool hasCurrent, object oldValue, ref object newValue); + + IXmlCollectionAccessor GetCollectionAccessor(Type itemType); + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/IXmlBehaviorSemantics.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/IXmlBehaviorSemantics.cs new file mode 100644 index 0000000..6e51cb5 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/IXmlBehaviorSemantics.cs @@ -0,0 +1,25 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + + public interface IXmlBehaviorSemantics + { + string GetLocalName (T behavior); + string GetNamespaceUri(T behavior); + Type GetClrType (T behavior); + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/IXmlCollectionAccessor.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/IXmlCollectionAccessor.cs new file mode 100644 index 0000000..736a2d0 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/IXmlCollectionAccessor.cs @@ -0,0 +1,25 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + using System.Collections; + + public interface IXmlCollectionAccessor : IXmlAccessor + { + IXmlCursor SelectCollectionItems(IXmlNode parentNode, bool mutable); + void GetCollectionItems (IXmlNode parentNode, IDictionaryAdapter parentObject, XmlReferenceManager references, IList values); + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/IXmlPropertyAccessor.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/IXmlPropertyAccessor.cs new file mode 100644 index 0000000..4582fe9 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/IXmlPropertyAccessor.cs @@ -0,0 +1,24 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + + public interface IXmlPropertyAccessor : IXmlAccessor + { + object GetPropertyValue(IXmlNode parentNode, IDictionaryAdapter parentObject, XmlReferenceManager references, bool orStub); + void SetPropertyValue(IXmlNode parentNode, IDictionaryAdapter parentObject, XmlReferenceManager references, object oldValue, ref object newValue); + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XPathBehaviorAccessor.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XPathBehaviorAccessor.cs new file mode 100644 index 0000000..72910aa --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XPathBehaviorAccessor.cs @@ -0,0 +1,220 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + using System.Xml.XPath; + + public class XPathBehaviorAccessor : XmlAccessor, IXmlIncludedType, IXmlIncludedTypeMap, + IConfigurable, + IConfigurable, + IConfigurable + { + private CompiledXPath path; + private XmlIncludedTypeSet includedTypes; + private XmlAccessor defaultAccessor; + private XmlAccessor itemAccessor; + + internal static readonly XmlAccessorFactory + Factory = (name, type, context) => new XPathBehaviorAccessor(type, context); + + protected XPathBehaviorAccessor(Type type, IXmlContext context) + : base(type, context) + { + includedTypes = new XmlIncludedTypeSet(); + + foreach (var includedType in context.GetIncludedTypes(ClrType)) + includedTypes.Add(includedType); + } + + XmlName IXmlIncludedType.XsiType + { + get { return XmlName.Empty; } + } + + IXmlIncludedType IXmlIncludedTypeMap.Default + { + get { return this; } + } + + private bool SelectsNodes + { + get { return path.Path.ReturnType == XPathResultType.NodeSet; } + } + + private bool CreatesAttributes + { + get { var step = path.LastStep; return step != null && step.IsAttribute; } + } + + public void Configure(XPathAttribute attribute) + { + if (path != null) + throw Error.AttributeConflict(path.Path.Expression); + + path = attribute.SetPath; + + if (path == attribute.GetPath) + return; + else if (Serializer.CanGetStub) + throw Error.SeparateGetterSetterOnComplexType(path.Path.Expression); + + defaultAccessor = new DefaultAccessor(this, attribute.GetPath); + } + + public void Configure(XPathVariableAttribute attribute) + { + CloneContext().AddVariable(attribute); + } + + public void Configure(XPathFunctionAttribute attribute) + { + CloneContext().AddFunction(attribute); + } + + public override void Prepare() + { + if (CreatesAttributes) + state &= ~States.Nillable; + + Context.Enlist(path); + + if (defaultAccessor != null) + defaultAccessor.Prepare(); + } + + public override bool IsPropertyDefined(IXmlNode parentNode) + { + return SelectsNodes + && base.IsPropertyDefined(parentNode); + } + + public override object GetPropertyValue(IXmlNode parentNode, IDictionaryAdapter parentObject, XmlReferenceManager references, bool orStub) + { + return GetPropertyValueCore (parentNode, parentObject, references, orStub) + ?? GetDefaultPropertyValue(parentNode, parentObject, references, orStub); + } + + private object GetPropertyValueCore(IXmlNode parentNode, IDictionaryAdapter parentObject, XmlReferenceManager references, bool orStub) + { + return SelectsNodes + ? base.GetPropertyValue(parentNode, parentObject, references, orStub) + : Evaluate(parentNode); + } + + private object GetDefaultPropertyValue(IXmlNode parentNode, IDictionaryAdapter parentObject, XmlReferenceManager references, bool orStub) + { + return defaultAccessor != null + ? defaultAccessor.GetPropertyValue(parentNode, parentObject, references, orStub) + : null; + } + + private object Evaluate(IXmlNode node) + { + var value = node.Evaluate(path); + return value != null + ? Convert.ChangeType(value, ClrType) + : null; + } + + public override void SetPropertyValue(IXmlNode parentNode, IDictionaryAdapter parentObject, XmlReferenceManager references, object oldValue, ref object value) + { + if (SelectsNodes) + base.SetPropertyValue(parentNode, parentObject, references, oldValue, ref value); + else + throw Error.XPathNotCreatable(path); + } + + public override IXmlCollectionAccessor GetCollectionAccessor(Type itemType) + { + return itemAccessor ?? (itemAccessor = new ItemAccessor(this)); + } + + public override IXmlCursor SelectPropertyNode(IXmlNode node, bool create) + { + var flags = CursorFlags.AllNodes.MutableIf(create); + return node.Select(path, this, Context, flags); + } + + public override IXmlCursor SelectCollectionNode(IXmlNode node, bool create) + { + return node.SelectSelf(ClrType); + } + + public override IXmlCursor SelectCollectionItems(IXmlNode node, bool create) + { + var flags = CursorFlags.AllNodes.MutableIf(create) | CursorFlags.Multiple; + return node.Select(path, this, Context, flags); + } + + public bool TryGet(XmlName xsiType, out IXmlIncludedType includedType) + { + if (xsiType == XmlName.Empty || xsiType == this.XsiType) + return Try.Success(out includedType, this); + + if (!includedTypes.TryGet(xsiType, out includedType)) + return false; + + if (!ClrType.IsAssignableFrom(includedType.ClrType)) + return Try.Failure(out includedType); + + return true; + } + + public bool TryGet(Type clrType, out IXmlIncludedType includedType) + { + return clrType == this.ClrType + ? Try.Success(out includedType, this) + : includedTypes.TryGet(clrType, out includedType); + } + + private class DefaultAccessor : XPathBehaviorAccessor + { + private readonly XPathBehaviorAccessor parent; + + public DefaultAccessor(XPathBehaviorAccessor parent, CompiledXPath path) + : base(parent.ClrType, parent.Context) + { + this.parent = parent; + this.path = path; + } + + public override void Prepare() + { + this.includedTypes = parent.includedTypes; + this.Context = parent.Context; + + base.Prepare(); + } + } + + private class ItemAccessor : XPathBehaviorAccessor + { + public ItemAccessor(XPathBehaviorAccessor parent) + : base(parent.ClrType.GetCollectionItemType(), parent.Context) + { + includedTypes = parent.includedTypes; + path = parent.path; + + ConfigureNillable(true); + } + + public override IXmlCollectionAccessor GetCollectionAccessor(Type itemType) + { + return GetDefaultCollectionAccessor(itemType); + } + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlAccessor.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlAccessor.cs new file mode 100644 index 0000000..3057b3c --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlAccessor.cs @@ -0,0 +1,345 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + using System.Collections; + + public abstract class XmlAccessor : IXmlPropertyAccessor, IXmlCollectionAccessor + { + private readonly Type clrType; + private readonly XmlName xsiType; + private readonly XmlTypeSerializer serializer; + private IXmlContext context; + protected States state; + + protected XmlAccessor(Type clrType, IXmlContext context) + { + if (clrType == null) + throw Error.ArgumentNull(nameof(clrType)); + if (context == null) + throw Error.ArgumentNull(nameof(context)); + + clrType = clrType.NonNullable(); + this.clrType = clrType; + this.xsiType = context.GetDefaultXsiType(clrType); + this.serializer = XmlTypeSerializer.For(clrType); + this.context = context; + } + + public Type ClrType + { + get { return clrType; } + } + + public XmlName XsiType + { + get { return xsiType; } + } + + public XmlTypeSerializer Serializer + { + get { return serializer; } + } + + public IXmlContext Context + { + get { return context; } + protected set { SetContext(value); } + } + + public bool IsCollection + { + get { return serializer.Kind == XmlTypeKind.Collection; } + } + + public virtual bool IsIgnored + { + get { return false; } + } + + public bool IsNillable + { + get { return 0 != (state & States.Nillable); } + } + + public bool IsVolatile + { + get { return 0 != (state & States.Volatile); } + } + + public bool IsReference + { + get { return 0 != (state & States.Reference); } + } + + public virtual void ConfigureNillable(bool nillable) + { + if (nillable) + state |= States.Nillable; + } + + public void ConfigureVolatile(bool isVolatile) + { + if (isVolatile) + state |= States.Volatile; + } + + public virtual void ConfigureReference(bool isReference) + { + if (isReference) + state |= States.Reference; + } + + public virtual void Prepare() + { + // Do nothing + } + + protected IXmlContext CloneContext() + { + if (0 == (state & States.ConfiguredContext)) + { + context = context.Clone(); + state |= States.ConfiguredContext; + } + return context; + } + + private void SetContext(IXmlContext value) + { + if (null == value) + throw Error.ArgumentNull(nameof(value)); + + context = value; + } + + public virtual bool IsPropertyDefined(IXmlNode parentNode) + { + var cursor = IsCollection + ? SelectCollectionNode(parentNode, false) + : SelectPropertyNode (parentNode, false); + + return cursor.MoveNext(); + } + + public virtual object GetPropertyValue(IXmlNode parentNode, IDictionaryAdapter parentObject, XmlReferenceManager references, bool orStub) + { + if (orStub) orStub &= serializer.CanGetStub; + + var cursor = IsCollection + ? SelectCollectionNode(parentNode, orStub) + : SelectPropertyNode (parentNode, orStub); + + return GetValue(cursor, parentObject, references, cursor.MoveNext(), orStub); + } + + public object GetValue(IXmlNode node, IDictionaryAdapter parentObject, XmlReferenceManager references, bool nodeExists, bool orStub) + { + object value; + + if ((nodeExists || orStub) && IsReference) + { + value = null; + object token; + + if (references.OnGetStarting(ref node, ref value, out token)) + { + value = GetValueCore(node, parentObject, nodeExists, orStub); + references.OnGetCompleted(node, value, token); + } + } + else + { + value = GetValueCore(node, parentObject, nodeExists, orStub); + } + return value; + } + + private object GetValueCore(IXmlNode node, IDictionaryAdapter parentObject, bool nodeExists, bool orStub) + { + if (nodeExists) + if (!node.IsNil) + return serializer.GetValue(node, parentObject, this); + else if (IsNillable) + return null; + + return orStub + ? serializer.GetStub(node, parentObject, this) + : null; + } + + public virtual void SetPropertyValue(IXmlNode parentNode, IDictionaryAdapter parentObject, XmlReferenceManager references, + object oldValue, ref object value) + { + var cursor = IsCollection + ? SelectCollectionNode(parentNode, true) + : SelectPropertyNode (parentNode, true); + + SetValue(cursor, parentObject, references, cursor.MoveNext(), oldValue, ref value); + } + + public virtual void SetValue(IXmlCursor cursor, IDictionaryAdapter parentObject, XmlReferenceManager references, + bool hasCurrent, object oldValue, ref object newValue) + { + var hasValue = null != newValue; + var isNillable = this.IsNillable; + var isReference = this.IsReference; + + var clrType = hasValue + ? newValue.GetComponentType() + : this.clrType; + + if (hasValue || isNillable) + { + if (hasCurrent) + Coerce(cursor, clrType, !hasValue && cursor.IsAttribute); // TODO: Refactor. (NB: && isNillable is implied) + else + cursor.Create(clrType); + } + else if (!hasCurrent) + { + // No node exists + no value to assign + and not nillable = no work to do + return; + } + + object token = null; + if (isReference) + if (!references.OnAssigningValue(cursor, oldValue, ref newValue, out token)) + return; + + var givenValue = newValue; + + if (hasValue) + serializer.SetValue(cursor, parentObject, this, oldValue, ref newValue); + else if (isNillable) + cursor.IsNil = true; + else + { cursor.Remove(); cursor.RemoveAllNext(); } + + if (isReference) + references.OnAssignedValue(cursor, givenValue, newValue, token); + } + + private void Coerce(IXmlCursor cursor, Type clrType, bool replace) + { + if (replace) + { + cursor.Remove(); + cursor.MoveNext(); + cursor.Create(ClrType); + } + else cursor.Coerce(clrType); + } + + public void GetCollectionItems(IXmlNode parentNode, IDictionaryAdapter parentObject, XmlReferenceManager references, IList values) + { + var cursor = SelectCollectionItems(parentNode, false); + + while (cursor.MoveNext()) + { + object value; + + if (IsReference) + { + IXmlNode node = cursor; + value = null; + object token; + + if (references.OnGetStarting(ref node, ref value, out token)) + { + value = serializer.GetValue(node, parentObject, this); + references.OnGetCompleted(node, value, token); + } + } + else + { + value = serializer.GetValue(cursor, parentObject, this); + } + values.Add(value); + } + } + + protected void RemoveCollectionItems(IXmlNode parentNode, XmlReferenceManager references, object value) + { + var collection = value as ICollectionProjection; + if (collection != null) + { + collection.Clear(); + return; + } + + var itemType = clrType.GetCollectionItemType(); + var accessor = GetCollectionAccessor(itemType); + var cursor = accessor.SelectCollectionItems(parentNode, true); + var isReference = IsReference; + + var items = value as IEnumerable; + if (items != null) + { + foreach (var item in items) + { + if (!cursor.MoveNext()) + break; + if (isReference) + references.OnAssigningNull(cursor, item); + } + } + + cursor.Reset(); + cursor.RemoveAllNext(); + } + + public virtual IXmlCollectionAccessor GetCollectionAccessor(Type itemType) + { + return GetDefaultCollectionAccessor(itemType); + } + + protected IXmlCollectionAccessor GetDefaultCollectionAccessor(Type itemType) + { + var accessor = new XmlDefaultBehaviorAccessor(itemType, Context); + accessor.ConfigureNillable (true); + accessor.ConfigureReference(IsReference); + return accessor; + } + + public virtual IXmlCursor SelectPropertyNode(IXmlNode parentNode, bool mutable) + { + throw Error.NotSupported(); + } + + public virtual IXmlCursor SelectCollectionNode(IXmlNode parentNode, bool mutable) + { + return SelectPropertyNode(parentNode, mutable); + } + + public virtual IXmlCursor SelectCollectionItems(IXmlNode parentNode, bool mutable) + { + throw Error.NotSupported(); + } + + [Flags] + protected enum States + { + Nillable = 0x01, // Set a null value as xsi:nil='true' + Volatile = 0x02, // Always get value from XML store; don't cache it + Reference = 0x04, // Participate in reference tracking + ConfiguredContext = 0x08, // Have created our own IXmlContext instance + ConfiguredLocalName = 0x10, // The local name has been configured + ConfiguredNamespaceUri = 0x20, // The namespace URI has been configured + ConfiguredKnownTypes = 0x40, // Known types have been configured from attributes + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlAccessorFactory.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlAccessorFactory.cs new file mode 100644 index 0000000..daade16 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlAccessorFactory.cs @@ -0,0 +1,22 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + + public delegate TAccessor + XmlAccessorFactory(string name, Type type, IXmlContext context) + where TAccessor : XmlAccessor; +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlArrayBehaviorAccessor.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlArrayBehaviorAccessor.cs new file mode 100644 index 0000000..c0a28aa --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlArrayBehaviorAccessor.cs @@ -0,0 +1,131 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + using System.Collections.Generic; + using System.Xml.Serialization; + + public class XmlArrayBehaviorAccessor : XmlNodeAccessor, + IConfigurable, + IConfigurable + { + private readonly ItemAccessor itemAccessor; + + internal static readonly XmlAccessorFactory + Factory = (name, type, context) => new XmlArrayBehaviorAccessor(name, type, context); + + public XmlArrayBehaviorAccessor(string name, Type type, IXmlContext context) + : base(name, type, context) + { + if (Serializer.Kind != XmlTypeKind.Collection) + throw Error.AttributeConflict(name); + + itemAccessor = new ItemAccessor(ClrType.GetCollectionItemType(), this); + } + + public void Configure(XmlArrayAttribute attribute) + { + ConfigureLocalName (attribute.ElementName); + ConfigureNamespaceUri(attribute.Namespace ); + ConfigureNillable (attribute.IsNullable ); + } + + public void Configure(XmlArrayItemAttribute attribute) + { + itemAccessor.Configure(attribute); + } + + public override void Prepare() + { + base.Prepare(); + itemAccessor.Prepare(); + } + + public override IXmlCollectionAccessor GetCollectionAccessor(Type itemType) + { + return itemAccessor; + } + + public override IXmlCursor SelectPropertyNode(IXmlNode node, bool mutable) + { + return node.SelectChildren(this, Context, PropertyFlags.MutableIf(mutable)); + } + + private class ItemAccessor : XmlNodeAccessor, + IConfigurable, + IXmlBehaviorSemantics + { + private List attributes; + + public ItemAccessor(Type itemClrType, XmlNodeAccessor accessor) + : base(itemClrType, accessor.Context) + { + ConfigureNillable(true); + ConfigureReference(accessor.IsReference); + } + + public void Configure(XmlArrayItemAttribute attribute) + { + if (attribute.Type == null) + { + ConfigureLocalName (attribute.ElementName); + ConfigureNamespaceUri(attribute.Namespace ); + ConfigureNillable (attribute.IsNullable ); + } + else + { + if (attributes == null) + attributes = new List(); + attributes.Add(attribute); + } + } + + public override void Prepare() + { + if (attributes != null) + { + ConfigureKnownTypesFromAttributes(attributes, this); + attributes = null; + } + base.Prepare(); + } + + public override IXmlCursor SelectCollectionItems(IXmlNode node, bool mutable) + { + return node.SelectChildren(KnownTypes, Context, CollectionItemFlags.MutableIf(mutable)); + } + + public string GetLocalName(XmlArrayItemAttribute attribute) + { + return attribute.ElementName; + } + + public string GetNamespaceUri(XmlArrayItemAttribute attribute) + { + return attribute.Namespace; + } + + public Type GetClrType(XmlArrayItemAttribute attribute) + { + return attribute.Type; + } + } + + private const CursorFlags + PropertyFlags = CursorFlags.Elements, + CollectionItemFlags = CursorFlags.Elements | CursorFlags.Multiple; + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlAttributeBehaviorAccessor.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlAttributeBehaviorAccessor.cs new file mode 100644 index 0000000..311145e --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlAttributeBehaviorAccessor.cs @@ -0,0 +1,64 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + using System.Xml.Serialization; + + public class XmlAttributeBehaviorAccessor : XmlNodeAccessor, + IConfigurable + { + internal static readonly XmlAccessorFactory + Factory = (name, type, context) => new XmlAttributeBehaviorAccessor(name, type, context); + + public XmlAttributeBehaviorAccessor(string name, Type type, IXmlContext context) + : base(name, type, context) + { + if (Serializer.Kind != XmlTypeKind.Simple) + throw Error.NotSupported(); + } + + public void Configure(XmlAttributeAttribute attribute) + { + ConfigureLocalName (attribute.AttributeName); + ConfigureNamespaceUri(attribute.Namespace); + } + + public override void ConfigureNillable(bool nillable) + { + // Attributes are never nillable + } + + public override void ConfigureReference(bool isReference) + { + // Attributes cannot store references + } + + public override IXmlCollectionAccessor GetCollectionAccessor(Type itemType) + { + throw Error.NotSupported(); + } + + public override IXmlCursor SelectPropertyNode(IXmlNode node, bool mutable) + { + return node.SelectChildren(this, Context, CursorFlags.Attributes.MutableIf(mutable)); + } + + public override IXmlCursor SelectCollectionNode(IXmlNode node, bool mutable) + { + throw Error.NotSupported(); + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlDefaultBehaviorAccessor.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlDefaultBehaviorAccessor.cs new file mode 100644 index 0000000..ecd7474 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlDefaultBehaviorAccessor.cs @@ -0,0 +1,50 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + using System.Xml; + + public class XmlDefaultBehaviorAccessor : XmlNodeAccessor + { + internal static readonly XmlAccessorFactory + Factory = (name, type, context) => new XmlDefaultBehaviorAccessor(name, type, context); + + public XmlDefaultBehaviorAccessor(Type type, IXmlContext context) + : base(type, context) { } + + public XmlDefaultBehaviorAccessor(string name, Type type, IXmlContext context) + : base(name, type, context) { } + + public override IXmlCursor SelectPropertyNode(IXmlNode node, bool mutable) + { + var flags = Serializer.Kind == XmlTypeKind.Simple + ? CursorFlags.AllNodes + : CursorFlags.Elements; + return node.SelectChildren(KnownTypes, Context, flags.MutableIf(mutable)); + } + + public override IXmlCursor SelectCollectionNode(IXmlNode node, bool mutable) + { + return SelectPropertyNode(node, mutable); + } + + public override IXmlCursor SelectCollectionItems(IXmlNode node, bool mutable) + { + var flags = CursorFlags.Elements | CursorFlags.Multiple; + return node.SelectChildren(KnownTypes, Context, flags.MutableIf(mutable)); + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlElementBehaviorAccessor.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlElementBehaviorAccessor.cs new file mode 100644 index 0000000..750b2e4 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlElementBehaviorAccessor.cs @@ -0,0 +1,122 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + using System.Collections.Generic; + using System.Xml.Serialization; + + public class XmlElementBehaviorAccessor : XmlNodeAccessor, + IConfigurable, + IXmlBehaviorSemantics + { + private ItemAccessor itemAccessor; + private List attributes; + + internal static readonly XmlAccessorFactory + Factory = (name, type, context) => new XmlElementBehaviorAccessor(name, type, context); + + public XmlElementBehaviorAccessor(string name, Type type, IXmlContext context) + : base(name, type, context) { } + + public void Configure(XmlElementAttribute attribute) + { + if (attribute.Type == null) + { + ConfigureLocalName (attribute.ElementName); + ConfigureNamespaceUri(attribute.Namespace ); + ConfigureNillable (attribute.IsNullable ); + } + else + { + if (attributes == null) + attributes = new List(); + attributes.Add(attribute); + } + } + + public override void Prepare() + { + if (attributes != null) + { + ConfigureKnownTypesFromAttributes(attributes, this); + attributes = null; + } + base.Prepare(); + } + + public override void SetValue(IXmlCursor cursor, IDictionaryAdapter parentObject, XmlReferenceManager references, + bool hasCurrent, object oldValue, ref object newValue) + { + if (newValue == null && IsCollection) + base.RemoveCollectionItems(cursor, references, oldValue); + else + base.SetValue(cursor, parentObject, references, hasCurrent, oldValue, ref newValue); + } + + public override IXmlCollectionAccessor GetCollectionAccessor(Type itemType) + { + return itemAccessor ?? (itemAccessor = new ItemAccessor(this)); + } + + public override IXmlCursor SelectPropertyNode(IXmlNode node, bool mutable) + { + return node.SelectChildren(KnownTypes, Context, CursorFlags.Elements.MutableIf(mutable)); + } + + public override IXmlCursor SelectCollectionNode(IXmlNode node, bool mutable) + { + return node.SelectSelf(ClrType); + } + + public string GetLocalName(XmlElementAttribute attribute) + { + return attribute.ElementName; + } + + public string GetNamespaceUri(XmlElementAttribute attribute) + { + return attribute.Namespace; + } + + public Type GetClrType(XmlElementAttribute attribute) + { + return attribute.Type; + } + + private class ItemAccessor : XmlNodeAccessor + { + public ItemAccessor(XmlNodeAccessor parent) + : base(parent.ClrType.GetCollectionItemType(), parent.Context) + { + ConfigureLocalName (parent.Name.LocalName ); + ConfigureNamespaceUri(parent.Name.NamespaceUri); + ConfigureNillable (parent.IsNillable ); + ConfigureReference (parent.IsReference ); + ConfigureKnownTypesFromParent(parent); + } + + public override void Prepare() + { + // Don't prepare; parent already did it + } + + public override IXmlCursor SelectCollectionItems(IXmlNode node, bool mutable) + { + return node.SelectChildren(KnownTypes, Context, CursorFlags.Elements.MutableIf(mutable) | CursorFlags.Multiple); + } + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlIgnoreBehaviorAccessor.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlIgnoreBehaviorAccessor.cs new file mode 100644 index 0000000..29a5468 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlIgnoreBehaviorAccessor.cs @@ -0,0 +1,111 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + using System.Collections.Generic; + using System.Linq; + + public class XmlIgnoreBehaviorAccessor : XmlAccessor + { + public static readonly XmlIgnoreBehaviorAccessor + Instance = new XmlIgnoreBehaviorAccessor(); + + private XmlIgnoreBehaviorAccessor() + : base(typeof(object), DummyContext.Instance) { } + + public override bool IsIgnored + { + get { return true; } + } + + public override IXmlCollectionAccessor GetCollectionAccessor(Type itemType) + { + throw Error.NotSupported(); + } + + public override IXmlCursor SelectPropertyNode(IXmlNode node, bool mutable) + { + throw Error.NotSupported(); + } + + public override IXmlCursor SelectCollectionNode(IXmlNode node, bool mutable) + { + throw Error.NotSupported(); + } + + public override IXmlCursor SelectCollectionItems(IXmlNode node, bool mutable) + { + throw Error.NotSupported(); + } + + private sealed class DummyContext : IXmlContext + { + public static DummyContext Instance = new DummyContext(); + + private DummyContext() { } + + public string ChildNamespaceUri + { + get { return null; } + } + + public IXmlContext Clone() + { + return this; + } + + public bool IsReservedNamespaceUri(string namespaceUri) + { + return false; + } + + public XmlName GetDefaultXsiType(Type clrType) + { + return new XmlName("anyType", Xsd.NamespaceUri); + } + + public IEnumerable GetIncludedTypes(Type baseType) + { + throw Error.NotSupported(); + } + + public void Enlist(CompiledXPath path) + { + throw Error.NotSupported(); + } + + public string GetElementPrefix(IXmlNode node, string namespaceUri) + { + throw Error.NotSupported(); + } + + public string GetAttributePrefix(IXmlNode node, string namespaceUri) + { + throw Error.NotSupported(); + } + + public void AddVariable(XPathVariableAttribute attribute) + { + throw Error.NotSupported(); + } + + public void AddFunction(XPathFunctionAttribute attribute) + { + throw Error.NotSupported(); + } + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlNodeAccessor.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlNodeAccessor.cs new file mode 100644 index 0000000..98515cd --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlNodeAccessor.cs @@ -0,0 +1,223 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.Xml; + + public abstract class XmlNodeAccessor : XmlAccessor, IXmlKnownType, IXmlKnownTypeMap + { + private string localName; + private string namespaceUri; + private XmlKnownTypeSet knownTypes; + + protected XmlNodeAccessor(Type type, IXmlContext context) + : this(context.GetDefaultXsiType(type).LocalName, type, context) { } + + protected XmlNodeAccessor(string name, Type type, IXmlContext context) + : base(type, context) + { + if (name == null) + throw Error.ArgumentNull(nameof(name)); + if (name == string.Empty) + throw Error.InvalidLocalName(); + + localName = XmlConvert.EncodeLocalName(name); + namespaceUri = context.ChildNamespaceUri; + } + + public XmlName Name + { + get { return new XmlName(localName, namespaceUri); } + } + + XmlName IXmlIdentity.XsiType + { + get { return XmlName.Empty; } + } + + protected IXmlKnownTypeMap KnownTypes + { + get + { + if (knownTypes != null) + return knownTypes; + return this; + } + } + + IXmlKnownType IXmlKnownTypeMap.Default + { + get { return this; } + } + + public bool TryGet(IXmlIdentity xmlName, out IXmlKnownType knownType) + { + return IsMatch(xmlName) + ? Try.Success(out knownType, this) + : Try.Failure(out knownType); + } + + public bool TryGet(Type clrType, out IXmlKnownType knownType) + { + return IsMatch(clrType) + ? Try.Success(out knownType, this) + : Try.Failure(out knownType); + } + + protected virtual bool IsMatch(IXmlIdentity xmlIdentity) + { + return NameComparer.Equals(localName, xmlIdentity.Name.LocalName) + && IsMatchOnNamespaceUri(xmlIdentity) + && IsMatchOnXsiType (xmlIdentity); + } + + private bool IsMatchOnNamespaceUri(IXmlIdentity xmlIdentity) + { + var otherNamespaceUri = xmlIdentity.Name.NamespaceUri; + if (Context.IsReservedNamespaceUri(otherNamespaceUri)) + return NameComparer.Equals(namespaceUri, otherNamespaceUri); + return namespaceUri == null + || ShouldIgnoreAttributeNamespaceUri(xmlIdentity) + || NameComparer.Equals(namespaceUri, otherNamespaceUri); + } + + private bool IsMatchOnXsiType(IXmlIdentity xmlIdentity) + { + var otherXsiType = xmlIdentity.XsiType; + return otherXsiType == XmlName.Empty + || otherXsiType == XsiType; + } + + private bool ShouldIgnoreAttributeNamespaceUri(IXmlIdentity xmlName) + { + var xmlNode = xmlName as IXmlNode; + return xmlNode != null + && xmlNode.IsAttribute + && 0 == (state & States.ConfiguredNamespaceUri); + } + + protected virtual bool IsMatch(Type clrType) + { + return clrType == this.ClrType + || ( Serializer.Kind == XmlTypeKind.Collection + && typeof(IEnumerable).IsAssignableFrom(clrType) ); + } + + protected void ConfigureLocalName(string localName) + { + ConfigureField(ref this.localName, localName, States.ConfiguredLocalName); + } + + protected void ConfigureNamespaceUri(string namespaceUri) + { + ConfigureField(ref this.namespaceUri, namespaceUri, States.ConfiguredNamespaceUri); + } + + private void ConfigureField(ref string field, string value, States mask) + { + if (string.IsNullOrEmpty(value)) + return; + if (0 != (state & mask)) + throw Error.AttributeConflict(localName); + field = value; + state |= mask; + } + + protected void ConfigureKnownTypesFromParent(XmlNodeAccessor accessor) + { + if (knownTypes != null) + throw Error.AttributeConflict(localName); + + knownTypes = accessor.knownTypes; + } + + protected void ConfigureKnownTypesFromAttributes(IEnumerable attributes, IXmlBehaviorSemantics semantics) + { + foreach (var attribute in attributes) + { + var clrType = semantics.GetClrType(attribute); + if (clrType != null) + { + var xsiType = Context.GetDefaultXsiType(clrType); + + var name = new XmlName( + semantics.GetLocalName (attribute).NonEmpty() ?? xsiType.LocalName, + semantics.GetNamespaceUri(attribute) ?? namespaceUri); + + AddKnownType(name, xsiType, clrType, true); + } + } + } + + public override void Prepare() + { + if (knownTypes == null) + ConfigureIncludedTypes(this); + else + ConfigureDefaultAndIncludedTypes(); + } + + private void ConfigureDefaultAndIncludedTypes() + { + var configuredKnownTypes = knownTypes.ToArray(); + + knownTypes.AddXsiTypeDefaults(); + + foreach (var knownType in configuredKnownTypes) + ConfigureIncludedTypes(knownType); + } + + private void ConfigureIncludedTypes(IXmlKnownType knownType) + { + var includedTypes = Context.GetIncludedTypes(knownType.ClrType); + + foreach (var include in includedTypes) + AddKnownType(knownType.Name, include.XsiType, include.ClrType, false); + } + + private void AddKnownType(XmlName name, XmlName xsiType, Type clrType, bool overwrite) + { + if (knownTypes == null) + { + knownTypes = new XmlKnownTypeSet(ClrType); + AddSelfAsKnownType(); + } + knownTypes.Add(new XmlKnownType(name, xsiType, clrType), overwrite); + } + + private void AddSelfAsKnownType() + { + var mask + = States.ConfiguredLocalName + | States.ConfiguredNamespaceUri + | States.ConfiguredKnownTypes; + + var selfIsKnownType + = (state & mask) != States.ConfiguredKnownTypes; + + if (selfIsKnownType) + { + knownTypes.Add(new XmlKnownType(Name, XsiType, ClrType), true); + knownTypes.Add(new XmlKnownType(Name, XmlName.Empty, ClrType), true); + } + } + + protected static readonly StringComparer + NameComparer = StringComparer.OrdinalIgnoreCase; + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlSelfAccessor.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlSelfAccessor.cs new file mode 100644 index 0000000..51f2ce8 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlSelfAccessor.cs @@ -0,0 +1,37 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + + public class XmlSelfAccessor : XmlAccessor + { + internal static readonly XmlAccessorFactory + Factory = (name, type, context) => new XmlSelfAccessor(type, context); + + public XmlSelfAccessor(Type clrType, IXmlContext context) + : base(clrType, context) { } + + public override void ConfigureNillable(bool nillable) + { + // This behavior cannot support nillable + } + + public override IXmlCursor SelectPropertyNode(IXmlNode parentNode, bool mutable) + { + return parentNode.SelectSelf(ClrType); + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Collections/XmlCollectionAdapter.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Collections/XmlCollectionAdapter.cs new file mode 100644 index 0000000..0b825e5 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Collections/XmlCollectionAdapter.cs @@ -0,0 +1,258 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + using System.Collections.Generic; + + internal class XmlCollectionAdapter : ICollectionAdapter, IXmlNodeSource + { + private List> items; + private List> snapshot; + private ICollectionAdapterObserver advisor; + + private readonly IXmlCursor cursor; + private readonly IXmlCollectionAccessor accessor; + private readonly IXmlNode parentNode; + private readonly IDictionaryAdapter parentObject; + private readonly XmlReferenceManager references; + + public XmlCollectionAdapter( + IXmlNode parentNode, + IDictionaryAdapter parentObject, + IXmlCollectionAccessor accessor) + { + items = new List>(); + + this.accessor = accessor; + this.cursor = accessor.SelectCollectionItems(parentNode, true); + this.parentNode = parentNode; + this.parentObject = parentObject; + this.references = XmlAdapter.For(parentObject).References; + + while (cursor.MoveNext()) + items.Add(new XmlCollectionItem(cursor.Save())); + } + + public IXmlNode Node + { + get { return parentNode; } + } + + public XmlReferenceManager References + { + get { return references; } + } + + public int Count + { + get { return items.Count; } + } + + public void Initialize(ICollectionAdapterObserver advisor) + { + this.advisor = advisor; + } + + public T this[int index] + { + get + { + var item = items[index]; + + if (!item.HasValue) + items[index] = item = item.WithValue(GetValue(item.Node)); + + return item.Value; + } + set + { + var item = items[index]; + cursor.MoveTo(item.Node); + SetValue(cursor, item.Value, ref value); + + if (advisor.OnReplacing(item.Value, value)) + { + // Commit the replacement + items[index] = item.WithValue(value); + advisor.OnReplaced(item.Value, value, index); + } + else + { + // Rollback the replacement + var oldValue = item.Value; + SetValue(cursor, value, ref oldValue); + items[index] = item.WithValue(oldValue); + } + } + } + + public T AddNew() + { + cursor.MoveToEnd(); + cursor.Create(typeof(T)); + + var node = cursor.Save(); + var value = GetValue(node); + var index = items.Count; + + CommitInsert(index, node, value, true); + return (T) value; + } + + public bool Add(T value) + { + return InsertCore(Count, value, append: true); + } + + public bool Insert(int index, T value) + { + return InsertCore(index, value, append: false); + } + + private bool InsertCore(int index, T value, bool append) + { + if (append) + cursor.MoveToEnd(); + else + cursor.MoveTo(items[index].Node); + + cursor.Create(GetTypeOrDefault(value)); + var node = cursor.Save(); + SetValue(cursor, default(T), ref value); + + return advisor.OnInserting(value) + ? CommitInsert(index, node, value, append) + : RollbackInsert(); + } + + private bool CommitInsert(int index, IXmlNode node, T value, bool append) + { + var item = new XmlCollectionItem(node, value); + + if (append) + items.Add(item); + else + items.Insert(index, item); + + advisor.OnInserted(value, index); + return true; + } + + private bool RollbackInsert() + { + cursor.Remove(); + return false; + } + + public void Remove(int index) + { + var item = items[index]; + OnRemoving(item); + + cursor.MoveTo(item.Node); + cursor.Remove(); + items.RemoveAt(index); + + advisor.OnRemoved(item.Value, index); + } + + public void Clear() + { + foreach (var item in items) + OnRemoving(item); + + cursor.Reset(); + cursor.RemoveAllNext(); + items.Clear(); + + // Don't call OnRemoved. Caller is already going to fire a Reset shortly. + } + + public void ClearReferences() + { + if (accessor.IsReference) + foreach (var item in items) + references.OnAssigningNull(item.Node, item.Value); + } + + private void OnRemoving(XmlCollectionItem item) + { + advisor.OnRemoving(item.Value); + + if (accessor.IsReference) + references.OnAssigningNull(item.Node, item.Value); + } + + private T GetValue(IXmlNode node) + { + return (T) (accessor.GetValue(node, parentObject, references, true, true) ?? default(T)); + } + + private void SetValue(IXmlCursor cursor, object oldValue, ref T value) + { + object obj = value; + accessor.SetValue(cursor, parentObject, references, true, oldValue, ref obj); + value = (T) (obj ?? default(T)); + } + + private static Type GetTypeOrDefault(T value) + { + return (null == value) + ? typeof(T) + : value.GetComponentType(); + } + + public IEqualityComparer Comparer + { + get { return null; } + } + + public bool HasSnapshot + { + get { return snapshot != null; } + } + + public int SnapshotCount + { + get { return snapshot.Count; } + } + + public T GetCurrentItem(int index) + { + return items[index].Value; + } + + public T GetSnapshotItem(int index) + { + return snapshot[index].Value; + } + + public void SaveSnapshot() + { + snapshot = new List>(items); + } + + public void LoadSnapshot() + { + items = snapshot; + } + + public void DropSnapshot() + { + snapshot = null; + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Collections/XmlCollectionItem.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Collections/XmlCollectionItem.cs new file mode 100644 index 0000000..1fd1cbd --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Collections/XmlCollectionItem.cs @@ -0,0 +1,41 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + internal struct XmlCollectionItem + { + public readonly IXmlNode Node; + public readonly T Value; + public readonly bool HasValue; + + public XmlCollectionItem(IXmlNode node) + : this(node, default(T), false) { } + + public XmlCollectionItem(IXmlNode node, T value) + : this(node, value, true) { } + + private XmlCollectionItem(IXmlNode node, T value, bool hasValue) + { + Node = node; + Value = value; + HasValue = hasValue; + } + + public XmlCollectionItem WithValue(T value) + { + return new XmlCollectionItem(Node, value); + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Collections/XmlNodeList.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Collections/XmlNodeList.cs new file mode 100644 index 0000000..a66bbfd --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Collections/XmlNodeList.cs @@ -0,0 +1,41 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + internal class XmlNodeList : ListProjection, IXmlNodeSource + { + public XmlNodeList + ( + IXmlNode parentNode, + IDictionaryAdapter parentObject, + IXmlCollectionAccessor accessor + ) + : base + ( + new XmlCollectionAdapter + ( + parentNode, + parentObject, + accessor + ) + ) + { } + + public IXmlNode Node + { + get { return ((IXmlNodeSource)Adapter).Node; } + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Collections/XmlNodeSet.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Collections/XmlNodeSet.cs new file mode 100644 index 0000000..efc47c8 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Collections/XmlNodeSet.cs @@ -0,0 +1,41 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + internal class XmlNodeSet : SetProjection, IXmlNodeSource + { + public XmlNodeSet + ( + IXmlNode parentNode, + IDictionaryAdapter parentObject, + IXmlCollectionAccessor accessor + ) + : base + ( + new XmlCollectionAdapter + ( + parentNode, + parentObject, + accessor + ) + ) + { } + + public IXmlNode Node + { + get { return ((IXmlNodeSource)Adapter).Node; } + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/CursorFlags.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/CursorFlags.cs new file mode 100644 index 0000000..4e5c314 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/CursorFlags.cs @@ -0,0 +1,57 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + + [Flags] + public enum CursorFlags + { + None = 0, + Elements = 1, + Attributes = 2, + Multiple = 4, + Mutable = 8, + AllNodes = Elements | Attributes + } + + public static class CursorFlagsExtensions + { + public static CursorFlags MutableIf(this CursorFlags flags, bool mutable) + { + return mutable ? (flags | CursorFlags.Mutable) : flags; + } + + public static bool IncludesElements(this CursorFlags flags) + { + return 0 != (flags & CursorFlags.Elements); + } + + public static bool IncludesAttributes(this CursorFlags flags) + { + return 0 != (flags & CursorFlags.Attributes); + } + + public static bool AllowsMultipleItems(this CursorFlags flags) + { + return 0 != (flags & CursorFlags.Multiple); + } + + public static bool SupportsMutation(this CursorFlags flags) + { + return 0 != (flags & CursorFlags.Mutable); + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/IXmlContext.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/IXmlContext.cs new file mode 100644 index 0000000..18bdbb2 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/IXmlContext.cs @@ -0,0 +1,33 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + using System.Collections.Generic; + + public interface IXmlContext : IXmlNamespaceSource + { + string ChildNamespaceUri { get; } + + IXmlContext Clone(); + XmlName GetDefaultXsiType(Type clrType); + IEnumerable GetIncludedTypes(Type baseType); + bool IsReservedNamespaceUri(string namespaceUri); + + void AddVariable(XPathVariableAttribute attribute); + void AddFunction(XPathFunctionAttribute attribute); + void Enlist(CompiledXPath path); + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/IXmlCursor.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/IXmlCursor.cs new file mode 100644 index 0000000..0a359c7 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/IXmlCursor.cs @@ -0,0 +1,30 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + + public interface IXmlCursor : IXmlIterator + { + void Reset(); + void MoveTo(IXmlNode node); + void MoveToEnd(); + + void Create(Type type); + void Coerce(Type type); + void Remove(); + void RemoveAllNext(); + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/IXmlIterator.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/IXmlIterator.cs new file mode 100644 index 0000000..6be4cc2 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/IXmlIterator.cs @@ -0,0 +1,23 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + + public interface IXmlIterator : IXmlNode + { + bool MoveNext(); + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/IXmlNamespaceSource.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/IXmlNamespaceSource.cs new file mode 100644 index 0000000..6afb05f --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/IXmlNamespaceSource.cs @@ -0,0 +1,22 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + public interface IXmlNamespaceSource + { + string GetElementPrefix (IXmlNode node, string namespaceUri); + string GetAttributePrefix(IXmlNode node, string namespaceUri); + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/IXmlNode.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/IXmlNode.cs new file mode 100644 index 0000000..1b7d7e1 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/IXmlNode.cs @@ -0,0 +1,55 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + using System.Xml; + + public interface IXmlNode : IXmlKnownType, IRealizableSource, IVirtual + { + bool IsElement { get; } + bool IsAttribute { get; } + bool IsNil { get; set; } + string Value { get; set; } // Equivalent to InnerText + string Xml { get; } // Equivalent to OuterXml + + IXmlNode Parent { get; } + IXmlNamespaceSource Namespaces { get; } + + string GetAttribute(XmlName name); + void SetAttribute(XmlName name, string value); + + string LookupPrefix (string namespaceUri); + string LookupNamespaceUri(string prefix); + void DefineNamespace (string prefix, string namespaceUri, bool root); + + object UnderlyingObject { get; } + bool UnderlyingPositionEquals(IXmlNode node); + + IXmlNode Save(); + IXmlCursor SelectSelf(Type clrType); + IXmlCursor SelectChildren(IXmlKnownTypeMap knownTypes, IXmlNamespaceSource namespaces, CursorFlags flags); + IXmlIterator SelectSubtree(); + + CompiledXPath Path { get; } + IXmlCursor Select (CompiledXPath path, IXmlIncludedTypeMap includedTypes, IXmlNamespaceSource namespaces, CursorFlags flags); + object Evaluate(CompiledXPath path); + + void Clear(); + XmlReader ReadSubtree(); + XmlWriter WriteAttributes(); + XmlWriter WriteChildren(); + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/IXmlNodeSource.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/IXmlNodeSource.cs new file mode 100644 index 0000000..3a09b12 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/IXmlNodeSource.cs @@ -0,0 +1,21 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + public interface IXmlNodeSource + { + IXmlNode Node { get; } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/XmlContext.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/XmlContext.cs new file mode 100644 index 0000000..3c207be --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/XmlContext.cs @@ -0,0 +1,62 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + using System.Collections.Generic; + + public class XmlContext : XmlContextBase, IXmlContext + { + private readonly XmlMetadata metadata; + + public XmlContext(XmlMetadata metadata) + { + if (metadata == null) + throw Error.ArgumentNull(nameof(metadata)); + + this.metadata = metadata; + } + + protected XmlContext(XmlContext parent) : base(parent) + { + this.metadata = parent.metadata; + } + + public IXmlContext Clone() + { + return new XmlContext(this); + } + + public string ChildNamespaceUri + { + get { return metadata.ChildNamespaceUri; } + } + + public bool IsReservedNamespaceUri(string namespaceUri) + { + return metadata.IsReservedNamespaceUri(namespaceUri); + } + + public XmlName GetDefaultXsiType(Type clrType) + { + return metadata.GetDefaultXsiType(clrType); + } + + public IEnumerable GetIncludedTypes(Type baseType) + { + return metadata.GetIncludedTypes(baseType); + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/XmlContextBase.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/XmlContextBase.cs new file mode 100644 index 0000000..eb7d85e --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/XmlContextBase.cs @@ -0,0 +1,287 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + using System.Collections.Generic; + using System.Xml; + using System.Xml.XPath; + using System.Xml.Xsl; + + public class XmlContextBase : XsltContext, IXmlNamespaceSource + { + private readonly XmlContextBase parent; + private Dictionary rootNamespaces; + private bool hasNamespaces; + private XPathContext xPathContext; + private Dictionary variables; + private Dictionary functions; + + public XmlContextBase() + : base(new NameTable()) + { + AddNamespace(Xsd .Namespace); + AddNamespace(Xsi .Namespace); + AddNamespace(Wsdl.Namespace); + AddNamespace(XRef.Namespace); + } + + protected XmlContextBase(XmlContextBase parent) + : base(GetNameTable(parent)) + { + this.parent = parent; + } + + private static NameTable GetNameTable(XmlContextBase parent) + { + return parent.NameTable as NameTable ?? new NameTable(); + } + + public void AddNamespace(XmlNamespaceAttribute attribute) + { + var prefix = attribute.Prefix; + var uri = attribute.NamespaceUri; + + if (string.IsNullOrEmpty(uri)) + throw Error.InvalidNamespaceUri(); + + if (attribute.Default) + AddNamespace(string.Empty, uri); + + if (string.IsNullOrEmpty(prefix)) + return; + + AddNamespace(prefix, uri); + + if (attribute.Root) + EnsureRootNamespaces().Add(prefix, uri); + } + + public override void AddNamespace(string prefix, string uri) + { + base.AddNamespace(prefix, uri); + hasNamespaces = true; + } + + private Dictionary EnsureRootNamespaces() + { + return rootNamespaces ?? + ( + rootNamespaces = parent != null + ? new Dictionary(parent.EnsureRootNamespaces()) + : new Dictionary() + ); + } + + public override string LookupNamespace(string prefix) + { + return hasNamespaces + ? base .LookupNamespace(prefix) + : parent.LookupNamespace(prefix); + } + + public override string LookupPrefix(string uri) + { + return hasNamespaces + ? base .LookupPrefix(uri) + : parent.LookupPrefix(uri); + } + + public string GetElementPrefix(IXmlNode node, string namespaceUri) + { + string prefix; + if (namespaceUri == node.LookupNamespaceUri(string.Empty)) + return string.Empty; + if (TryGetDefinedPrefix(node, namespaceUri, out prefix)) + return prefix; + if (!TryGetPreferredPrefix(node, namespaceUri, out prefix)) + return string.Empty; + if (!ShouldDefineOnRoot(prefix, namespaceUri)) + return string.Empty; + + node.DefineNamespace(prefix, namespaceUri, true); + return prefix; + } + + public string GetAttributePrefix(IXmlNode node, string namespaceUri) + { + string prefix; + if (string.IsNullOrEmpty(namespaceUri)) // was: namespaceUri == node.Name.NamespaceUri + return string.Empty; + if (TryGetDefinedPrefix(node, namespaceUri, out prefix)) + return prefix; + if (!TryGetPreferredPrefix(node, namespaceUri, out prefix)) + prefix = GeneratePrefix(node); + + var root = ShouldDefineOnRoot(prefix, namespaceUri); + node.DefineNamespace(prefix, namespaceUri, root); + return prefix; + } + + private static bool TryGetDefinedPrefix(IXmlNode node, string namespaceUri, out string prefix) + { + var definedPrefix = node.LookupPrefix(namespaceUri); + return string.IsNullOrEmpty(definedPrefix) + ? Try.Failure(out prefix) + : Try.Success(out prefix, definedPrefix); + } + + private bool TryGetPreferredPrefix(IXmlNode node, string namespaceUri, out string prefix) + { + prefix = this.LookupPrefix(namespaceUri); + if (string.IsNullOrEmpty(prefix)) + return Try.Failure(out prefix); // No preferred prefix + + namespaceUri = node.LookupNamespaceUri(prefix); + return string.IsNullOrEmpty(namespaceUri) + ? true // Can use preferred prefix + : Try.Failure(out prefix); // Preferred prefix already in use + } + + private static string GeneratePrefix(IXmlNode node) + { + for (var i = 0; ; i++) + { + var prefix = "p" + i; + var namespaceUri = node.LookupNamespaceUri(prefix); + if (string.IsNullOrEmpty(namespaceUri)) + return prefix; + } + } + + private bool ShouldDefineOnRoot(string prefix, string uri) + { + return rootNamespaces != null + ? ShouldDefineOnRootCore (prefix, uri) + : parent.ShouldDefineOnRoot(prefix, uri); + } + + private bool ShouldDefineOnRootCore(string prefix, string uri) + { + string candidate; + return rootNamespaces.TryGetValue(prefix, out candidate) + && candidate == uri; + } + + private XPathContext XPathContext + { + get { return xPathContext ?? (xPathContext = new XPathContext(this)); } + } + + public override bool Whitespace + { + get { return true; } + } + + public override bool PreserveWhitespace(XPathNavigator node) + { + return true; + } + + public override int CompareDocument(string baseUriA, string baseUriB) + { + return StringComparer.Ordinal.Compare(baseUriA, baseUriB); + } + + public void AddVariable(string prefix, string name, IXsltContextVariable variable) + { + var key = new XmlName(name, prefix ?? string.Empty); + AddVariable(key, variable); + } + + public void AddFunction(string prefix, string name, IXsltContextFunction function) + { + var key = new XmlName(name, prefix ?? string.Empty); + AddFunction(key, function); + } + + public void AddVariable(XPathVariableAttribute attribute) + { + AddVariable(attribute.Name, attribute); + } + + public void AddFunction(XPathFunctionAttribute attribute) + { + AddFunction(attribute.Name, attribute); + } + + public void AddVariable(XmlName name, IXsltContextVariable variable) + { + EnsureVariables()[name] = variable; + } + + public void AddFunction(XmlName name, IXsltContextFunction function) + { + EnsureFunctions()[name] = function; + } + + private Dictionary EnsureVariables() + { + return variables ?? + ( + variables = (parent != null) + ? new Dictionary(parent.EnsureVariables()) + : new Dictionary() + ); + } + + private Dictionary EnsureFunctions() + { + return functions ?? + ( + functions = (parent != null) + ? new Dictionary(parent.EnsureFunctions()) + : new Dictionary() + ); + } + + public override IXsltContextVariable ResolveVariable(string prefix, string name) + { + return + variables != null ? ResolveVariableCore (prefix, name) : + parent != null ? parent.ResolveVariable(prefix, name) : + null; + } + + public override IXsltContextFunction ResolveFunction(string prefix, string name, XPathResultType[] argTypes) + { + return + functions != null ? ResolveFunctionCore (prefix, name, argTypes) : + parent != null ? parent.ResolveFunction(prefix, name, argTypes) : + null; + } + + private IXsltContextVariable ResolveVariableCore(string prefix, string name) + { + IXsltContextVariable variable; + var key = new XmlName(name, prefix ?? string.Empty); + variables.TryGetValue(key, out variable); + return variable; + } + + private IXsltContextFunction ResolveFunctionCore(string prefix, string name, XPathResultType[] argTypes) + { + IXsltContextFunction function; + var key = new XmlName(name, prefix ?? string.Empty); + functions.TryGetValue(key, out function); + return function; + } + + public void Enlist(CompiledXPath path) + { + path.SetContext(XPathContext); + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/XmlExtensions.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/XmlExtensions.cs new file mode 100644 index 0000000..3dd2de5 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/XmlExtensions.cs @@ -0,0 +1,46 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + using System.Xml; + + internal static class XmlExtensions + { + public static bool PositionEquals(this IXmlNode nodeA, IXmlNode nodeB) + { + return XmlPositionComparer.Instance.Equals(nodeA, nodeB); + } + + public static void CopyTo(this IXmlNode source, IXmlNode target) + { + using (var reader = source.ReadSubtree()) + { + if (!reader.Read()) + return; + + using (var writer = target.WriteAttributes()) + writer.WriteAttributes(reader, false); + + if (!reader.Read()) + return; + + using (var writer = target.WriteChildren()) + do writer.WriteNode(reader, false); + while (!(reader.EOF || reader.NodeType == XmlNodeType.EndElement)); + } + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/XmlName.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/XmlName.cs new file mode 100644 index 0000000..38eca47 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/XmlName.cs @@ -0,0 +1,100 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + + public struct XmlName : IEquatable + { + public static readonly XmlName Empty = default(XmlName); + + private readonly string localName; + private readonly string namespaceUri; + + public XmlName(string localName, string namespaceUri) + { + this.localName = localName; + this.namespaceUri = namespaceUri; + } + + public string LocalName + { + get { return localName; } + } + + public string NamespaceUri + { + get { return namespaceUri; } + } + + public override int GetHashCode() + { + return XmlNameComparer.Default.GetHashCode(this); + } + + public bool Equals(XmlName other) + { + return XmlNameComparer.Default.Equals(this, other); + } + + public override bool Equals(object obj) + { + return obj is XmlName + && Equals((XmlName) obj); + } + + public static bool operator == (XmlName x, XmlName y) + { + return XmlNameComparer.Default.Equals(x, y); + } + + public static bool operator != (XmlName x, XmlName y) + { + return ! XmlNameComparer.Default.Equals(x, y); + } + + public XmlName WithNamespaceUri(string namespaceUri) + { + return new XmlName(localName, namespaceUri); + } + + public override string ToString() + { + if (string.IsNullOrEmpty(localName)) + return string.Empty; + if (string.IsNullOrEmpty(namespaceUri)) + return localName; + return string.Concat(namespaceUri, ":", localName); + } + + public static XmlName ParseQName(string text) + { + if (text == null) + throw Error.ArgumentNull(nameof(text)); + + var index = text.IndexOf(':'); + if (index == -1) + return new XmlName(text, null); + if (index == 0) + return new XmlName(text.Substring(1), null); + if (index == text.Length) + return new XmlName(text.Substring(0, index), null); + + return new XmlName( + text.Substring(index + 1), + text.Substring(0, index)); + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/XmlNameComparer.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/XmlNameComparer.cs new file mode 100644 index 0000000..c1cc9c3 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/XmlNameComparer.cs @@ -0,0 +1,52 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + using System.Collections.Generic; + + public class XmlNameComparer : IEqualityComparer + { + public static readonly XmlNameComparer + Default = new XmlNameComparer(StringComparer.Ordinal), + IgnoreCase = new XmlNameComparer(StringComparer.OrdinalIgnoreCase); + + private readonly StringComparer comparer; + + private XmlNameComparer(StringComparer comparer) + { + this.comparer = comparer; + } + + public int GetHashCode(XmlName name) + { + var code = (name.LocalName != null) + ? comparer.GetHashCode(name.LocalName) + : 0; + + if (name.NamespaceUri != null) + code = (code << 7 | code >> 25) + ^ comparer.GetHashCode(name.NamespaceUri); + + return code; + } + + public bool Equals(XmlName x, XmlName y) + { + return comparer.Equals(x.LocalName, y.LocalName) + && comparer.Equals(x.NamespaceUri, y.NamespaceUri); + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/XmlNodeBase.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/XmlNodeBase.cs new file mode 100644 index 0000000..90dc2e6 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/XmlNodeBase.cs @@ -0,0 +1,81 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + + public abstract class XmlNodeBase : IRealizableSource, IVirtual + { + protected Type type; + private readonly IXmlNode parent; + private readonly IXmlNamespaceSource namespaces; + + protected XmlNodeBase(IXmlNamespaceSource namespaces, IXmlNode parent) + { + if (null == namespaces) + throw Error.ArgumentNull(nameof(namespaces)); + + this.namespaces = namespaces; + this.parent = parent; + } + + public virtual bool IsReal + { + get { return true; } + } + + public virtual Type ClrType + { + get { return type; } + } + + public IXmlNode Parent + { + get { return parent; } + } + + public IXmlNamespaceSource Namespaces + { + get { return namespaces; } + } + + public virtual CompiledXPath Path + { + get { return null; } + } + + IRealizable IRealizableSource.AsRealizable() + { + return this as IRealizable; + } + + protected virtual void Realize() + { + // Default nodes are fully realized already + } + + void IVirtual.Realize() + { + Realize(); + } + + public virtual event EventHandler Realized + { + // Default nodes never realize + add { } + remove { } + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/XmlPositionComparer.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/XmlPositionComparer.cs new file mode 100644 index 0000000..bbf0fe9 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/XmlPositionComparer.cs @@ -0,0 +1,94 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + public class XmlPositionComparer + { + public static readonly XmlPositionComparer + Instance = new XmlPositionComparer(); + + public bool Equals(IXmlNode nodeA, IXmlNode nodeB) + { + var comparer = XmlNameComparer.Default; + var a = new ComparandIterator { Node = nodeA }; + var b = new ComparandIterator { Node = nodeB }; + + for (;;) + { + if (a.Node.IsReal && b.Node.IsReal) + return a.Node.UnderlyingPositionEquals(b.Node); + if (!a.MoveNext() || !b.MoveNext()) + return false; + if (!comparer.Equals(a.Name, b.Name)) + return false; + } + } + + private struct ComparandIterator + { + public IXmlNode Node; + public XmlName Name; + public CompiledXPathNode Step; + + public bool MoveNext() + { + return + Step != null ? ConsumeStep() : + Node != null ? ConsumeNode() : + Stop(); + } + + private bool ConsumeNode() + { + var result = true; + var path = Node.Path; + if (path != null) + result = ConsumeFirstStep(path); + else + Name = Node.Name; + + Node = Node.Parent; + return result; + } + + private bool Stop() + { + Name = XmlName.Empty; + return false; + } + + private bool ConsumeFirstStep(CompiledXPath path) + { + if (!path.IsCreatable) + return false; + + Step = path.LastStep; + return ConsumeStep(); + } + + private bool ConsumeStep() + { + Name = new XmlName + ( + Step.LocalName, + Node.LookupNamespaceUri(Step.Prefix) + ); + + Step = Step.PreviousNode; + return true; + } + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/XmlSelfCursor.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/XmlSelfCursor.cs new file mode 100644 index 0000000..04c4287 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/XmlSelfCursor.cs @@ -0,0 +1,250 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + using System.Xml; + + public class XmlSelfCursor : IXmlCursor + { + private readonly IXmlNode node; + private readonly Type clrType; + private int position; + + public XmlSelfCursor(IXmlNode node, Type clrType) + { + this.node = node; + this.clrType = clrType; + Reset(); + } + + public CursorFlags Flags + { + get { return node.IsAttribute ? CursorFlags.Attributes : CursorFlags.Elements; } + } + + public CompiledXPath Path + { + get { return node.Path; } + } + + public XmlName Name + { + get { return node.Name; } + } + + public XmlName XsiType + { + get { return node.XsiType; } + } + + public Type ClrType + { + get { return clrType ?? node.ClrType; } + } + + public bool IsReal + { + get { return node.IsReal; } + } + + public bool IsElement + { + get { return node.IsElement; } + } + + public bool IsAttribute + { + get { return node.IsAttribute; } + } + + public bool IsNil + { + get { return node.IsNil; } + set { throw Error.NotSupported(); } + } + + public string Value + { + get { return node.Value; } + set { node.Value = value; } + } + + public string Xml + { + get { return node.Xml; } + } + + public IXmlNode Parent + { + get { return node.Parent; } + } + + public IXmlNamespaceSource Namespaces + { + get { return node.Namespaces; } + } + + public object UnderlyingObject + { + get { return node.UnderlyingObject; } + } + + public bool UnderlyingPositionEquals(IXmlNode node) + { + return this.node.UnderlyingPositionEquals(node); + } + + public IRealizable AsRealizable() + { + return node.AsRealizable(); + } + + public void Realize() + { + node.Realize(); + } + + public event EventHandler Realized + { + add { node.Realized += value; } + remove { node.Realized -= value; } + } + + public string GetAttribute(XmlName name) + { + return node.GetAttribute(name); + } + + public void SetAttribute(XmlName name, string value) + { + node.SetAttribute(name, value); + } + + public string LookupPrefix(string namespaceUri) + { + return node.LookupPrefix(namespaceUri); + } + + public string LookupNamespaceUri(string prefix) + { + return node.LookupNamespaceUri(prefix); + } + + public void DefineNamespace(string prefix, string namespaceUri, bool root) + { + node.DefineNamespace(prefix, namespaceUri, root); + } + + public bool MoveNext() + { + return 0 == ++position; + } + + public void MoveToEnd() + { + position = 1; + } + + public void Reset() + { + position = -1; + } + + public void MoveTo(IXmlNode position) + { + if (position != node) + throw Error.NotSupported(); + } + + public IXmlNode Save() + { + return position == 0 + ? new XmlSelfCursor(node.Save(), clrType) { position = 0 } + : this; + } + + public IXmlCursor SelectSelf(Type clrType) + { + return new XmlSelfCursor(node, clrType); + } + + public IXmlCursor SelectChildren(IXmlKnownTypeMap knownTypes, IXmlNamespaceSource namespaces, CursorFlags flags) + { + return node.SelectChildren(knownTypes, namespaces, flags); + } + + public IXmlIterator SelectSubtree() + { + return node.SelectSubtree(); + } + + public IXmlCursor Select(CompiledXPath path, IXmlIncludedTypeMap knownTypes, IXmlNamespaceSource namespaces, CursorFlags flags) + { + return node.Select(path, knownTypes, namespaces, flags); + } + + public object Evaluate(CompiledXPath path) + { + return node.Evaluate(path); + } + + public XmlReader ReadSubtree() + { + return node.ReadSubtree(); + } + + public XmlWriter WriteAttributes() + { + return node.WriteAttributes(); + } + + public XmlWriter WriteChildren() + { + return node.WriteChildren(); + } + + public void MakeNext(Type type) + { + if (!MoveNext()) + throw Error.NotSupported(); + } + + public void Create(Type type) + { + throw Error.NotSupported(); + } + + public void Coerce(Type type) + { + // Do nothing + } + + public void Clear() + { + node.Clear(); + } + + public void Remove() + { + // Do nothing + } + + public void RemoveAllNext() + { + // Do nothing + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/SystemXml/SysXmlCursor.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/SystemXml/SysXmlCursor.cs new file mode 100644 index 0000000..62fa949 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/SystemXml/SysXmlCursor.cs @@ -0,0 +1,566 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + using System.Xml.XPath; + using System.Xml; + + public class SysXmlCursor : SysXmlNode, IXmlCursor + { + private State state; + private int index; + private readonly IXmlKnownTypeMap knownTypes; + private readonly CursorFlags flags; + + protected enum State + { + Empty = -4, // After last item, no items were selected + End = -3, // After last item, 1+ items were selected + AttributePrimed = -2, // MoveNext will select an attribute (happens after remove) + ElementPrimed = -1, // MoveNext will select an element (happens after remove) + Initial = 0, // Before first item + Element = 1, // An element is currently selected + Attribute = 2 // An attribute is currently selected + } + + public SysXmlCursor(IXmlNode parent, IXmlKnownTypeMap knownTypes, IXmlNamespaceSource namespaces, CursorFlags flags) + : base(namespaces, parent) + { + if (null == parent) + throw Error.ArgumentNull(nameof(parent)); + if (null == knownTypes) + throw Error.ArgumentNull(nameof(knownTypes)); + + this.knownTypes = knownTypes; + this.flags = flags; + this.index = -1; + + var source = parent.RequireRealizable(); + if (source.IsReal) + node = source.Value; + } + + public override bool IsReal + { + get { return HasCurrent; } + } + + public bool HasCurrent + { + get { return state > State.Initial; } + } + + public override Type ClrType + { + get { return HasCurrent ? base.ClrType : knownTypes.Default.ClrType; } + } + + public override XmlName Name + { + get { return HasCurrent ? base.Name : GetEffectiveName(knownTypes.Default, node); } + } + + public override XmlName XsiType + { + get { return HasCurrent ? base.XsiType : knownTypes.Default.XsiType; } + } + + public override bool IsElement + { + get { return HasCurrent ? base.IsElement : flags.IncludesElements(); } + } + + public override bool IsAttribute + { + get { return HasCurrent ? base.IsAttribute : !flags.IncludesElements(); } + } + + public override bool IsNil + { + get { return HasCurrent && base.IsNil; } + set { Realize(); base.IsNil = value; } + } + + public override string Value + { + get { return HasCurrent ? base.Value : string.Empty; } + set { base.Value = value; } // base sets IsNil, so no need to call Realize() here + } + + public override string Xml + { + get { return HasCurrent ? base.Xml : null; } + } + + public override object Evaluate(CompiledXPath path) + { + return HasCurrent ? base.Evaluate(path) : null; + } + + public bool MoveNext() + { + var hadCurrent = HasCurrent; + var hasCurrent = MoveNextCore() && + ( + flags.AllowsMultipleItems() || + IsAtEnd() + ); + + if (!hasCurrent && !hadCurrent) + state = State.Empty; + + return hasCurrent; + } + + private bool MoveNextCore() + { + while (Advance()) + if (IsMatch()) return true; + + return false; + } + + private bool IsMatch() + { + IXmlKnownType knownType; + return knownTypes.TryGet(this, out knownType) + ? Try.Success(out type, knownType.ClrType) + : Try.Failure(out type); + } + + private bool Advance() + { + for (;;) + { + switch (state) + { + case State.Initial: return AdvanceToFirstElement() || AdvanceToFirstAttribute() || Fail(State.End); + case State.Element: return AdvanceToNextElement() || AdvanceToFirstAttribute() || Fail(State.End); + case State.Attribute: return AdvanceToNextAttribute() || Fail(State.End); + case State.ElementPrimed: return Succeed(State.Element); + case State.AttributePrimed: return Succeed(State.Attribute); + case State.End: return false; + case State.Empty: return false; + } + } + } + + protected virtual bool AdvanceToFirstElement() + { + if (!flags.IncludesElements() || node == null) + return false; + if (!AdvanceElement(node.FirstChild)) + return false; + state = State.Element; + return true; + } + + private bool AdvanceToNextElement() + { + if (AdvanceElement(node.NextSibling)) + return true; + MoveToParentOfElement(); + return false; + } + + protected virtual bool AdvanceToFirstAttribute() + { + if (!flags.IncludesAttributes() || node == null) + return false; + if (!AdvanceAttribute(node)) + return false; + state = State.Attribute; + return true; + } + + private bool AdvanceToNextAttribute() + { + if (AdvanceAttribute(((XmlAttribute)node).OwnerElement)) + return true; + MoveToParentOfAttribute(); + return false; + } + + private bool AdvanceElement(XmlNode next) + { + for (;;) + { + if (next == null) + return false; + + if (next.NodeType == XmlNodeType.Element) + { + node = next; + return true; + } + + next = next.NextSibling; + } + } + + private bool AdvanceAttribute(XmlNode parent) + { + var attributes = parent.Attributes; + + for (;;) + { + index++; + if (index >= attributes.Count) + return false; + + var attribute = attributes[index]; + if (!attribute.IsNamespace()) + { + node = attribute; + return true; + } + } + } + + private bool Succeed(State state) + { + this.state = state; + return true; + } + + private bool Fail(State state) + { + this.state = state; + return false; + } + + private bool IsAtEnd() + { + var priorNode = node; + var priorType = type; + var priorState = state; + var priorIndex = index; + + var hasNext = MoveNextCore(); + + node = priorNode; + type = priorType; + state = priorState; + index = priorIndex; + + return !hasNext; + } + + public void MoveTo(IXmlNode position) + { + var source = position.AsRealizable(); + if (source == null || !source.IsReal) + throw Error.CursorCannotMoveToGivenNode(); + + IXmlKnownType knownType; + if (!knownTypes.TryGet(position, out knownType)) + throw Error.CursorCannotMoveToGivenNode(); + + node = source.Value; + type = knownType.ClrType; + + if (IsElement) + SetMovedToElement(); + else + SetMovedToAttribute(); + } + + private void SetMovedToElement() + { + state = State.Element; + index = -1; + } + + private void SetMovedToAttribute() + { + state = State.Attribute; + + var parent = ((XmlAttribute) node).OwnerElement; + var attributes = parent.Attributes; + + for (index = 0; index < attributes.Count; index++) + if (attributes[index] == node) + break; + } + + public void MoveToEnd() + { + switch (state) + { + case State.Element: + case State.ElementPrimed: + MoveToParentOfElement(); + state = State.End; + break; + + case State.Attribute: + case State.AttributePrimed: + MoveToParentOfAttribute(); + state = State.End; + break; + + case State.Initial: + state = IsAtEnd() ? State.Empty : State.End; + break; + } + } + + public void Reset() + { + MoveToEnd(); + state = State.Initial; + index = -1; + } + + private void MoveToParentOfElement() + { + node = node.ParentNode; + } + + private void MoveToParentOfAttribute() + { + node = ((XmlAttribute) node).OwnerElement; + } + + private void MoveToRealizedParent() + { + var parent = Parent; + node = parent.AsRealizable().Value; + parent.IsNil = false; + } + + public override event EventHandler Realized; + protected virtual void OnRealized() + { + if (Realized != null) + Realized(this, EventArgs.Empty); + } + + protected override void Realize() + { + if (HasCurrent) + return; + if (state != State.Empty) + throw Error.CursorNotInRealizableState(); + if (!flags.SupportsMutation()) + throw Error.CursorNotMutable(); + Create(knownTypes.Default.ClrType); + OnRealized(); + } + + public void MakeNext(Type clrType) + { + if (MoveNext()) + Coerce(clrType); + else + Create(clrType); + } + + public void Coerce(Type clrType) + { + RequireCoercible(); + + var knownType = knownTypes.Require(clrType); + + if (IsElement) + CoerceElement (knownType); + else + CoerceAttribute(knownType); + + this.type = knownType.ClrType; + } + + private void CoerceElement(IXmlKnownType knownType) + { + var oldNode = (XmlElement) node; + var parent = oldNode.ParentNode; + var name = GetEffectiveName(knownType, parent); + + if (!XmlNameComparer.Default.Equals(this.Name, name)) + { + var newNode = CreateElementCore(parent, name); + parent.ReplaceChild(newNode, oldNode); + + if (knownType.XsiType != XmlName.Empty) + this.SetXsiType(knownType.XsiType); + } + else this.SetXsiType(knownType.XsiType); + } + + private void CoerceAttribute(IXmlKnownType knownType) + { + RequireNoXsiType(knownType); + + var oldNode = (XmlAttribute) node; + var parent = oldNode.OwnerElement; + var name = GetEffectiveName(knownType, parent); + + if (!XmlNameComparer.Default.Equals(this.Name, name)) + { + var newNode = CreateAttributeCore(parent, name); + var attributes = parent.Attributes; + attributes.RemoveNamedItem(newNode.LocalName, newNode.NamespaceURI); + attributes.InsertBefore(newNode, oldNode); + attributes.Remove(oldNode); + } + } + + public void Create(Type type) + { + var knownType = knownTypes.Require(type); + var position = RequireCreatable(); + + if (flags.IncludesElements()) + CreateElement (knownType, position); + else + CreateAttribute(knownType, position); + + this.type = knownType.ClrType; + } + + private void CreateElement(IXmlKnownType knownType, XmlNode position) + { + var parent = node; + var name = GetEffectiveName(knownType, parent); + var element = CreateElementCore(parent, name); + parent.InsertBefore(element, position); + state = State.Element; + + if (knownType.XsiType != XmlName.Empty) + this.SetXsiType(knownType.XsiType); + } + + private void CreateAttribute(IXmlKnownType knownType, XmlNode position) + { + RequireNoXsiType(knownType); + + var parent = node; + var name = GetEffectiveName(knownType, parent); + var attribute = CreateAttributeCore(parent, name); + parent.Attributes.InsertBefore(attribute, (XmlAttribute) position); + state = State.Attribute; + } + + private XmlElement CreateElementCore(XmlNode parent, XmlName name) + { + var document = parent.OwnerDocument ?? (XmlDocument) parent; + var prefix = Namespaces.GetElementPrefix(this, name.NamespaceUri); + var element = document.CreateElement(prefix, name.LocalName, name.NamespaceUri); + node = element; + return element; + } + + private XmlAttribute CreateAttributeCore(XmlNode parent, XmlName name) + { + var document = parent.OwnerDocument ?? (XmlDocument) parent; + var prefix = Namespaces.GetAttributePrefix(this, name.NamespaceUri); + var attribute = document.CreateAttribute(prefix, name.LocalName, name.NamespaceUri); + node = attribute; + return attribute; + } + + private void RequireNoXsiType(IXmlKnownType knownType) + { + if (knownType.XsiType != XmlName.Empty) + throw Error.CannotSetAttribute(this); + } + + private XmlName GetEffectiveName(IXmlKnownType knownType, XmlNode parent) + { + var name = knownType.Name; + + return name.NamespaceUri != null + ? name + : name.WithNamespaceUri + ( + parent != null + ? parent.NamespaceURI + : string.Empty + ); + } + + public void RemoveAllNext() + { + while (MoveNext()) + Remove(); + } + + public void Remove() + { + RequireRemovable(); + + var removedNode = node; + var wasElement = IsElement; + MoveNext(); + + switch (state) + { + case State.Attribute: state = State.AttributePrimed; break; + case State.Element: state = State.ElementPrimed; break; + } + + if (wasElement) + RemoveElement (removedNode); + else + RemoveAttribute(removedNode); + } + + private void RemoveElement(XmlNode node) + { + node.ParentNode.RemoveChild(node); + } + + private void RemoveAttribute(XmlNode node) + { + var attribute = (XmlAttribute) node; + attribute.OwnerElement.Attributes.Remove(attribute); + } + + public override IXmlNode Save() + { + return HasCurrent ? new SysXmlNode(node, type, Namespaces) : this; + } + + private XmlNode RequireCreatable() + { + XmlNode position; + switch (state) + { + case State.Element: position = node; MoveToParentOfElement(); break; + case State.Attribute: position = node; MoveToParentOfAttribute(); break; + case State.Empty: position = null; MoveToRealizedParent(); break; + case State.End: position = null; break; + default: throw Error.CursorNotInCreatableState(); + } + return position; + } + + private void RequireCoercible() + { + if (state <= State.Initial) + throw Error.CursorNotInCoercibleState(); + } + + private void RequireRemovable() + { + if (state <= State.Initial) + throw Error.CursorNotInRemovableState(); + } + + protected static readonly StringComparer + DefaultComparer = StringComparer.OrdinalIgnoreCase; + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/SystemXml/SysXmlExtensions.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/SystemXml/SysXmlExtensions.cs new file mode 100644 index 0000000..791f365 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/SystemXml/SysXmlExtensions.cs @@ -0,0 +1,57 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + using System.Collections.Generic; + using System.Xml; + using System.Xml.Serialization; + using System.Xml.XPath; + + public static class SysXmlExtensions + { + public static void DefineNamespace(this XmlElement node, string prefix, string namespaceUri) + { + var attribute = node.OwnerDocument.CreateAttribute(Xmlns.Prefix, prefix, Xmlns.NamespaceUri); + attribute.Value = namespaceUri; + node.SetAttributeNode(attribute); + } + + public static bool IsNamespace(this XmlAttribute attribute) + { + return attribute.Prefix == Xmlns.Prefix || + ( + string.IsNullOrEmpty(attribute.Prefix) && + attribute.LocalName == Xmlns.Prefix + ); + } + + public static XmlElement FindRoot(this XmlElement node) + { + for (;;) + { + var next = node.ParentNode as XmlElement; + if (next == null) return node; + node = next; + } + } + + public static bool IsXsiType(this XmlAttribute attribute) + { + return attribute.LocalName == Xsi.Type.LocalName + && attribute.NamespaceURI == Xsi.NamespaceUri; + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/SystemXml/SysXmlNode.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/SystemXml/SysXmlNode.cs new file mode 100644 index 0000000..81202f6 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/SystemXml/SysXmlNode.cs @@ -0,0 +1,298 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + using System.Xml; + using System.Xml.XPath; + + public class SysXmlNode : XmlNodeBase, IXmlNode, + IRealizable, + IRealizable + { + protected XmlNode node; + + protected SysXmlNode(IXmlNamespaceSource namespaces, IXmlNode parent) + : base(namespaces, parent) { } + + public SysXmlNode(XmlNode node, Type type, IXmlNamespaceSource namespaces) + : base(namespaces, null) + { + if (node == null) + throw Error.ArgumentNull(nameof(node)); + if (type == null) + throw Error.ArgumentNull(nameof(type)); + + this.node = node; + this.type = type; + } + + public object UnderlyingObject + { + get { return node; } + } + + XmlNode IRealizable.Value + { + get { Realize(); return node; } + } + + XPathNavigator IRealizable.Value + { + get { Realize(); return node.CreateNavigator(); } + } + + public virtual XmlName Name + { + get { return new XmlName(node.LocalName, node.NamespaceURI); } + } + + public virtual XmlName XsiType + { + get { return this.GetXsiType(); } + } + + public virtual bool IsElement + { + get { return node.NodeType == XmlNodeType.Element; } + } + + public virtual bool IsAttribute + { + get { return node.NodeType == XmlNodeType.Attribute; } + } + + public virtual bool IsNil + { + get { return this.IsXsiNil(); } + set { this.SetXsiNil(value); } + } + + public virtual string Value + { + get { return node.InnerText; } + set { var nil = (value == null); IsNil = nil; if (!nil) node.InnerText = value; } + } + + public virtual string Xml + { + get { return node.OuterXml; } + } + + public bool UnderlyingPositionEquals(IXmlNode node) + { + var sysXmlNode = node.AsRealizable(); + if (sysXmlNode != null) + return sysXmlNode.IsReal + && sysXmlNode.Value == this.node; + + var xPathNode = node.AsRealizable(); + if (xPathNode != null) + return xPathNode.IsReal + && xPathNode.Value.UnderlyingObject == this.node; + + return false; + } + + public string GetAttribute(XmlName name) + { + if (!IsReal) + return null; + + var element = node as XmlElement; + if (element == null) + return null; + + var attribute = element.GetAttributeNode(name.LocalName, name.NamespaceUri); + if (attribute == null) + return null; + + var value = attribute.Value; + if (string.IsNullOrEmpty(value)) + return null; + + return value; + } + + public void SetAttribute(XmlName name, string value) + { + if (string.IsNullOrEmpty(value)) + ClearAttribute(name); + else + SetAttributeCore(name, value); + } + + private void SetAttributeCore(XmlName name, string value) + { + if (!IsElement) + throw Error.CannotSetAttribute(this); + + Realize(); + + var element = node as XmlElement; + if (element == null) + throw Error.CannotSetAttribute(this); + + var attribute = element.GetAttributeNode(name.LocalName, name.NamespaceUri); + if (attribute == null) + { + var prefix = Namespaces.GetAttributePrefix(this, name.NamespaceUri); + attribute = element.OwnerDocument.CreateAttribute(prefix, name.LocalName, name.NamespaceUri); + element.SetAttributeNode(attribute); + } + attribute.Value = value; + } + + private void ClearAttribute(XmlName name) + { + if (!IsReal) + return; + + var element = node as XmlElement; + if (element == null) + return; + + element.RemoveAttribute(name.LocalName, name.NamespaceUri); + return; + } + + public string LookupPrefix(string namespaceUri) + { + return node.GetPrefixOfNamespace(namespaceUri); + } + + public string LookupNamespaceUri(string prefix) + { + return node.GetNamespaceOfPrefix(prefix); + } + + public void DefineNamespace(string prefix, string namespaceUri, bool root) + { + var target = GetNamespaceTargetElement(); + if (target == null) + throw Error.InvalidOperation(); + + if (root) + target = target.FindRoot(); + + target.DefineNamespace(prefix, namespaceUri); + } + + private XmlElement GetNamespaceTargetElement() + { + var element = node as XmlElement; + if (element != null) + return element; + + var attribute = node as XmlAttribute; + if (attribute != null) + return attribute.OwnerElement; + + var document = node as XmlDocument; + if (document != null) + return document.DocumentElement; + + return null; + } + + public virtual IXmlNode Save() + { + return this; + } + + public IXmlCursor SelectSelf(Type clrType) + { + return new XmlSelfCursor(this, clrType); + } + + public IXmlCursor SelectChildren(IXmlKnownTypeMap knownTypes, IXmlNamespaceSource namespaces, CursorFlags flags) + { + return new SysXmlCursor(this, knownTypes, namespaces, flags); + } + + public IXmlIterator SelectSubtree() + { + return new SysXmlSubtreeIterator(this, Namespaces); + } + + public XmlReader ReadSubtree() + { + return node.CreateNavigator().ReadSubtree(); + } + + public XmlWriter WriteAttributes() + { + return node.CreateNavigator().CreateAttributes(); + } + + public XmlWriter WriteChildren() + { + return node.CreateNavigator().AppendChild(); + } + + public IXmlCursor Select(CompiledXPath path, IXmlIncludedTypeMap includedTypes, IXmlNamespaceSource namespaces, CursorFlags flags) + { + return flags.SupportsMutation() + ? (IXmlCursor) new XPathMutableCursor (this, path, includedTypes, namespaces, flags) + : (IXmlCursor) new XPathReadOnlyCursor(this, path, includedTypes, namespaces, flags); + } + + public virtual object Evaluate(CompiledXPath path) + { + return node.CreateNavigator().Evaluate(path.Path); + } + + public XmlNode GetNode() + { + return node; + } + + public void Clear() + { + if (IsElement) + { + ClearAttributes(); + } + else if (IsAttribute) + { + Value = string.Empty; + return; + } + ClearChildren(); + } + + private void ClearAttributes() + { + var attributes = node.Attributes; + var count = attributes.Count; + while (count > 0) + { + var attribute = attributes[--count]; + if (!attribute.IsNamespace() && !attribute.IsXsiType()) + attributes.RemoveAt(count); + } + } + + private void ClearChildren() + { + XmlNode next; + for (var child = node.FirstChild; child != null; child = next) + { + next = child.NextSibling; + node.RemoveChild(child); + } + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/SystemXml/SysXmlSubtreeIterator.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/SystemXml/SysXmlSubtreeIterator.cs new file mode 100644 index 0000000..c3191d4 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/SystemXml/SysXmlSubtreeIterator.cs @@ -0,0 +1,96 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + using System.Xml; + + public class SysXmlSubtreeIterator : SysXmlNode, IXmlIterator + { + private State state; + + public SysXmlSubtreeIterator(IXmlNode parent, IXmlNamespaceSource namespaces) + : base(namespaces, parent) + { + if (null == parent) + throw Error.ArgumentNull(nameof(parent)); + + var source = parent.RequireRealizable(); + if (source.IsReal) + node = source.Value; + + type = typeof(object); + } + + public bool MoveNext() + { + switch (state) + { + case State.Initial: return MoveToInitial(); + case State.Current: return MoveToSubsequent(); + default: return false; + } + } + + private bool MoveToInitial() + { + if (node == null) + return false; + + state = State.Current; + return true; + } + + private bool MoveToSubsequent() + { + if (MoveToElement(node.FirstChild)) + return true; + + for (; node != null; node = node.ParentNode) + if (MoveToElement(node.NextSibling)) + return true; + + state = State.End; + return false; + } + + private bool MoveToElement(XmlNode node) + { + for (; node != null; node = node.NextSibling) + if (node.NodeType == XmlNodeType.Element) + return SetNext(node); + + return false; + } + + private bool SetNext(XmlNode node) + { + this.node = node; + return true; + } + + public override IXmlNode Save() + { + return new SysXmlNode(node, type, Namespaces); + } + + private enum State + { + Initial, + Current, + End + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/CompiledXPath.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/CompiledXPath.cs new file mode 100644 index 0000000..8ffc697 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/CompiledXPath.cs @@ -0,0 +1,88 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System.Xml.XPath; + using System.Xml.Xsl; + + public class CompiledXPath + { + private XPathExpression path; + private CompiledXPathStep firstStep; + private int depth; + + internal CompiledXPath() { } + + public XPathExpression Path + { + get { return path; } + internal set { path = value; } + } + + public CompiledXPathStep FirstStep + { + get { return firstStep; } + internal set { firstStep = value; } + } + + public CompiledXPathStep LastStep + { + get + { + var step = null as CompiledXPathStep; + var next = firstStep; + + while (next != null) + { + step = next; + next = step.NextStep; + } + + return step; + } + } + + public int Depth + { + get { return depth; } + internal set { depth = value; } + } + + public bool IsCreatable + { + get { return firstStep != null; } + } + + internal void MakeNotCreatable() + { + firstStep = null; + depth = 0; + } + + internal void Prepare() + { + if (firstStep != null) + firstStep.Prepare(); + } + + public void SetContext(XsltContext context) + { + path.SetContext(context); + + if (firstStep != null) + firstStep.SetContext(context); + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/CompiledXPathNode.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/CompiledXPathNode.cs new file mode 100644 index 0000000..a5a4748 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/CompiledXPathNode.cs @@ -0,0 +1,136 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Xml.XPath; + using System.Xml.Xsl; + + public class CompiledXPathNode + { + private string prefix; + private string localName; + private bool isAttribute; + private XPathExpression value; + private CompiledXPathNode next; + private CompiledXPathNode previous; + private IList dependencies; + + internal CompiledXPathNode() { } + + public string Prefix + { + get { return prefix; } + internal set { prefix = value; } + } + + public string LocalName + { + get { return localName; } + internal set { localName = value; } + } + + public bool IsAttribute + { + get { return isAttribute; } + internal set { isAttribute = value; } + } + + public bool IsSelfReference + { + get { return localName == null; } + } + + public bool IsSimple + { + get { return next == null && HasNoRealDependencies(); } + } + + public XPathExpression Value + { + get { return value ?? GetSelfReferenceValue(); } + internal set { this.value = value; } + } + + public CompiledXPathNode NextNode + { + get { return next; } + internal set { next = value; } + } + + public CompiledXPathNode PreviousNode + { + get { return previous; } + internal set { previous = value; } + } + + public IList Dependencies + { + get { return dependencies ?? (dependencies = new List()); } + } + + private static readonly IList + NoDependencies = Array.AsReadOnly(new CompiledXPathNode[0]); + + private bool HasNoRealDependencies() + { + return + ( + dependencies == null || + dependencies.Count == 0 || + ( + dependencies.Count == 1 && + dependencies[0].IsSelfReference + ) + ); + } + + private XPathExpression GetSelfReferenceValue() + { + return dependencies != null + && dependencies.Count == 1 + && dependencies[0].IsSelfReference + ? dependencies[0].value + : null; + } + + internal virtual void Prepare() + { + dependencies = (dependencies != null) + ? Array.AsReadOnly(dependencies.ToArray()) + : NoDependencies; + + foreach (var child in dependencies) + child.Prepare(); + + if (next != null) + next.Prepare(); + } + + internal virtual void SetContext(XsltContext context) + { + if (value != null) + value.SetContext(context); + + foreach (var child in dependencies) + child.SetContext(context); + + if (next != null) + next.SetContext(context); + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/CompiledXPathStep.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/CompiledXPathStep.cs new file mode 100644 index 0000000..2fffe13 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/CompiledXPathStep.cs @@ -0,0 +1,44 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + using System.Xml.XPath; + using System.Xml.Xsl; + + public class CompiledXPathStep : CompiledXPathNode + { + private XPathExpression path; + + internal CompiledXPathStep() { } + + public XPathExpression Path + { + get { return path; } + internal set { path = value; } + } + + public CompiledXPathStep NextStep + { + get { return (CompiledXPathStep) NextNode; } + } + + internal override void SetContext(XsltContext context) + { + path.SetContext(context); + base.SetContext(context); + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/XPathBufferedNodeIterator.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/XPathBufferedNodeIterator.cs new file mode 100644 index 0000000..d310569 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/XPathBufferedNodeIterator.cs @@ -0,0 +1,83 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + using System.Collections.Generic; + using System.Xml.XPath; + + internal class XPathBufferedNodeIterator : XPathNodeIterator + { + private readonly IList items; + private int index; + + public XPathBufferedNodeIterator(XPathNodeIterator iterator) + { + items = new List(); + do items.Add(iterator.Current.Clone()); + while (iterator.MoveNext()); + } + + private XPathBufferedNodeIterator(XPathBufferedNodeIterator iterator) + { + items = iterator.items; + index = iterator.index; + } + + public override int CurrentPosition + { + get { return index; } + } + + public override int Count + { + get { return items.Count - 1; } + } + + public bool IsEmpty + { + get { return items.Count == 1; } + } + + public override XPathNavigator Current + { + get { return items[index]; } + } + + public void Reset() + { + index = 0; + } + + public override bool MoveNext() + { + if (++index < items.Count) + return true; + if (index > items.Count) + index--; + return false; + } + + public void MoveToEnd() + { + index = items.Count; + } + + public override XPathNodeIterator Clone() + { + return new XPathBufferedNodeIterator(this); + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/XPathCompiler.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/XPathCompiler.cs new file mode 100644 index 0000000..8a88dc4 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/XPathCompiler.cs @@ -0,0 +1,452 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + using System.Xml; + using System.Xml.XPath; + + public static class XPathCompiler + { + public static CompiledXPath Compile(string path) + { + if (null == path) + throw Error.ArgumentNull(nameof(path)); + + // Compile whole path to catch errors + var result = new CompiledXPath(); + result.Path = XPathExpression.Compile(path); + + // Try to split into individual path steps + var tokenizer = new Tokenizer(path); + if (!ParsePath(tokenizer, result)) + result.MakeNotCreatable(); + + // Finish compilation + result.Prepare(); + return result; + } + + private static bool ParsePath(Tokenizer source, CompiledXPath path) + { + for (CompiledXPathStep step = null;;) + { + if (!ParseStep(source, path, ref step)) + return false; + if (source.Token == Token.EndOfInput) + return true; + if (!Consume(source, Token.StepSeparator)) + return false; + if (step.IsAttribute) + return false; + } + } + + private static bool ParseStep(Tokenizer source, CompiledXPath path, ref CompiledXPathStep step) + { + var previous = step; + var start = source.Index; + + if (!ParseNodeCore(source, StepFactory, ref step)) + return false; + + if (step != previous) + { + var text = source.GetConsumedText(start); + step.Path = XPathExpression.Compile(text); + + if (previous == null) + path.FirstStep = step; + else + LinkNodes(previous, step); + + path.Depth++; + } + return true; + } + + private static bool ParseNodeCore(Tokenizer source, Func factory, ref TNode node) + where TNode : CompiledXPathNode + { + if (!Consume(source, Token.SelfReference)) + { + node = factory(); + + if (Consume(source, Token.AttributeStart)) + node.IsAttribute = true; + + if (!ParseQualifiedName(source, node)) + return false; + } + + return node == null + ? source.Token != Token.PredicateStart + : ParsePredicateList(source, node); + } + + private static bool ParsePredicateList(Tokenizer source, CompiledXPathNode parent) + { + while (Consume(source, Token.PredicateStart)) + if (!ParsePredicate(source, parent)) + return false; + + return true; + } + + private static bool ParsePredicate(Tokenizer source, CompiledXPathNode parent) + { + // Don't need to check this; caller must have already checked it. + //if (!Consume(source, Token.PredicateStart)) + // return false; + + if (!ParseAndExpression(source, parent)) + return false; + + if (!Consume(source, Token.PredicateEnd)) + return false; + + return true; + } + + private static bool ParseAndExpression(Tokenizer source, CompiledXPathNode parent) + { + for (;;) + { + if (!ParseExpression(source, parent)) + return false; + + if (source.Token != Token.Name || source.Text != "and") + return true; + source.Consume(); + } + } + + private static bool ParseExpression(Tokenizer source, CompiledXPathNode parent) + { + var isLeftToRight + = source.Token == Token.Name + || source.Token == Token.AttributeStart + || source.Token == Token.SelfReference; + + return (isLeftToRight) + ? ParseLeftToRightExpression(source, parent) + : ParseRightToLeftExpression(source, parent); + } + + private static bool ParseLeftToRightExpression(Tokenizer source, CompiledXPathNode parent) + { + CompiledXPathNode node; + if (!ParseNestedPath(source, parent, out node)) + return false; + + if (!Consume(source, Token.EqualsOperator)) + return true; + + XPathExpression value; + if (!ParseValue(source, out value)) + return false; + + node.Value = value; + return true; + } + + private static bool ParseRightToLeftExpression(Tokenizer source, CompiledXPathNode parent) + { + XPathExpression value; + if (!ParseValue(source, out value)) + return false; + + if (!Consume(source, Token.EqualsOperator)) + return false; + + CompiledXPathNode node; + if (!ParseNestedPath(source, parent, out node)) + return false; + + node.Value = value; + return true; + } + + private static bool ParseNestedPath(Tokenizer source, CompiledXPathNode parent, out CompiledXPathNode node) + { + for (node = null;;) + { + if (!ParseNode(source, parent, ref node)) + return false; + if (!Consume(source, Token.StepSeparator)) + break; + if (node.IsAttribute) + return false; + } + + if (node == null) + { + var dependencies = parent.Dependencies; + if (dependencies.Count != 0) + return false; + dependencies.Add(node = NodeFactory()); // Self-reference + } + return true; + } + + private static bool ParseNode(Tokenizer source, CompiledXPathNode parent, ref CompiledXPathNode node) + { + var previous = node; + + if (!ParseNodeCore(source, NodeFactory, ref node)) + return false; + + if (node != previous) + { + if (previous == null) + parent.Dependencies.Add(node); + else + LinkNodes(previous, node); + } + return true; + } + + private static bool ParseValue(Tokenizer source, out XPathExpression value) + { + var start = source.Index; + + var parsed = + Consume(source, Token.StringLiteral) || + ( + Consume(source, Token.VariableStart) && + ParseQualifiedName(source, null) + ); + if (!parsed) + return Try.Failure(out value); + + var xpath = source.GetConsumedText(start); + value = XPathExpression.Compile(xpath); + return true; + } + + private static bool ParseQualifiedName(Tokenizer source, CompiledXPathNode node) + { + string nameA, nameB; + + if (!ParseName(source, out nameA)) + return false; + + if (!Consume(source, Token.NameSeparator)) + { + if (node != null) + node.LocalName = nameA; + return true; + } + + if (!ParseName(source, out nameB)) + return false; + + if (node != null) + { + node.Prefix = nameA; + node.LocalName = nameB; + } + return true; + } + + private static bool ParseName(Tokenizer source, out string name) + { + if (source.Token != Token.Name) + return Try.Failure(out name); + name = source.Text; + source.Consume(); + return true; + } + + private static bool Consume(Tokenizer source, Token token) + { + if (source.Token != token) + return false; + source.Consume(); + return true; + } + + private static void LinkNodes(CompiledXPathNode previous, CompiledXPathNode next) + { + previous.NextNode = next; + next.PreviousNode = previous; + } + + private static readonly Func + NodeFactory = () => new CompiledXPathNode(); + + private static readonly Func + StepFactory = () => new CompiledXPathStep(); + + private enum Token + { + Name, + SelfReference, + + StepSeparator, + NameSeparator, + AttributeStart, + VariableStart, + EqualsOperator, + + PredicateStart, + PredicateEnd, + + StringLiteral, + + EndOfInput, + Error + } + + private class Tokenizer + { + private readonly string input; + + private State state; + private Token token; + private int index; + private int start; + private int prior; + + public Tokenizer(string input) + { + this.input = input; + this.state = State.Initial; + this.index = -1; + Consume(); + } + + // Type of the current token + public Token Token + { + get { return token; } + } + + // Text of the current token + public string Text + { + get { return input.Substring(start, index - start + 1); } + } + + // Gets text that has been consumed previously + public string GetConsumedText(int start) + { + return input.Substring(start, prior - start + 1); + } + + // Index where current token starts + public int Index + { + get { return start; } + } + + // Consider the current token consumed, and read next token + public void Consume() + { + prior = index; + + for(;;) + { + var c = ReadChar(); + + switch (state) + { + case State.Initial: + start = index; + switch (c) + { + case '.': token = Token.SelfReference; return; + case '/': token = Token.StepSeparator; return; + case ':': token = Token.NameSeparator; return; + case '@': token = Token.AttributeStart; return; + case '$': token = Token.VariableStart; return; + case '=': token = Token.EqualsOperator; return; + case '[': token = Token.PredicateStart; return; + case ']': token = Token.PredicateEnd; return; + case '\0': token = Token.EndOfInput; return; + case '\'': state = State.SingleQuoteString; break; + case '\"': state = State.DoubleQuoteString; break; + default: + if (IsNameStartChar(c)) { state = State.Name; } + else if (IsWhitespace(c)) { /* Ignore */ } + else { state = State.Failed; } + break; + } + break; + + case State.Name: + if (IsNameChar(c)) { break; } + RewindChar(); + token = Token.Name; + state = State.Initial; + return; + + case State.SingleQuoteString: + if (c != '\'') { break; } + token = Token.StringLiteral; + state = State.Initial; + return; + + case State.DoubleQuoteString: + if (c != '\"') { break; } + token = Token.StringLiteral; + state = State.Initial; + return; + + case State.Failed: + token = Token.Error; + return; + } + } + } + + private char ReadChar() + { + return (++index < input.Length) + ? input[index] + : default(char); // EOF sentinel + } + + private void RewindChar() + { + --index; + } + + private static bool IsWhitespace(char c) + { + return XmlConvert.IsWhitespaceChar(c); + } + + private static bool IsNameStartChar(char c) + { + return XmlConvert.IsStartNCNameChar(c); + } + + private static bool IsNameChar(char c) + { + return XmlConvert.IsNCNameChar(c); + } + + private enum State + { + Initial = 0, + Name, + SingleQuoteString, + DoubleQuoteString, + Failed + } + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/XPathContext.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/XPathContext.cs new file mode 100644 index 0000000..925b216 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/XPathContext.cs @@ -0,0 +1,68 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System.Xml.XPath; + using System.Xml.Xsl; + + internal class XPathContext : XsltContext + { + private readonly XsltContext context; + + public XPathContext(XsltContext xpathContext) + { + this.context = xpathContext; + } + + public override string DefaultNamespace + { + // Must be empty, or XPath evaluation will break + get { return string.Empty; } + } + + public override string LookupNamespace(string prefix) + { + // Must return empty uri for empty prefix, or XPath evaluation will break + return string.IsNullOrEmpty(prefix) + ? string.Empty + : context.LookupNamespace(prefix); + } + + public override bool Whitespace + { + get { return context.Whitespace; } + } + + public override bool PreserveWhitespace(XPathNavigator node) + { + return context.PreserveWhitespace(node); + } + + public override int CompareDocument(string baseUri, string nextbaseUri) + { + return context.CompareDocument(baseUri, nextbaseUri); + } + + public override IXsltContextFunction ResolveFunction(string prefix, string name, XPathResultType[] argTypes) + { + return context.ResolveFunction(prefix, name, argTypes); + } + + public override IXsltContextVariable ResolveVariable(string prefix, string name) + { + return context.ResolveVariable(prefix, name); + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/XPathExtensions.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/XPathExtensions.cs new file mode 100644 index 0000000..18a24a4 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/XPathExtensions.cs @@ -0,0 +1,76 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + using System.Xml; + using System.Xml.XPath; + + public static class XPathExtensions + { + public static XPathNavigator CreateNavigatorSafe(this IXPathNavigable source) + { + if (source == null) + throw Error.ArgumentNull(nameof(source)); + return source.CreateNavigator(); + } + + public static bool MoveToLastChild(this XPathNavigator navigator) + { + if (!navigator.MoveToFirstChild()) + return false; + + while (navigator.MoveToNext()) { } + + return true; + } + + public static bool MoveToLastAttribute(this XPathNavigator navigator) + { + if (!navigator.MoveToFirstAttribute()) + return false; + + while (navigator.MoveToNextAttribute()) { } + + return true; + } + + public static XPathNavigator GetRootElement(this XPathNavigator navigator) + { + navigator = navigator.Clone(); + navigator.MoveToRoot(); + if (navigator.NodeType == XPathNodeType.Root) + if (!navigator.MoveToFirstChild()) + throw Error.InvalidOperation(); + return navigator; + } + + public static XPathNavigator GetParent(this XPathNavigator navigator) + { + navigator = navigator.Clone(); + if (!navigator.MoveToParent()) + throw Error.InvalidOperation(); + return navigator; + } + + public static void DeleteChildren(this XPathNavigator node) + { + while (node.MoveToFirstChild()) + node.DeleteSelf(); + while (node.MoveToFirstAttribute()) + node.DeleteSelf(); + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/XPathMutableCursor.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/XPathMutableCursor.cs new file mode 100644 index 0000000..6d5e41f --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/XPathMutableCursor.cs @@ -0,0 +1,415 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + using System.Xml; + using System.Xml.XPath; + + internal class XPathMutableCursor : XPathNode, IXmlCursor + { + private XPathBufferedNodeIterator iterator; + private CompiledXPathStep step; + private int depth; + + private readonly IXmlIncludedTypeMap knownTypes; + private readonly CursorFlags flags; + + public XPathMutableCursor(IXmlNode parent, CompiledXPath path, + IXmlIncludedTypeMap knownTypes, IXmlNamespaceSource namespaces, CursorFlags flags) + : base(path, namespaces, parent) + { + if (null == parent) + throw Error.ArgumentNull(nameof(parent)); + if (null == path) + throw Error.ArgumentNull(nameof(path)); + if (null == knownTypes) + throw Error.ArgumentNull(nameof(knownTypes)); + if (!path.IsCreatable) + throw Error.XPathNotCreatable(path); + + this.step = path.FirstStep; + this.knownTypes = knownTypes; + this.flags = flags; + + var source = parent.RequireRealizable(); + if (source.IsReal) + iterator = new XPathBufferedNodeIterator( + source.Value.Select(path.FirstStep.Path)); + } + + public override bool IsReal + { + get { return HasCurrent; } + } + + public bool HasCurrent + { + get { return depth == xpath.Depth; } + } + + public bool HasPartialOrCurrent + { + get { return null != node; } // (_depth > 0 works also) + } + + public override Type ClrType + { + get { return HasCurrent ? base.ClrType : knownTypes.Default.ClrType; } + } + + public override XmlName Name + { + get { return HasCurrent ? base.Name : XmlName.Empty; } + } + + public override XmlName XsiType + { + get { return HasCurrent ? base.XsiType : knownTypes.Default.XsiType; } + } + + public override bool IsElement + { + get { return HasCurrent ? base.IsElement : flags.IncludesElements(); } + } + + public override bool IsAttribute + { + get { return HasCurrent ? base.IsAttribute : !flags.IncludesElements(); } + } + + public override bool IsNil + { + get { return HasCurrent && base.IsNil; } + set { Realize(); base.IsNil = value; } + } + + public override string Value + { + get { return HasCurrent ? base.Value : string.Empty; } + set { base.Value = value; } // base sets IsNil, so no need to call Realize() here + } + + public override string Xml + { + get { return HasCurrent ? base.Xml : null; } + } + + public override object Evaluate(CompiledXPath path) + { + return HasCurrent ? base.Evaluate(path) : null; + } + + public bool MoveNext() + { + ResetCurrent(); + + for (;;) + { + var hasNext + = iterator != null + && iterator.MoveNext() + && Consume(iterator, flags.AllowsMultipleItems()); + + if (!hasNext) + return SetAtEnd(); + if (SeekCurrent()) + return true; + } + } + + private bool SeekCurrent() + { + while (depth < xpath.Depth) + { + var iterator = node.Select(step.Path); + if (!iterator.MoveNext()) + return true; // Sought as far as possible + if (!Consume(iterator, false)) + return false; // Problem: found multiple nodes + } + + IXmlIncludedType includedType; + if (!knownTypes.TryGet(XsiType, out includedType)) + return false; // Problem: unrecognized xsi:type + + type = includedType.ClrType; + return true; // Sought all the way + } + + private bool Consume(XPathNodeIterator iterator, bool multiple) + { + var candidate = iterator.Current; + if (!multiple && iterator.MoveNext()) + return false; + + node = candidate; + Descend(); + return true; + } + + private bool SetAtEnd() + { + ResetCurrent(); + return false; + } + + public void Reset() + { + ResetCurrent(); + iterator.Reset(); + } + + public void MoveToEnd() + { + ResetCurrent(); + iterator.MoveToEnd(); + } + + private void ResetCurrent() + { + node = null; + type = null; + ResetDepth(); + } + + private void ResetDepth() + { + step = xpath.FirstStep; + depth = 0; + } + + private int Descend() + { + step = step.NextStep; + return ++depth; + } + + public void MoveTo(IXmlNode position) + { + var source = position.AsRealizable(); + if (source == null || !source.IsReal) + throw Error.CursorCannotMoveToGivenNode(); + + var positionNode = source.Value; + + Reset(); + while (MoveNext()) + if (HasCurrent && node.IsSamePosition(positionNode)) + return; + + throw Error.CursorCannotMoveToGivenNode(); + } + + public override event EventHandler Realized; + protected virtual void OnRealized() + { + if (Realized != null) + Realized(this, EventArgs.Empty); + } + + protected override void Realize() + { + if (HasCurrent) + return; + if (!(iterator == null || iterator.IsEmpty || HasPartialOrCurrent)) + throw Error.CursorNotInRealizableState(); + Create(knownTypes.Default.ClrType); + OnRealized(); + } + + public void MakeNext(Type clrType) + { + if (MoveNext()) + Coerce(clrType); + else + Create(clrType); + } + + public void Coerce(Type clrType) + { + var includedType = knownTypes.Require(clrType); + this.SetXsiType(includedType.XsiType); + this.type = clrType; + } + + public void Create(Type type) + { + if (HasCurrent) + Insert(); + else if (HasPartialOrCurrent) + Complete(); + else + Append(); + + Coerce(type); + } + + private void Insert() + { + while (--depth > 0) + node.MoveToParent(); + ResetDepth(); + + using (var writer = node.InsertBefore()) + WriteNode(step, writer); + + var moved = node.MoveToPrevious(); + SeekCurrentAfterCreate(moved); + } + + private void Append() + { + node = Parent.AsRealizable().Value.Clone(); + Parent.IsNil = false; + Complete(); + } + + private void Complete() + { + using (var writer = CreateWriterForAppend()) + WriteNode(step, writer); + + var moved = step.IsAttribute + ? node.MoveToLastAttribute() + : node.MoveToLastChild(); + SeekCurrentAfterCreate(moved); + } + + private XmlWriter CreateWriterForAppend() + { + return step.IsAttribute + ? node.CreateAttributes() + : node.AppendChild(); + } + + private void WriteNode(CompiledXPathNode node, XmlWriter writer) + { + if (node.IsAttribute) + WriteAttribute(node, writer); + else if (node.IsSimple) + WriteSimpleElement(node, writer); + else + WriteComplexElement(node, writer); + } + + private void WriteAttribute(CompiledXPathNode node, XmlWriter writer) + { + writer.WriteStartAttribute(node.Prefix, node.LocalName, null); + WriteValue(node, writer); + writer.WriteEndAttribute(); + } + + private void WriteSimpleElement(CompiledXPathNode node, XmlWriter writer) + { + writer.WriteStartElement(node.Prefix, node.LocalName, null); + WriteValue(node, writer); + writer.WriteEndElement(); + } + + private void WriteComplexElement(CompiledXPathNode node, XmlWriter writer) + { + writer.WriteStartElement(node.Prefix, node.LocalName, null); + WriteSubnodes(node, writer, true); + WriteSubnodes(node, writer, false); + writer.WriteEndElement(); + } + + private void WriteSubnodes(CompiledXPathNode parent, XmlWriter writer, bool attributes) + { + var next = parent.NextNode; + if (next != null && next.IsAttribute == attributes) + WriteNode(next, writer); + + foreach (var node in parent.Dependencies) + if (node.IsAttribute == attributes) + WriteNode(node, writer); + } + + private void WriteValue(CompiledXPathNode node, XmlWriter writer) + { + if (node.Value == null) + return; + + var value = Parent.AsRealizable().Value.Evaluate(node.Value); + writer.WriteValue(value); + } + + private void SeekCurrentAfterCreate(bool moved) + { + RequireMoved(moved); + if (Descend() == xpath.Depth) + return; + + do + { + moved = step.IsAttribute + ? node.MoveToFirstAttribute() + : node.MoveToFirstChild(); + RequireMoved(moved); + } + while (Descend() < xpath.Depth); + } + + public void RemoveAllNext() + { + while (MoveNext()) + Remove(); + } + + public void Remove() + { + RequireRemovable(); + + var name = XmlName.Empty; + + if (!HasCurrent) + { + var namespaceUri = LookupNamespaceUri(step.Prefix) ?? node.NamespaceURI; + name = new XmlName(step.LocalName, namespaceUri); + } + + do + { + if (node.MoveToChild(name.LocalName, name.NamespaceUri)) + break; + + name = new XmlName(node.LocalName, node.NamespaceURI); + node.DeleteSelf(); + depth--; + } + while (depth > 0); + + ResetCurrent(); + } + + public override IXmlNode Save() + { + return HasCurrent ? new XPathNode(node.Clone(), type, Namespaces) : this; + } + + private void RequireRemovable() + { + if (!HasPartialOrCurrent) + throw Error.CursorNotInRemovableState(); + } + + private void RequireMoved(bool result) + { + if (!result) + throw Error.XPathNavigationFailed(step.Path); + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/XPathNode.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/XPathNode.cs new file mode 100644 index 0000000..ea40616 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/XPathNode.cs @@ -0,0 +1,233 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + using System.Xml; + using System.Xml.XPath; + + public class XPathNode : XmlNodeBase, IXmlNode, IRealizable + , IRealizable + { + protected XPathNavigator node; + protected readonly CompiledXPath xpath; + + protected XPathNode(CompiledXPath path, IXmlNamespaceSource namespaces, IXmlNode parent) + : base(namespaces, parent) + { + this.xpath = path; + } + + public XPathNode(XPathNavigator node, Type type, IXmlNamespaceSource namespaces) + : this(null, namespaces, null) + { + if (node == null) + throw Error.ArgumentNull(nameof(node)); + if (type == null) + throw Error.ArgumentNull(nameof(type)); + + this.node = node; + this.type = type; + } + + public object UnderlyingObject + { + get { return node; } + } + + XPathNavigator IRealizable.Value + { + get { Realize(); return node; } + } + + XmlNode IRealizable.Value + { + get { Realize(); return (XmlNode) node.UnderlyingObject; } + } + + public override CompiledXPath Path + { + get { return xpath; } + } + + public virtual XmlName Name + { + get { return new XmlName(node.LocalName, node.NamespaceURI); } + } + + public virtual XmlName XsiType + { + get { return this.GetXsiType(); } + } + + public virtual bool IsElement + { + get { return node.NodeType == XPathNodeType.Element; } + } + + public virtual bool IsAttribute + { + get { return node.NodeType == XPathNodeType.Attribute; } + } + + public virtual bool IsNil + { + get { return this.IsXsiNil(); } + set { this.SetXsiNil(value); } + } + + public virtual string Value + { + get { return node.Value; } + set { var nil = (value == null); IsNil = nil; if (!nil) node.SetValue(value); } + } + + public virtual string Xml + { + get { return node.OuterXml; } + } + + public string GetAttribute(XmlName name) + { + if (!IsReal || !node.MoveToAttribute(name.LocalName, name.NamespaceUri)) + return null; + + var value = node.Value; + node.MoveToParent(); + return string.IsNullOrEmpty(value) ? null : value; + } + + public void SetAttribute(XmlName name, string value) + { + if (string.IsNullOrEmpty(value)) + ClearAttribute(name); + else + SetAttributeCore(name, value); + } + + private void SetAttributeCore(XmlName name, string value) + { + if (!IsElement) + throw Error.CannotSetAttribute(this); + + Realize(); + + if (node.MoveToAttribute(name.LocalName, name.NamespaceUri)) + { + node.SetValue(value); + node.MoveToParent(); + } + else + { + var prefix = Namespaces.GetAttributePrefix(this, name.NamespaceUri); + node.CreateAttribute(prefix, name.LocalName, name.NamespaceUri, value); + } + } + + private void ClearAttribute(XmlName name) + { + if (IsReal && node.MoveToAttribute(name.LocalName, name.NamespaceUri)) + node.DeleteSelf(); + } + + public string LookupPrefix(string namespaceUri) + { + return node.LookupPrefix(namespaceUri); + } + + public string LookupNamespaceUri(string prefix) + { + return node.LookupNamespace(prefix); + } + + public void DefineNamespace(string prefix, string namespaceUri, bool root) + { + var target + = root ? node.GetRootElement() + : IsElement ? node + : IsAttribute ? node.GetParent() + : node.GetRootElement(); + + target.CreateAttribute(Xmlns.Prefix, prefix, Xmlns.NamespaceUri, namespaceUri); + } + + public bool UnderlyingPositionEquals(IXmlNode node) + { + var sysXmlNode = node.AsRealizable(); + if (sysXmlNode != null) + return sysXmlNode.IsReal + && sysXmlNode.Value == this.node.UnderlyingObject; + + var xPathNode = node.AsRealizable(); + if (xPathNode != null) + return xPathNode.IsReal + && xPathNode.Value.IsSamePosition(this.node); + + return false; + } + + public virtual IXmlNode Save() + { + return this; + } + + public IXmlCursor SelectSelf(Type clrType) + { + return new XmlSelfCursor(this, clrType); + } + + public IXmlCursor SelectChildren(IXmlKnownTypeMap knownTypes, IXmlNamespaceSource namespaces, CursorFlags flags) + { + return new SysXmlCursor(this, knownTypes, namespaces, flags); + } + + public IXmlIterator SelectSubtree() + { + return new SysXmlSubtreeIterator(this, Namespaces); + } + + public IXmlCursor Select(CompiledXPath path, IXmlIncludedTypeMap includedTypes, IXmlNamespaceSource namespaces, CursorFlags flags) + { + return flags.SupportsMutation() + ? (IXmlCursor) new XPathMutableCursor (this, path, includedTypes, namespaces, flags) + : (IXmlCursor) new XPathReadOnlyCursor(this, path, includedTypes, namespaces, flags); + } + + public virtual object Evaluate(CompiledXPath path) + { + return node.Evaluate(path.Path); + } + + public virtual XmlReader ReadSubtree() + { + return node.ReadSubtree(); + } + + public virtual XmlWriter WriteAttributes() + { + return node.CreateAttributes(); + } + + public virtual XmlWriter WriteChildren() + { + return node.AppendChild(); + } + + public virtual void Clear() + { + node.DeleteChildren(); + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/XPathReadOnlyCursor.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/XPathReadOnlyCursor.cs new file mode 100644 index 0000000..cc2fc64 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/XPathReadOnlyCursor.cs @@ -0,0 +1,140 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + using System.Xml.XPath; + + public class XPathReadOnlyCursor : XPathNode, IXmlCursor + { + private XPathNodeIterator iterator; + private readonly IXmlIncludedTypeMap includedTypes; + private readonly CursorFlags flags; + + public XPathReadOnlyCursor(IXmlNode parent, CompiledXPath path, + IXmlIncludedTypeMap includedTypes, IXmlNamespaceSource namespaces, CursorFlags flags) + : base(path, namespaces, parent) + { + if (parent == null) + throw Error.ArgumentNull(nameof(parent)); + if (path == null) + throw Error.ArgumentNull(nameof(path)); + if (includedTypes == null) + throw Error.ArgumentNull(nameof(includedTypes)); + + this.includedTypes = includedTypes; + this.flags = flags; + + Reset(); + } + + public void Reset() + { + var source = Parent.RequireRealizable(); + if (source.IsReal) + iterator = source.Value.Select(xpath.Path); + } + + public bool MoveNext() + { + for (;;) + { + var hasNext + = iterator != null + && iterator.MoveNext() + && (flags.AllowsMultipleItems() || !iterator.MoveNext()); + + if (!hasNext) + return SetAtEnd(); + if (SetAtNext()) + return true; + } + } + + private bool SetAtEnd() + { + node = null; + type = null; + return false; + } + + private bool SetAtNext() + { + node = iterator.Current; + + IXmlIncludedType includedType; + if (!includedTypes.TryGet(XsiType, out includedType)) + return false; + + type = includedType.ClrType; + return true; + } + + public void MoveTo(IXmlNode position) + { + var source = position.AsRealizable(); + if (source == null || !source.IsReal) + throw Error.CursorCannotMoveToGivenNode(); + + var positionNode = source.Value; + + Reset(); + + if (iterator != null) + while (iterator.MoveNext()) + if (iterator.Current.IsSamePosition(positionNode)) + { SetAtNext(); return; } + + throw Error.CursorCannotMoveToGivenNode(); + } + + public void MoveToEnd() + { + if (iterator != null) + while (iterator.MoveNext()) ; + SetAtEnd(); + } + + public void MakeNext(Type type) + { + throw Error.CursorNotMutable(); + } + + public void Create(Type type) + { + throw Error.CursorNotMutable(); + } + + public void Coerce(Type type) + { + throw Error.CursorNotMutable(); + } + + public void Remove() + { + throw Error.CursorNotMutable(); + } + + public void RemoveAllNext() + { + throw Error.CursorNotMutable(); + } + + public override IXmlNode Save() + { + return new XPathNode(node.Clone(), type, Namespaces); + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Namespaces/Wsdl.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Namespaces/Wsdl.cs new file mode 100644 index 0000000..e68ec85 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Namespaces/Wsdl.cs @@ -0,0 +1,27 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + // Namespace for Guid type + public static class Wsdl + { + public const string + Prefix = "wsdl", + NamespaceUri = "http://microsoft.com/wsdl/types/"; + + internal static readonly XmlNamespaceAttribute + Namespace = new XmlNamespaceAttribute(NamespaceUri, Prefix) { Root = true }; + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Namespaces/XRef.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Namespaces/XRef.cs new file mode 100644 index 0000000..c6540ac --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Namespaces/XRef.cs @@ -0,0 +1,53 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + using System.Collections.Generic; + + public static class XRef + { + public static string GetId(this IXmlNode node) + { + return node.GetAttribute(XRef.Id); + } + + public static void SetId(this IXmlCursor node, string id) + { + node.SetAttribute(XRef.Id, id); + } + + public static string GetReference(this IXmlNode node) + { + return node.GetAttribute(XRef.Ref); + } + + public static void SetReference(this IXmlCursor cursor, string id) + { + cursor.SetAttribute(XRef.Ref, id); + } + + public const string + Prefix = "x", + NamespaceUri = "urn:schemas-castle-org:xml-reference"; + + public static readonly XmlName + Id = new XmlName("id", NamespaceUri), + Ref = new XmlName("ref", NamespaceUri); + + internal static readonly XmlNamespaceAttribute + Namespace = new XmlNamespaceAttribute(NamespaceUri, Prefix) { Root = true }; + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Namespaces/Xmlns.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Namespaces/Xmlns.cs new file mode 100644 index 0000000..bbfeb89 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Namespaces/Xmlns.cs @@ -0,0 +1,23 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + public static class Xmlns + { + public const string + Prefix = "xmlns", + NamespaceUri = "http://www.w3.org/2000/xmlns/"; + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Namespaces/Xsd.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Namespaces/Xsd.cs new file mode 100644 index 0000000..d27ed04 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Namespaces/Xsd.cs @@ -0,0 +1,26 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + public static class Xsd + { + public const string + Prefix = "xsd", + NamespaceUri = "http://www.w3.org/2001/XMLSchema"; + + internal static readonly XmlNamespaceAttribute + Namespace = new XmlNamespaceAttribute(NamespaceUri, Prefix) { Root = true }; + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Namespaces/Xsi.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Namespaces/Xsi.cs new file mode 100644 index 0000000..de1c05e --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Namespaces/Xsi.cs @@ -0,0 +1,75 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + + public static class Xsi + { + public static XmlName GetXsiType(this IXmlNode node) + { + var type = node.GetAttribute(Xsi.Type); + if (type == null) + return XmlName.Empty; + + var xsiType = XmlName.ParseQName(type); + if (xsiType.NamespaceUri != null) + { + var namespaceUri = node.LookupNamespaceUri(xsiType.NamespaceUri); + xsiType = xsiType.WithNamespaceUri(namespaceUri); + } + return xsiType; + } + + public static void SetXsiType(this IXmlNode node, XmlName xsiType) + { + if (xsiType.NamespaceUri != null) + { + var prefix = node.Namespaces.GetAttributePrefix(node, xsiType.NamespaceUri); + xsiType = xsiType.WithNamespaceUri(prefix); + } + node.SetAttribute(Xsi.Type, xsiType.ToString()); + } + + public static bool IsXsiNil(this IXmlNode node) + { + return node.GetAttribute(Xsi.Nil) == NilValue; + } + + public static void SetXsiNil(this IXmlNode node, bool nil) + { + string value; + if (nil) + { + node.Clear(); + value = NilValue; + } + else value = null; + node.SetAttribute(Xsi.Nil, value); + } + + public const string + Prefix = "xsi", + NamespaceUri = "http://www.w3.org/2001/XMLSchema-instance", + NilValue = "true"; + + public static readonly XmlName + Type = new XmlName("type", NamespaceUri), + Nil = new XmlName("nil", NamespaceUri); + + internal static readonly XmlNamespaceAttribute + Namespace = new XmlNamespaceAttribute(NamespaceUri, Prefix) { Root = true }; + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlArraySerializer.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlArraySerializer.cs new file mode 100644 index 0000000..89028d5 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlArraySerializer.cs @@ -0,0 +1,102 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + using System.Collections; + using System.Collections.Generic; + + public class XmlArraySerializer : XmlTypeSerializer + { + public static readonly XmlArraySerializer + Instance = new XmlArraySerializer(); + + protected XmlArraySerializer() { } + + public override XmlTypeKind Kind + { + get { return XmlTypeKind.Collection; } + } + + public override bool CanGetStub + { + get { return true; } + } + + public override object GetStub(IXmlNode node, IDictionaryAdapter parent, IXmlAccessor accessor) + { + var itemType = node.ClrType.GetElementType(); + + return Array.CreateInstance(itemType, 0); + } + + public override object GetValue(IXmlNode node, IDictionaryAdapter parent, IXmlAccessor accessor) + { + var items = new ArrayList(); + var itemType = node.ClrType.GetElementType(); + var references = XmlAdapter.For(parent).References; + + accessor + .GetCollectionAccessor(itemType) + .GetCollectionItems(node, parent, references, items); + + return items.ToArray(itemType); + } + + public override void SetValue(IXmlNode node, IDictionaryAdapter parent, IXmlAccessor accessor, object oldValue, ref object value) + { + var source = (Array) value; + var target = (Array) null; + var originals = (Array) oldValue; + var itemType = source.GetType().GetElementType(); + var subaccessor = accessor.GetCollectionAccessor(itemType); + var cursor = subaccessor.SelectCollectionItems(node, true); + var serializer = subaccessor.Serializer; + var references = XmlAdapter.For(parent).References; + + for (var i = 0; i < source.Length; i++) + { + var originalItem = GetItemSafe(originals, i); + var providedItem = source.GetValue(i); + var assignedItem = providedItem; + + subaccessor.SetValue(cursor, parent, references, cursor.MoveNext(), originalItem, ref assignedItem); + + if (target != null) + { + target.SetValue(assignedItem, i); + } + else if (!Equals(assignedItem, providedItem)) + { + target = Array.CreateInstance(itemType, source.Length); + Array.Copy(source, target, i); + target.SetValue(assignedItem, i); + } + } + + cursor.RemoveAllNext(); + + if (target != null) + value = target; + } + + private static object GetItemSafe(Array array, int index) + { + return array != null && index >= 0 && index < array.Length + ? array.GetValue(index) + : null; + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlCollectionSerializer.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlCollectionSerializer.cs new file mode 100644 index 0000000..4783681 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlCollectionSerializer.cs @@ -0,0 +1,76 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + using System.Collections; + + public abstract class XmlCollectionSerializer : XmlTypeSerializer + { + protected XmlCollectionSerializer() { } + + public override XmlTypeKind Kind + { + get { return XmlTypeKind.Collection; } + } + + public override bool CanGetStub + { + get { return true; } + } + + public abstract Type ListTypeConstructor + { + get; // generic type constructor + } + + public override object GetStub(IXmlNode node, IDictionaryAdapter parent, IXmlAccessor accessor) + { + return GetValueCore(node, parent, accessor); + } + + public override object GetValue(IXmlNode node, IDictionaryAdapter parent, IXmlAccessor accessor) + { + return GetValueCore(node.Save(), parent, accessor); + } + + private object GetValueCore(IXmlNode node, IDictionaryAdapter parent, IXmlAccessor accessor) + { + var itemType = node.ClrType.GetGenericArguments()[0]; + var listType = ListTypeConstructor.MakeGenericType(itemType); + var subaccessor = accessor.GetCollectionAccessor(itemType); + return Activator.CreateInstance(listType, node, parent, subaccessor); + } + + public override void SetValue(IXmlNode node, IDictionaryAdapter parent, IXmlAccessor accessor, object oldValue, ref object value) + { + var current = value as IXmlNodeSource; + if (current != null && current.Node.PositionEquals(node)) + return; + + var newItems = value as IEnumerable; + if (newItems == null) + throw Error.NotSupported(); + + var oldCollection = oldValue as ICollectionProjection; + if (oldCollection != null) + oldCollection.ClearReferences(); + + var newCollection = (ICollectionProjection) GetValue(node, parent, accessor); + newCollection.Replace(newItems); + value = newCollection; + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlComponentSerializer.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlComponentSerializer.cs new file mode 100644 index 0000000..2c62847 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlComponentSerializer.cs @@ -0,0 +1,73 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + using System.Collections; + + public class XmlComponentSerializer : XmlTypeSerializer + { + public static readonly XmlComponentSerializer + Instance = new XmlComponentSerializer(); + + protected XmlComponentSerializer() { } + + public override XmlTypeKind Kind + { + get { return XmlTypeKind.Complex; } + } + + public override bool CanGetStub + { + get { return true; } + } + + public override object GetStub(IXmlNode node, IDictionaryAdapter parent, IXmlAccessor accessor) + { + // TODO: Refactor + var adapter = new XmlAdapter(node, XmlAdapter.For(parent).References); + return parent.CreateChildAdapter(accessor.ClrType, adapter); + } + + public override object GetValue(IXmlNode node, IDictionaryAdapter parent, IXmlAccessor accessor) + { + var adapter = new XmlAdapter(node.Save(), XmlAdapter.For(parent).References); + return parent.CreateChildAdapter(node.ClrType, adapter); + } + + public override void SetValue(IXmlNode node, IDictionaryAdapter parent, IXmlAccessor accessor, object oldValue, ref object value) + { + // Require a dictionary adapter + var source = value as IDictionaryAdapter; + if (source == null) + throw Error.NotDictionaryAdapter(nameof(value)); + + // Detect assignment of own value + var sourceAdapter = XmlAdapter.For(source, false); + if (sourceAdapter != null && node.PositionEquals(sourceAdapter.Node)) + return; + + // Create a fresh component + var targetAdapter = new XmlAdapter(node.Save(), XmlAdapter.For(parent).References); + if (sourceAdapter != null) + targetAdapter.References.UnionWith(sourceAdapter.References); + var component = (IDictionaryAdapter) parent.CreateChildAdapter(node.ClrType, targetAdapter); + + // Copy value onto fresh component + source.CopyTo(component); + value = component; + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlCustomSerializer.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlCustomSerializer.cs new file mode 100644 index 0000000..72d21fd --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlCustomSerializer.cs @@ -0,0 +1,60 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + using System.Xml.Serialization; + + public class XmlCustomSerializer : XmlTypeSerializer + { + public static readonly XmlCustomSerializer + Instance = new XmlCustomSerializer(); + + private XmlCustomSerializer() { } + + public override XmlTypeKind Kind + { + get { return XmlTypeKind.Complex; } + } + + public override object GetValue(IXmlNode node, IDictionaryAdapter parent, IXmlAccessor accessor) + { + var serializable = (IXmlSerializable) Activator.CreateInstance(node.ClrType); + + using (var reader = new XmlSubtreeReader(node, XmlDefaultSerializer.Root)) + { + // Do NOT pre-read containing element + // ...IXmlSerializable is not a symmetric contract + serializable.ReadXml(reader); + } + + return serializable; + } + + public override void SetValue(IXmlNode node, IDictionaryAdapter parent, IXmlAccessor accessor, object oldValue, ref object value) + { + var serializable = (IXmlSerializable) value; + var root = XmlDefaultSerializer.Root; + + using (var writer = new XmlSubtreeWriter(node)) + { + // Pre-write containing element + writer.WriteStartElement(string.Empty, root.ElementName, root.Namespace); + serializable.WriteXml(writer); + writer.WriteEndElement(); + } + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlDefaultSerializer.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlDefaultSerializer.cs new file mode 100644 index 0000000..5b13413 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlDefaultSerializer.cs @@ -0,0 +1,55 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + using System.Xml.Serialization; + + public class XmlDefaultSerializer : XmlTypeSerializer + { + private readonly XmlSerializer serializer; + + public XmlDefaultSerializer(Type type) + { + serializer = new XmlSerializer(type, Root); + } + + public override XmlTypeKind Kind + { + get { return XmlTypeKind.Complex; } + } + + public override object GetValue(IXmlNode node, IDictionaryAdapter parent, IXmlAccessor accessor) + { + using (var reader = new XmlSubtreeReader(node, Root)) + return serializer.CanDeserialize(reader) + ? serializer.Deserialize(reader) + : null; + } + + public override void SetValue(IXmlNode node, IDictionaryAdapter parent, IXmlAccessor accessor, object oldValue, ref object value) + { + using (var writer = new XmlSubtreeWriter(node)) + serializer.Serialize(writer, value); + } + + public static readonly XmlRootAttribute + Root = new XmlRootAttribute + { + ElementName = "Root", + Namespace = string.Empty + }; + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlDynamicSerializer.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlDynamicSerializer.cs new file mode 100644 index 0000000..565b990 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlDynamicSerializer.cs @@ -0,0 +1,44 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + public class XmlDynamicSerializer : XmlTypeSerializer + { + public static readonly XmlDynamicSerializer + Instance = new XmlDynamicSerializer(); + + protected XmlDynamicSerializer() { } + + public override XmlTypeKind Kind + { + get { return XmlTypeKind.Simple; } + } + + public override object GetValue(IXmlNode node, IDictionaryAdapter parent, IXmlAccessor accessor) + { + return node.ClrType == typeof(object) + ? new object() + : XmlTypeSerializer.For(node.ClrType).GetValue(node, parent, accessor); + } + + public override void SetValue(IXmlNode node, IDictionaryAdapter parent, IXmlAccessor accessor, object oldValue, ref object value) + { + if (node.ClrType != typeof(object)) + XmlTypeSerializer.For(node.ClrType).SetValue(node, parent, accessor, oldValue, ref value); + else + node.Clear(); + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlEnumerationSerializer.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlEnumerationSerializer.cs new file mode 100644 index 0000000..08013a2 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlEnumerationSerializer.cs @@ -0,0 +1,36 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + + public class XmlEnumerationSerializer : XmlStringSerializer + { + public static readonly new XmlEnumerationSerializer + Instance = new XmlEnumerationSerializer(); + + protected XmlEnumerationSerializer() { } + + public override XmlTypeKind Kind + { + get { return XmlTypeKind.Simple; } + } + + public override object GetValue(IXmlNode node, IDictionaryAdapter parent, IXmlAccessor accessor) + { + return Enum.Parse(node.ClrType, node.Value, true); + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlListSerializer.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlListSerializer.cs new file mode 100644 index 0000000..46341bd --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlListSerializer.cs @@ -0,0 +1,31 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + + public class XmlListSerializer : XmlCollectionSerializer + { + public static readonly XmlListSerializer + Instance = new XmlListSerializer(); + + protected XmlListSerializer() { } + + public override Type ListTypeConstructor + { + get { return typeof(XmlNodeList<>); } + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlSetSerializer.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlSetSerializer.cs new file mode 100644 index 0000000..00003c0 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlSetSerializer.cs @@ -0,0 +1,31 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + + public class XmlSetSerializer : XmlCollectionSerializer + { + public static readonly XmlSetSerializer + Instance = new XmlSetSerializer(); + + protected XmlSetSerializer() { } + + public override Type ListTypeConstructor + { + get { return typeof(XmlNodeSet<>); } + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlSimpleSerializer.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlSimpleSerializer.cs new file mode 100644 index 0000000..7eeff28 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlSimpleSerializer.cs @@ -0,0 +1,82 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + using System.Xml; + + public class XmlSimpleSerializer : XmlTypeSerializer + { + private readonly Func getString; + private readonly Func getObject; + + public XmlSimpleSerializer( + Func getString, + Func getObject) + { + this.getString = getString; + this.getObject = getObject; + } + + public override XmlTypeKind Kind + { + get { return XmlTypeKind.Simple; } + } + + public override object GetValue(IXmlNode node, IDictionaryAdapter parent, IXmlAccessor accessor) + { + return getObject(node.Value); + } + + public override void SetValue(IXmlNode node, IDictionaryAdapter parent, IXmlAccessor accessor, object oldValue, ref object value) + { + node.Value = getString((T) value); + } + } + + public static class XmlSimpleSerializer + { + public static readonly XmlTypeSerializer + ForBoolean = new XmlSimpleSerializer (XmlConvert.ToString, XmlConvert.ToBoolean), + ForChar = new XmlSimpleSerializer (XmlConvert.ToString, XmlConvert.ToChar), + ForSByte = new XmlSimpleSerializer (XmlConvert.ToString, XmlConvert.ToSByte), + ForInt16 = new XmlSimpleSerializer (XmlConvert.ToString, XmlConvert.ToInt16), + ForInt32 = new XmlSimpleSerializer (XmlConvert.ToString, XmlConvert.ToInt32), + ForInt64 = new XmlSimpleSerializer (XmlConvert.ToString, XmlConvert.ToInt64), + ForByte = new XmlSimpleSerializer (XmlConvert.ToString, XmlConvert.ToByte), + ForUInt16 = new XmlSimpleSerializer (XmlConvert.ToString, XmlConvert.ToUInt16), + ForUInt32 = new XmlSimpleSerializer (XmlConvert.ToString, XmlConvert.ToUInt32), + ForUInt64 = new XmlSimpleSerializer (XmlConvert.ToString, XmlConvert.ToUInt64), + ForSingle = new XmlSimpleSerializer (XmlConvert.ToString, XmlConvert.ToSingle), + ForDouble = new XmlSimpleSerializer (XmlConvert.ToString, XmlConvert.ToDouble), + ForDecimal = new XmlSimpleSerializer (XmlConvert.ToString, XmlConvert.ToDecimal), + ForTimeSpan = new XmlSimpleSerializer (XmlConvert.ToString, XmlConvert.ToTimeSpan), + ForDateTime = new XmlSimpleSerializer (XmlConvert_ToString, XmlConvert_ToDateTime), + ForDateTimeOffset = new XmlSimpleSerializer (XmlConvert.ToString, XmlConvert.ToDateTimeOffset), + ForGuid = new XmlSimpleSerializer (XmlConvert.ToString, XmlConvert.ToGuid), + ForByteArray = new XmlSimpleSerializer (Convert.ToBase64String, Convert.FromBase64String), + ForUri = new XmlSimpleSerializer (u => u.ToString(), s => new Uri(s, UriKind.RelativeOrAbsolute)); + + private static string XmlConvert_ToString(DateTime value) + { + return XmlConvert.ToString(value, XmlDateTimeSerializationMode.RoundtripKind); + } + + private static DateTime XmlConvert_ToDateTime(string value) + { + return XmlConvert.ToDateTime(value, XmlDateTimeSerializationMode.RoundtripKind); + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlStringSerializer.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlStringSerializer.cs new file mode 100644 index 0000000..0ddbf72 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlStringSerializer.cs @@ -0,0 +1,39 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + public class XmlStringSerializer : XmlTypeSerializer + { + public static readonly XmlStringSerializer + Instance = new XmlStringSerializer(); + + protected XmlStringSerializer() { } + + public override XmlTypeKind Kind + { + get { return XmlTypeKind.Simple; } + } + + public override object GetValue(IXmlNode node, IDictionaryAdapter parent, IXmlAccessor accessor) + { + return node.Value; + } + + public override void SetValue(IXmlNode node, IDictionaryAdapter parent, IXmlAccessor accessor, object oldValue, ref object value) + { + node.Value = value.ToString(); + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlTypeKind.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlTypeKind.cs new file mode 100644 index 0000000..c495b85 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlTypeKind.cs @@ -0,0 +1,23 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + public enum XmlTypeKind + { + Simple, + Complex, + Collection + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlTypeSerializer.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlTypeSerializer.cs new file mode 100644 index 0000000..30b0896 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlTypeSerializer.cs @@ -0,0 +1,42 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + + public abstract class XmlTypeSerializer + { + protected XmlTypeSerializer() { } + + public abstract XmlTypeKind Kind + { + get; + } + + public virtual bool CanGetStub + { + get { return false; } + } + + public virtual object GetStub (IXmlNode node, IDictionaryAdapter parent, IXmlAccessor accessor) { throw Error.NotSupported(); } + public abstract object GetValue(IXmlNode node, IDictionaryAdapter parent, IXmlAccessor accessor); + public abstract void SetValue(IXmlNode node, IDictionaryAdapter parent, IXmlAccessor accessor, object oldValue, ref object value); + + public static XmlTypeSerializer For(Type type) + { + return XmlTypeSerializerCache.Instance[type]; + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlTypeSerializerCache.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlTypeSerializerCache.cs new file mode 100644 index 0000000..df11f50 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlTypeSerializerCache.cs @@ -0,0 +1,98 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + using System.Collections.Generic; + using System.ComponentModel; + using System.Reflection; + using System.Xml.Serialization; + + internal class XmlTypeSerializerCache : SingletonDispenser + { + public static readonly XmlTypeSerializerCache + Instance = new XmlTypeSerializerCache(); + + private XmlTypeSerializerCache() + : base(CreateSerializer) + { + this[typeof(Object)] = XmlDynamicSerializer.Instance; + this[typeof(String)] = XmlStringSerializer.Instance; + this[typeof(Boolean)] = XmlSimpleSerializer.ForBoolean; + this[typeof(Char)] = XmlSimpleSerializer.ForChar; + this[typeof(SByte)] = XmlSimpleSerializer.ForSByte; + this[typeof(Int16)] = XmlSimpleSerializer.ForInt16; + this[typeof(Int32)] = XmlSimpleSerializer.ForInt32; + this[typeof(Int64)] = XmlSimpleSerializer.ForInt64; + this[typeof(Byte)] = XmlSimpleSerializer.ForByte; + this[typeof(UInt16)] = XmlSimpleSerializer.ForUInt16; + this[typeof(UInt32)] = XmlSimpleSerializer.ForUInt32; + this[typeof(UInt64)] = XmlSimpleSerializer.ForUInt64; + this[typeof(Single)] = XmlSimpleSerializer.ForSingle; + this[typeof(Double)] = XmlSimpleSerializer.ForDouble; + this[typeof(Decimal)] = XmlSimpleSerializer.ForDecimal; + this[typeof(TimeSpan)] = XmlSimpleSerializer.ForTimeSpan; + this[typeof(DateTime)] = XmlSimpleSerializer.ForDateTime; + this[typeof(DateTimeOffset)] = XmlSimpleSerializer.ForDateTimeOffset; + this[typeof(Guid)] = XmlSimpleSerializer.ForGuid; + this[typeof(Byte[])] = XmlSimpleSerializer.ForByteArray; + this[typeof(Uri)] = XmlSimpleSerializer.ForUri; + } + + private static XmlTypeSerializer CreateSerializer(Type type) + { + if (type.IsArray) + return XmlArraySerializer.Instance; + + if (type.IsGenericType) + { + var genericType = type.GetGenericTypeDefinition(); + if (genericType == typeof(IList<>) || + genericType == typeof(ICollection<>) || + genericType == typeof(IEnumerable<>) || + genericType == typeof(IBindingList<>)) + return XmlListSerializer.Instance; + if (genericType == typeof(ISet<>)) + return XmlSetSerializer.Instance; + if (// Dictionaries are not supported + genericType == typeof(IDictionary<,>) || + genericType == typeof(Dictionary<,>) || + genericType == typeof(SortedDictionary<,>) || + // Concrete list types are not supported + genericType == typeof(List<>) || + genericType == typeof(Stack<>) || + genericType == typeof(Queue<>) || + genericType == typeof(LinkedList<>) || + genericType == typeof(SortedList<,>) || + // Concrete set types are not supported + genericType == typeof(HashSet<>) || + genericType == typeof(SortedSet<>) || + // CLR binding list is not supported; use Castle version + genericType == typeof(BindingList<>)) + throw Error.UnsupportedCollectionType(type); + } + + if (type.IsInterface) + return XmlComponentSerializer.Instance; + if (type.IsEnum) + return XmlEnumerationSerializer.Instance; + if (type.IsCustomSerializable()) + return XmlCustomSerializer.Instance; + if (typeof(System.Xml.XmlNode).IsAssignableFrom(type)) + return XmlXmlNodeSerializer.Instance; + return new XmlDefaultSerializer(type); + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlXmlNodeSerializer.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlXmlNodeSerializer.cs new file mode 100644 index 0000000..a693bcc --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlXmlNodeSerializer.cs @@ -0,0 +1,49 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + using System.Xml; + + public class XmlXmlNodeSerializer : XmlTypeSerializer + { + public static readonly XmlXmlNodeSerializer + Instance = new XmlXmlNodeSerializer(); + + private XmlXmlNodeSerializer() { } + + public override XmlTypeKind Kind + { + get { return XmlTypeKind.Complex; } + } + + public override object GetValue(IXmlNode node, IDictionaryAdapter parent, IXmlAccessor accessor) + { + var source = node.AsRealizable(); + + return (source != null && source.IsReal) + ? source.Value + : null; + } + + public override void SetValue(IXmlNode node, IDictionaryAdapter parent, IXmlAccessor accessor, object oldValue, ref object value) + { + var newNode = (XmlNode) value; + + using (var writer = new XmlSubtreeWriter(node)) + newNode.WriteTo(writer); + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/IXmlIdentity.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/IXmlIdentity.cs new file mode 100644 index 0000000..22eff4e --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/IXmlIdentity.cs @@ -0,0 +1,22 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + public interface IXmlIdentity + { + XmlName Name { get; } + XmlName XsiType { get; } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/IXmlIncludedType.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/IXmlIncludedType.cs new file mode 100644 index 0000000..2039d60 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/IXmlIncludedType.cs @@ -0,0 +1,24 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + + public interface IXmlIncludedType + { + XmlName XsiType { get; } + Type ClrType { get; } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/IXmlIncludedTypeMap.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/IXmlIncludedTypeMap.cs new file mode 100644 index 0000000..48b5488 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/IXmlIncludedTypeMap.cs @@ -0,0 +1,38 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + + public interface IXmlIncludedTypeMap + { + IXmlIncludedType Default { get; } + + bool TryGet(XmlName xsiType, out IXmlIncludedType includedType); + bool TryGet(Type clrType, out IXmlIncludedType includedType); + } + + public static class XmlIncludedTypeMapExtensions + { + public static IXmlIncludedType Require(this IXmlIncludedTypeMap includedTypes, Type clrType) + { + IXmlIncludedType includedType; + if (includedTypes.TryGet(clrType, out includedType)) + return includedType; + + throw Error.NotXmlKnownType(clrType); + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/IXmlKnownType.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/IXmlKnownType.cs new file mode 100644 index 0000000..3bbdfb3 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/IXmlKnownType.cs @@ -0,0 +1,23 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + + public interface IXmlKnownType : IXmlIdentity + { + Type ClrType { get; } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/IXmlKnownTypeMap.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/IXmlKnownTypeMap.cs new file mode 100644 index 0000000..282b3af --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/IXmlKnownTypeMap.cs @@ -0,0 +1,38 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + + public interface IXmlKnownTypeMap + { + IXmlKnownType Default { get; } + + bool TryGet(IXmlIdentity xmlNode, out IXmlKnownType knownType); + bool TryGet(Type clrType, out IXmlKnownType knownType); + } + + public static class XmlKnownTypeMapExtensions + { + public static IXmlKnownType Require(this IXmlKnownTypeMap map, Type clrType) + { + IXmlKnownType knownType; + if (map.TryGet(clrType, out knownType)) + return knownType; + + throw Error.NotXmlKnownType(clrType); + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/XmlIncludedType.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/XmlIncludedType.cs new file mode 100644 index 0000000..9106a30 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/XmlIncludedType.cs @@ -0,0 +1,48 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + + public class XmlIncludedType : IXmlIncludedType + { + private readonly XmlName xsiType; + private readonly Type clrType; + + public XmlIncludedType(XmlName xsiType, Type clrType) + { + if (xsiType.LocalName == null) + throw Error.ArgumentNull("xsiType.LocalName"); + if (clrType == null) + throw Error.ArgumentNull(nameof(clrType)); + + this.xsiType = xsiType; + this.clrType = clrType; + } + + public XmlIncludedType(string localName, string namespaceUri, Type clrType) + : this(new XmlName(localName, namespaceUri), clrType) { } + + public XmlName XsiType + { + get { return xsiType; } + } + + public Type ClrType + { + get { return clrType; } + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/XmlIncludedTypeSet.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/XmlIncludedTypeSet.cs new file mode 100644 index 0000000..edf6e73 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/XmlIncludedTypeSet.cs @@ -0,0 +1,95 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + using System.Collections; + using System.Collections.Generic; + + public class XmlIncludedTypeSet : IXmlIncludedTypeMap, IEnumerable + { + private readonly Dictionary itemsByXsiType; + private readonly Dictionary itemsByClrType; + + public XmlIncludedTypeSet() + { + itemsByXsiType = new Dictionary(); + itemsByClrType = new Dictionary(); + + foreach (var includedType in DefaultEntries) + Add(includedType); + } + + IXmlIncludedType IXmlIncludedTypeMap.Default + { + get { throw Error.NoDefaultKnownType(); } + } + + public void Add(IXmlIncludedType includedType) + { + // Allow only one item per xsi:type + itemsByXsiType.Add(includedType.XsiType, includedType); + + // Overwrite any prior entry for CLR type + itemsByClrType[includedType.ClrType] = includedType; + } + + public bool TryGet(XmlName xsiType, out IXmlIncludedType includedType) + { + return itemsByXsiType.TryGetValue(xsiType, out includedType); + } + + public bool TryGet(Type clrType, out IXmlIncludedType includedType) + { + return itemsByClrType.TryGetValue(clrType, out includedType); + } + + public IEnumerator GetEnumerator() + { + return itemsByXsiType.Values.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public static readonly IList DefaultEntries + = Array.AsReadOnly(new IXmlIncludedType[] + { + new XmlIncludedType("anyType", Xsd .NamespaceUri, typeof(object)), + new XmlIncludedType("string", Xsd .NamespaceUri, typeof(string)), + new XmlIncludedType("boolean", Xsd .NamespaceUri, typeof(bool)), + new XmlIncludedType("byte", Xsd .NamespaceUri, typeof(sbyte)), + new XmlIncludedType("unsignedByte", Xsd .NamespaceUri, typeof(byte)), + new XmlIncludedType("short", Xsd .NamespaceUri, typeof(short)), + new XmlIncludedType("unsignedShort", Xsd .NamespaceUri, typeof(ushort)), + new XmlIncludedType("int", Xsd .NamespaceUri, typeof(int)), + new XmlIncludedType("unsignedInt", Xsd .NamespaceUri, typeof(uint)), + new XmlIncludedType("long", Xsd .NamespaceUri, typeof(long)), + new XmlIncludedType("unsignedLong", Xsd .NamespaceUri, typeof(ulong)), + new XmlIncludedType("float", Xsd .NamespaceUri, typeof(float)), + new XmlIncludedType("double", Xsd .NamespaceUri, typeof(double)), + new XmlIncludedType("decimal", Xsd .NamespaceUri, typeof(decimal)), + new XmlIncludedType("guid", Wsdl.NamespaceUri, typeof(Guid)), + new XmlIncludedType("dateTime", Xsd .NamespaceUri, typeof(DateTime)), +// new XmlIncludedType("dateTime", Xsd .NamespaceUri, typeof(DateTimeOffset)), TODO: Find a way to enable this without duplicate key exception. + new XmlIncludedType("duration", Xsd .NamespaceUri, typeof(TimeSpan)), + new XmlIncludedType("base64Binary", Xsd .NamespaceUri, typeof(byte[])), + new XmlIncludedType("anyURI", Xsd .NamespaceUri, typeof(Uri)), + new XmlIncludedType("QName", Xsd .NamespaceUri, typeof(System.Xml.XmlQualifiedName)) + }); + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/XmlKnownType.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/XmlKnownType.cs new file mode 100644 index 0000000..c1d4f7b --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/XmlKnownType.cs @@ -0,0 +1,61 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + + public class XmlKnownType : IXmlKnownType + { + private readonly XmlName name; + private readonly XmlName xsiType; + private readonly Type clrType; + + public XmlKnownType(XmlName name, XmlName xsiType, Type clrType) + { + if (name.LocalName == null) + throw Error.ArgumentNull("name.LocalName"); + if (clrType == null) + throw Error.ArgumentNull(nameof(clrType)); + + this.name = name; + this.xsiType = xsiType; + this.clrType = clrType; + } + + public XmlKnownType(string nameLocalName, string nameNamespaceUri, string xsiTypeLocalName, string xsiTypeNamespaceUri, Type clrType) + : this + ( + new XmlName(nameLocalName, nameNamespaceUri), + new XmlName(xsiTypeLocalName, xsiTypeNamespaceUri), + clrType + ) + { } + + public XmlName Name + { + get { return name; } + } + + public XmlName XsiType + { + get { return xsiType; } + } + + public Type ClrType + { + get { return clrType; } + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/XmlKnownTypeSet.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/XmlKnownTypeSet.cs new file mode 100644 index 0000000..d29f139 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/XmlKnownTypeSet.cs @@ -0,0 +1,176 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.Linq; + + public class XmlKnownTypeSet : IXmlKnownTypeMap, IEnumerable + { + private readonly Dictionary itemsByXmlIdentity; + private readonly Dictionary itemsByClrType; + private readonly Type defaultType; + + public XmlKnownTypeSet(Type defaultType) + { + if (defaultType == null) + throw Error.ArgumentNull(nameof(defaultType)); + + itemsByXmlIdentity = new Dictionary(XmlIdentityComparer.Instance); + itemsByClrType = new Dictionary(); + this.defaultType = defaultType; + } + + public IXmlKnownType Default + { + get + { + IXmlKnownType knownType; + if (defaultType == null || !TryGet(defaultType, out knownType)) + throw Error.NoDefaultKnownType(); + return knownType; + } + } + + public void Add(IXmlKnownType knownType, bool overwrite) + { + // All XmlTypes are present here + if (overwrite || !itemsByXmlIdentity.ContainsKey(knownType)) + itemsByXmlIdentity[knownType] = knownType; + + // Only contains the default XmlType for each ClrType + var clrType = knownType.ClrType; + if (overwrite || !itemsByClrType.ContainsKey(clrType)) + itemsByClrType[clrType] = knownType; + } + + public void AddXsiTypeDefaults() + { + // If there is only one xsi:type possible for a known local name and namespace URI, + // add another XmlType to recognize nodes that don't provide the xsi:type. + + var bits = new Dictionary( + itemsByXmlIdentity.Count, + XmlKnownTypeNameComparer.Instance); + + foreach (var knownType in itemsByXmlIdentity.Values) + { + bool bit; + bits[knownType] = bits.TryGetValue(knownType, out bit) + ? false // another by same name; can't add a default + : knownType.XsiType != XmlName.Empty; // first by this name; can add a default, if not already in default form + } + + foreach (var pair in bits) + { + if (pair.Value) + { + var template = pair.Key; + var knownType = new XmlKnownType(template.Name, XmlName.Empty, template.ClrType); + Add(knownType, true); + } + } + } + + public bool TryGet(IXmlIdentity xmlIdentity, out IXmlKnownType knownType) + { + return itemsByXmlIdentity.TryGetValue(xmlIdentity, out knownType); + } + + public bool TryGet(Type clrType, out IXmlKnownType knownType) + { + return itemsByClrType.TryGetValue(clrType, out knownType); + } + + public IXmlKnownType[] ToArray() + { + return itemsByXmlIdentity.Values.ToArray(); + } + + public IEnumerator GetEnumerator() + { + return itemsByXmlIdentity.Values.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return itemsByXmlIdentity.Values.GetEnumerator(); + } + + private sealed class XmlIdentityComparer : IEqualityComparer + { + public static readonly XmlIdentityComparer + Instance = new XmlIdentityComparer(); + + private XmlIdentityComparer() { } + + public bool Equals(IXmlIdentity x, IXmlIdentity y) + { + var nameX = x.Name; + var nameY = y.Name; + + if (!NameComparer.Equals(nameX.LocalName, nameY.LocalName)) + return false; + + if (!XsiTypeComparer.Equals(x.XsiType, y.XsiType)) + return false; + + return nameX.NamespaceUri == null + || nameY.NamespaceUri == null + || NameComparer.Equals(nameX.NamespaceUri, nameY.NamespaceUri); + } + + public int GetHashCode(IXmlIdentity name) + { + var code = NameComparer.GetHashCode(name.Name.LocalName); + + if (name.XsiType != XmlName.Empty) + code = (code << 7 | code >> 25) + ^ XsiTypeComparer.GetHashCode(name.XsiType); + + // DO NOT include NamespaceUri in hash code. + // That would break 'null means any' behavior. + + return code; + } + } + + private sealed class XmlKnownTypeNameComparer : IEqualityComparer + { + public static readonly XmlKnownTypeNameComparer + Instance = new XmlKnownTypeNameComparer(); + + private XmlKnownTypeNameComparer() { } + + public bool Equals(IXmlKnownType knownTypeA, IXmlKnownType knownTypeB) + { + return XmlNameComparer.IgnoreCase.Equals(knownTypeA.Name, knownTypeB.Name); + } + + public int GetHashCode(IXmlKnownType knownType) + { + return XmlNameComparer.IgnoreCase.GetHashCode(knownType.Name); + } + } + + private static readonly StringComparer + NameComparer = StringComparer.OrdinalIgnoreCase; + + private static readonly XmlNameComparer + XsiTypeComparer = XmlNameComparer.Default; + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/DictionaryAdapterExtensions.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/DictionaryAdapterExtensions.cs new file mode 100644 index 0000000..7281f9a --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/DictionaryAdapterExtensions.cs @@ -0,0 +1,90 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + using System.Linq; + using System.Collections; + + public static class DictionaryAdapterExtensions + { + public static object CreateChildAdapter(this IDictionaryAdapter parent, Type type, XmlAdapter adapter) + { + return CreateChildAdapter(parent, type, adapter, null); + } + + public static object CreateChildAdapter(this IDictionaryAdapter parent, Type type, XmlAdapter adapter, IDictionary dictionary) + { + if (null == dictionary) + dictionary = new Hashtable(); + + var descriptor = parent.Meta.CreateDescriptor(); + parent.This.Descriptor.CopyBehaviors(descriptor); + descriptor.AddBehavior(adapter); + + return parent.This.Factory.GetAdapter(type, dictionary, descriptor); + } + + public static bool HasAccessor(this PropertyDescriptor property) + { + return property.ExtendedProperties.Contains(XmlAccessorKey); + } + + public static XmlAccessor GetAccessor(this PropertyDescriptor property) + { + return (XmlAccessor) property.ExtendedProperties[XmlAccessorKey]; + } + + public static void SetAccessor(this PropertyDescriptor property, XmlAccessor accessor) + { + property.ExtendedProperties[XmlAccessorKey] = accessor; + } + + public static bool HasXmlMeta(this DictionaryAdapterMeta meta) + { + return meta.ExtendedProperties.Contains(XmlMetaKey); + } + + public static XmlMetadata GetXmlMeta(this DictionaryAdapterMeta meta) + { + return (XmlMetadata) meta.ExtendedProperties[XmlMetaKey]; + } + + public static void SetXmlMeta(this DictionaryAdapterMeta meta, XmlMetadata xmlMeta) + { + meta.ExtendedProperties[XmlMetaKey] = xmlMeta; + } + + public static bool HasXmlType(this DictionaryAdapterMeta meta) + { + return meta.ExtendedProperties.Contains(XmlTypeKey); + } + + public static string GetXmlType(this DictionaryAdapterMeta meta) + { + return (string) meta.ExtendedProperties[XmlTypeKey]; + } + + public static void SetXmlType(this DictionaryAdapterMeta meta, string value) + { + meta.ExtendedProperties[XmlTypeKey] = value; + } + + private const string + XmlAccessorKey = "XmlAccessor", + XmlMetaKey = "XmlMeta", + XmlTypeKey = "XmlType"; + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/Error.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/Error.cs new file mode 100644 index 0000000..dc84631 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/Error.cs @@ -0,0 +1,219 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + using SerializationException = System.Runtime.Serialization.SerializationException; + using System.Xml.XPath; + + internal static class Error + { + internal static Exception ArgumentNull(string paramName) + { + return new ArgumentNullException(paramName); + } + + internal static Exception ArgumentOutOfRange(string paramName) + { + return new ArgumentOutOfRangeException(paramName); + } + + internal static Exception InvalidOperation() + { + return new InvalidOperationException(); + } + + internal static Exception NotSupported() + { + return new NotSupportedException(); + } + + internal static Exception ObjectDisposed(string objectName) + { + return new ObjectDisposedException(objectName); + } + + internal static Exception AttributeConflict(string propertyName) + { + var message = string.Format + ( + "The behaviors defined for property '{0}' are ambiguous or conflicting.", + propertyName + ); + return new InvalidOperationException(message); + } + + internal static Exception SeparateGetterSetterOnComplexType(string propertyName) + { + var message = string.Format + ( + "Cannot apply getter/setter behaviors for property '{0}'. Separate getters/setters are supported for simple types only.", + propertyName + ); + return new InvalidOperationException(message); + } + + internal static Exception XmlMetadataNotAvailable(Type clrType) + { + var message = string.Format + ( + "XML metadata is not available for type '{0}'.", + clrType.FullName + ); + return new InvalidOperationException(message); + } + + internal static Exception NotDictionaryAdapter(string paramName) + { + var message = "The argument is not a dictionary adapter."; + return new ArgumentException(message, paramName); + } + + internal static Exception NoInstanceDescriptor(string paramName) + { + var message = "The dictionary adapter does not have an instance descriptor."; + return new ArgumentException(message, paramName); + } + + internal static Exception NoXmlAdapter(string paramName) + { + var message = "The dictionary adapter does not have XmlAdapter behavior."; + return new ArgumentException(message, paramName); + } + + internal static Exception NotRealizable() + { + var message = string.Format( + "The given node cannot provide an underlying object of type {0}.", + typeof(T).FullName); + return new NotSupportedException(message); + } + + internal static Exception CursorNotMutable() + { + var message = "The cursor does not support creation, removal, or modification of nodes."; + return new NotSupportedException(message); + } + + internal static Exception CursorNotInCreatableState() + { + var message = "The cursor cannot create nodes in its current state."; + return new InvalidOperationException(message); + } + + internal static Exception CursorNotInRemovableState() + { + var message = "The cursor cannot remove nodes in its current state."; + return new InvalidOperationException(message); + } + + internal static Exception CursorNotInCoercibleState() + { + var message = "The cursor cannot change node types in its current state."; + return new InvalidOperationException(message); + } + + internal static Exception CursorNotInRealizableState() + { + var message = "The cursor cannot realize virtual nodes in its current state"; + return new InvalidOperationException(message); + } + + internal static Exception CursorCannotMoveToGivenNode() + { + var message = "The cursor cannot move to the given node."; + return new InvalidOperationException(message); + } + + internal static Exception CannotSetAttribute(IXmlIdentity identity) + { + var message = string.Format + ( + "Cannot set attribute on node '{0}'.", + identity.Name.ToString() + ); + return new InvalidOperationException(message); + } + + internal static Exception NotXmlKnownType(Type clrType) + { + var message = string.Format + ( + "No XML type is defined for CLR type {0}.", + clrType.FullName + ); + return new SerializationException(message); + } + + internal static Exception UnsupportedCollectionType(Type clrType) + { + var message = string.Format + ( + "Unsupported collection type: {0}.", + clrType.FullName + ); + return new SerializationException(message); + } + + internal static Exception NotCollectionType(string paramName) + { + var message = "The argument is not a valid collection type."; + return new ArgumentException(message, paramName); + } + + + internal static Exception InvalidLocalName() + { + var message = "Invalid local name."; + return new FormatException(message); + } + + internal static Exception InvalidNamespaceUri() + { + var message = "Invalid namespace URI."; + return new FormatException(message); + } + + internal static Exception NoDefaultKnownType() + { + var message = "No default XML type exists in the given context."; + return new InvalidOperationException(message); + } + + internal static Exception XPathNotCreatable(CompiledXPath path) + { + var message = string.Format( + "The path '{0}' is not a creatable XPath expression.", + path.Path.Expression); + return new XPathException(message); + } + + internal static Exception XPathNavigationFailed(XPathExpression path) + { + var message = string.Format( + "Failed navigation to {0} element after creation.", + path.Expression); + return new XPathException(message); + } + + internal static Exception ObjectIdNotFound(string id) + { + var message = string.Format( + "No object with ID '{0}' was present in the XML.", + id); + return new SerializationException(message); + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/IConfigurable.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/IConfigurable.cs new file mode 100644 index 0000000..f52250a --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/IConfigurable.cs @@ -0,0 +1,21 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + public interface IConfigurable + { + void Configure(T value); + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/IRealizable.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/IRealizable.cs new file mode 100644 index 0000000..2ab75e7 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/IRealizable.cs @@ -0,0 +1,40 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + // OBSOLETE: This has been replaced with IVirtual. + + public interface IRealizable : IRealizableSource + { + bool IsReal { get; } + T Value { get; } + } + + public interface IRealizableSource + { + IRealizable AsRealizable(); + } + + public static class RealizableExtensions + { + public static IRealizable RequireRealizable(this IRealizableSource obj) + { + var realizable = obj.AsRealizable(); + if (realizable == null) + throw Error.NotRealizable(); + return realizable; + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/SingletonDispenser.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/SingletonDispenser.cs new file mode 100644 index 0000000..c3a9a01 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/SingletonDispenser.cs @@ -0,0 +1,131 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + using System.Collections.Generic; + using System.Threading; + + public class SingletonDispenser + where TItem : class + { + private readonly ReaderWriterLockSlim locker; + private readonly Dictionary items; + private readonly Func factory; + + public SingletonDispenser(Func factory) + { + if (factory == null) + throw Error.ArgumentNull(nameof(factory)); + + this.locker = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion); + this.items = new Dictionary(); + this.factory = factory; + } + + public TItem this[TKey key] + { + get { return GetOrCreate(key); } + protected set { items[key] = value; } + } + + private TItem GetOrCreate(TKey key) + { + object item; + return TryGetExistingItem(key, out item) + ? item as TItem ?? WaitForCreate(key, item) + : Create(key, item); + } + + private bool TryGetExistingItem(TKey key, out object item) + { + locker.EnterReadLock(); + try + { + if (items.TryGetValue(key, out item)) + { + return true; + } + } + finally + { + locker.ExitReadLock(); + } + + locker.EnterUpgradeableReadLock(); + try + { + if (items.TryGetValue(key, out item)) + { + return true; + } + else + { + locker.EnterWriteLock(); + try + { + items[key] = item = new ManualResetEvent(false); + return false; + } + finally + { + locker.ExitWriteLock(); + } + } + } + finally + { + locker.ExitUpgradeableReadLock(); + } + } + + private TItem WaitForCreate(TKey key, object item) + { + var handle = (ManualResetEvent) item; + + handle.WaitOne(); + + locker.EnterReadLock(); + try + { + return (TItem)items[key]; + } + finally + { + locker.ExitReadLock(); + } + } + + private TItem Create(TKey key, object item) + { + var handle = (ManualResetEvent) item; + + var result = factory(key); + + locker.EnterWriteLock(); + try + { + items[key] = result; + } + finally + { + locker.ExitWriteLock(); + } + + handle.Set(); + return result; + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/StringExtensions.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/StringExtensions.cs new file mode 100644 index 0000000..df756f1 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/StringExtensions.cs @@ -0,0 +1,26 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + + internal static class StringExtensions + { + public static string NonEmpty(this string s) + { + return string.IsNullOrEmpty(s) ? null : s; + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/Try.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/Try.cs new file mode 100644 index 0000000..224da76 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/Try.cs @@ -0,0 +1,35 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System.Diagnostics; + + public static class Try + { + [DebuggerHidden] + public static bool Failure(out T result) + { + result = default(T); + return false; + } + + [DebuggerHidden] + public static bool Success(out T result, T value) + { + result = value; + return true; + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/TypeExtensions.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/TypeExtensions.cs new file mode 100644 index 0000000..2989ddc --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/TypeExtensions.cs @@ -0,0 +1,54 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + using System.Linq; + using System.Reflection; + using System.Xml.Serialization; + + public static class TypeExtensions + { + public static Type NonNullable(this Type type) + { + return type.IsGenericType + && type.GetGenericTypeDefinition() == typeof(Nullable<>) + ? type.GetGenericArguments()[0] + : type; + } + + public static Type GetCollectionItemType(this Type type) + { + if (type.IsArray) + return type.GetElementType(); + if (type.IsGenericType) + return type.GetGenericArguments().Single(); + throw Error.NotCollectionType(nameof(type)); + } + + public static Type GetComponentType(this object obj) + { + var adapter = obj as IDictionaryAdapter; + return (adapter == null) + ? obj.GetType() + : adapter.Meta.Type; + } + + internal static bool IsCustomSerializable(this Type type) + { + return typeof(IXmlSerializable).IsAssignableFrom(type); + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/XmlSubtreeReader.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/XmlSubtreeReader.cs new file mode 100644 index 0000000..66812b3 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/XmlSubtreeReader.cs @@ -0,0 +1,227 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + using System.Threading; + using System.Xml; + using System.Xml.Serialization; + + public class XmlSubtreeReader : XmlReader + { + private readonly string rootLocalName; + private readonly string rootNamespaceURI; + private string underlyingNamespaceURI; + private XmlReader reader; + + public XmlSubtreeReader(IXmlNode node, XmlRootAttribute root) + : this(node, root.ElementName, root.Namespace) { } + + public XmlSubtreeReader(IXmlNode node, string rootLocalName, string rootNamespaceUri) + { + if (null == node) + throw Error.ArgumentNull(nameof(node)); + if (null == rootLocalName) + throw Error.ArgumentNull(nameof(rootLocalName)); + + this.reader = node.ReadSubtree(); + this.rootLocalName = reader.NameTable.Add(rootLocalName); + this.rootNamespaceURI = rootNamespaceUri ?? string.Empty; + } + + protected override void Dispose(bool managed) + { + try { if (managed) DisposeReader(); } + finally { base.Dispose(managed); } + } + + private void DisposeReader() + { + IDisposable value = Interlocked.Exchange(ref reader, null); + if (null != value) value.Dispose(); + } + + public bool IsDisposed + { + get { return null == reader; } + } + + private void RequireNotDisposed() + { + if (IsDisposed) + throw Error.ObjectDisposed("XmlSubtreeReader"); + } + + protected XmlReader Reader + { + get { RequireNotDisposed(); return reader; } + } + + public override ReadState ReadState + { + get { return IsDisposed ? ReadState.Closed : reader.ReadState; } + } + + public override int Depth + { + get { return Reader.Depth; } + } + + public override XmlNodeType NodeType + { + get { return Reader.NodeType; } + } + + public bool IsAtRootElement + { + get + { + RequireNotDisposed(); + return + reader.ReadState == ReadState.Interactive && + reader.Depth == 0 && + ( + reader.NodeType == XmlNodeType.Element || + reader.NodeType == XmlNodeType.EndElement + ); + } + } + + public override bool EOF + { + get { return Reader.EOF; } + } + + public override string Prefix + { + get { return Reader.Prefix; } + } + + public override string LocalName + { + get { return IsAtRootElement ? rootLocalName : Reader.LocalName; } + } + + public override string NamespaceURI + { + get { return IsAtRootElement ? CaptureNamespaceUri() : TranslateNamespaceURI(); } + } + + private string CaptureNamespaceUri() + { + if (underlyingNamespaceURI == null) + underlyingNamespaceURI = Reader.NamespaceURI; + return rootNamespaceURI; + } + + private string TranslateNamespaceURI() + { + var actualNamespaceURI = Reader.NamespaceURI; + return actualNamespaceURI == underlyingNamespaceURI + ? rootNamespaceURI + : actualNamespaceURI; + } + + public override string Value + { + get { return Reader.Value; } + } + + public override bool IsEmptyElement + { + get { return Reader.IsEmptyElement; } + } + + public override int AttributeCount + { + get { return Reader.AttributeCount; } + } + + public override string BaseURI + { + get { return Reader.BaseURI; } + } + + public override XmlNameTable NameTable + { + get { return Reader.NameTable; } + } + + public override bool Read() + { + return Reader.Read(); + } + + public override bool MoveToElement() + { + return Reader.MoveToElement(); + } + + public override bool MoveToFirstAttribute() + { + return Reader.MoveToFirstAttribute(); + } + + public override bool MoveToNextAttribute() + { + return Reader.MoveToNextAttribute(); + } + + public override bool MoveToAttribute(string name) + { + return Reader.MoveToAttribute(name); + } + + public override bool MoveToAttribute(string name, string ns) + { + return Reader.MoveToAttribute(name, ns); + } + + public override bool ReadAttributeValue() + { + return Reader.ReadAttributeValue(); + } + + public override string GetAttribute(int i) + { + return Reader.GetAttribute(i); + } + + public override string GetAttribute(string name) + { + return Reader.GetAttribute(name); + } + + public override string GetAttribute(string name, string namespaceURI) + { + return Reader.GetAttribute(name, namespaceURI); + } + + public override string LookupNamespace(string prefix) + { + return Reader.LookupNamespace(prefix); + } + + public override void ResolveEntity() + { + Reader.ResolveEntity(); + } + + public override void Close() + { + if (!IsDisposed) reader.Close(); + } + } +} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/XmlSubtreeWriter.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/XmlSubtreeWriter.cs new file mode 100644 index 0000000..1b44172 --- /dev/null +++ b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/XmlSubtreeWriter.cs @@ -0,0 +1,355 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter.Xml +{ + using System; + using System.Threading; + using System.Xml; + + // DEPTH: ROOT STATES: + // 0: [Start, Prolog] + // 1: [Element, Attribute] + // 2: ... [Content] + + public class XmlSubtreeWriter : XmlWriter + { + private readonly IXmlNode node; + private XmlWriter rootWriter; + private XmlWriter childWriter; + private WriteState state; + private int depth; + + public XmlSubtreeWriter(IXmlNode node) + { + if (node == null) + throw Error.ArgumentNull(nameof(node)); + + this.node = node; + } + + protected override void Dispose(bool managed) + { + try + { + if (managed) + { + Reset(WriteState.Closed); + DisposeWriter(ref rootWriter); + DisposeWriter(ref childWriter); + } + } + finally + { + base.Dispose(managed); + } + } + + private void DisposeWriter(ref XmlWriter writer) + { + var value = Interlocked.Exchange(ref writer, null); + if (null != value) value.Close(); + } + + private XmlWriter RootWriter + { + get { return rootWriter ?? (rootWriter = node.WriteAttributes()); } + } + + private XmlWriter ChildWriter + { + get { return childWriter ?? (childWriter = node.WriteChildren()); } + } + + private bool IsInRootAttribute + { + get { return state == WriteState.Attribute; } + } + + private bool IsInRoot + { + get { return depth > 0; } + } + + private bool IsInChild + { + get { return depth > 1; } + } + + public override WriteState WriteState + { + get { return (IsInRoot && state == WriteState.Content) ? childWriter.WriteState : state; } + } + + public override void WriteStartDocument(bool standalone) + { + WriteStartDocument(); + } + + public override void WriteStartDocument() + { + RequireState(WriteState.Start); + state = WriteState.Prolog; + // (do not write anything) + } + + public override void WriteDocType(string name, string pubid, string sysid, string subset) + { + RequireState(WriteState.Start, WriteState.Prolog); + state = WriteState.Prolog; + // (do not write anything) + } + + public override void WriteStartElement(string prefix, string localName, string ns) + { + try + { + if (IsInRoot) + { + ChildWriter.WriteStartElement(prefix, localName, ns); + state = WriteState.Content; + } + else // is in prolog + { + RequireState(WriteState.Start, WriteState.Prolog); + node.Clear(); + state = WriteState.Element; + } + depth++; + } + catch { Reset(WriteState.Error); throw; } + } + + private void WriteEndElement(Action action) + { + try + { + if (IsInChild) + { + action(ChildWriter); + state = WriteState.Content; + } + else // is in root (or prolog) + { + RequireState(WriteState.Element, WriteState.Content); + state = WriteState.Prolog; + } + depth--; + } + catch { Reset(WriteState.Error); throw; } + } + + public override void WriteEndElement() + { + WriteEndElement(w => w.WriteEndElement()); + } + + public override void WriteFullEndElement() + { + WriteEndElement(w => w.WriteFullEndElement()); + } + + private void WriteAttribute(Action action, WriteState entryState, WriteState exitState) + { + try + { + if (IsInChild) + { + action(ChildWriter); + } + else // is in root (or prolog) + { + RequireState(entryState); + action(RootWriter); + state = exitState; + } + } + catch { Reset(WriteState.Error); throw; } + } + + public override void WriteStartAttribute(string prefix, string localName, string ns) + { + WriteAttribute(w => w.WriteStartAttribute(prefix, localName, ns), + entryState: WriteState.Element, + exitState: WriteState.Attribute); + } + + public override void WriteEndAttribute() + { + WriteAttribute(w => w.WriteEndAttribute(), + entryState: WriteState.Attribute, + exitState: WriteState.Element); + } + + private void WriteElementOrAttributeContent(Action action) + { + try + { + if (IsInChild) + action(ChildWriter); + else if (IsInRootAttribute) + action(RootWriter); + else // is in root (or prolog) + { + RequireState(WriteState.Element, WriteState.Content); + action(ChildWriter); + state = WriteState.Content; + } + } + catch { Reset(WriteState.Error); throw; } + } + + public override void WriteString(string text) + { + WriteElementOrAttributeContent(w => w.WriteString(text)); + } + + public override void WriteCharEntity(char ch) + { + WriteElementOrAttributeContent(w => w.WriteCharEntity(ch)); + } + + public override void WriteSurrogateCharEntity(char lowChar, char highChar) + { + WriteElementOrAttributeContent(w => w.WriteSurrogateCharEntity(lowChar, highChar)); + } + + public override void WriteEntityRef(string name) + { + WriteElementOrAttributeContent(w => w.WriteEntityRef(name)); + } + + public override void WriteChars(char[] buffer, int index, int count) + { + WriteElementOrAttributeContent(w => w.WriteChars(buffer, index, count)); + } + + public override void WriteBase64(byte[] buffer, int index, int count) + { + WriteElementOrAttributeContent(w => w.WriteBase64(buffer, index, count)); + } + + public override void WriteRaw(string data) + { + WriteElementOrAttributeContent(w => w.WriteRaw(data)); + } + + public override void WriteRaw(char[] buffer, int index, int count) + { + WriteElementOrAttributeContent(w => w.WriteRaw(buffer, index, count)); + } + + private void WriteElementContent(Action action) + { + try + { + RequireState(WriteState.Element, WriteState.Content); + action(ChildWriter); + state = WriteState.Content; + } + catch { Reset(WriteState.Error); throw; } + } + + public override void WriteCData(string text) + { + WriteElementContent(w => w.WriteCData(text)); + } + + public override void WriteProcessingInstruction(string name, string text) + { + WriteElementContent(w => w.WriteProcessingInstruction(name, text)); + } + + public override void WriteComment(string text) + { + WriteElementContent(w => w.WriteComment(text)); + } + + public override void WriteWhitespace(string ws) + { + WriteElementContent(w => w.WriteWhitespace(ws)); + } + + private void WithWriters(Action action, bool worksIfClosed = false, WriteState? resetTo = null) + { + try + { + if (! worksIfClosed ) RequireNotClosed(); + if (null != rootWriter ) action(rootWriter); + if (null != childWriter) action(childWriter); + if (null != resetTo ) Reset(resetTo.Value); + } + catch { Reset(WriteState.Error); throw; } + } + + public override void Flush() + { + WithWriters(w => w.Flush()); + } + + public override void WriteEndDocument() + { + WithWriters(w => w.WriteEndDocument(), resetTo: WriteState.Start); + } + + public override void Close() + { + WithWriters(w => w.Close(), resetTo: WriteState.Closed, worksIfClosed: true); + } + + public override string LookupPrefix(string ns) + { + // This one is the oddball + try + { + string prefix; + return + ( // Try child writer first + null != childWriter && + null != (prefix = childWriter.LookupPrefix(ns)) + ) ? prefix : + ( // Try root writer next + null != rootWriter && + null != (prefix = rootWriter.LookupPrefix(ns)) + ) ? prefix : + null; + } + catch { Reset(WriteState.Error); throw; } + } + + private void RequireNotClosed() + { + if (state == WriteState.Closed || state == WriteState.Error) + throw Error.InvalidOperation(); + } + + private void RequireState(WriteState state) + { + if (this.state != state) + throw Error.InvalidOperation(); + } + + private void RequireState(WriteState state1, WriteState state2) + { + if (state != state1 && state != state2) + throw Error.InvalidOperation(); + } + + private void Reset(WriteState state) + { + this.depth = 0; + this.state = state; + } + } +} diff --git a/Castle.Core/Core/Configuration/AbstractConfiguration.cs b/Castle.Core/Core/Configuration/AbstractConfiguration.cs new file mode 100644 index 0000000..d1120a4 --- /dev/null +++ b/Castle.Core/Core/Configuration/AbstractConfiguration.cs @@ -0,0 +1,99 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Core.Configuration +{ + using System; + using System.Globalization; + + /// + /// This is an abstract implementation + /// that deals with methods that can be abstracted away + /// from underlying implementations. + /// + /// + /// AbstractConfiguration makes easier to implementers + /// to create a new version of + /// +#if FEATURE_SERIALIZATION + [Serializable] +#endif + public abstract class AbstractConfiguration : IConfiguration + { + private readonly ConfigurationAttributeCollection attributes = new ConfigurationAttributeCollection(); + private readonly ConfigurationCollection children = new ConfigurationCollection(); + + /// + /// Gets node attributes. + /// + /// + /// All attributes of the node. + /// + public virtual ConfigurationAttributeCollection Attributes + { + get { return attributes; } + } + + /// + /// Gets all child nodes. + /// + /// The of child nodes. + public virtual ConfigurationCollection Children + { + get { return children; } + } + + /// + /// Gets the name of the . + /// + /// + /// The Name of the . + /// + public string Name { get; protected set; } + + /// + /// Gets the value of . + /// + /// + /// The Value of the . + /// + public string Value { get; protected set; } + + /// + /// Gets the value of the node and converts it + /// into specified . + /// + /// The + /// + /// The Default value returned if the conversion fails. + /// + /// The Value converted into the specified type. + public virtual object GetValue(Type type, object defaultValue) + { + if (type == null) + { + throw new ArgumentNullException(nameof(type)); + } + + try + { + return Convert.ChangeType(Value, type, CultureInfo.CurrentCulture); + } + catch (InvalidCastException) + { + return defaultValue; + } + } + } +} \ No newline at end of file diff --git a/Castle.Core/Core/Configuration/ConfigurationAttributeCollection.cs b/Castle.Core/Core/Configuration/ConfigurationAttributeCollection.cs new file mode 100644 index 0000000..fbd8e13 --- /dev/null +++ b/Castle.Core/Core/Configuration/ConfigurationAttributeCollection.cs @@ -0,0 +1,38 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Core.Configuration +{ +#if FEATURE_SERIALIZATION + using System; + using System.Runtime.Serialization; +#endif + +#if FEATURE_SERIALIZATION + [Serializable] +#endif + public class ConfigurationAttributeCollection + : System.Collections.Specialized.NameValueCollection + { + public ConfigurationAttributeCollection() + { + } + +#if FEATURE_SERIALIZATION + protected ConfigurationAttributeCollection(SerializationInfo info, StreamingContext context) : base(info, context) + { + } +#endif + } +} \ No newline at end of file diff --git a/Castle.Core/Core/Configuration/ConfigurationCollection.cs b/Castle.Core/Core/Configuration/ConfigurationCollection.cs new file mode 100644 index 0000000..8c9b34f --- /dev/null +++ b/Castle.Core/Core/Configuration/ConfigurationCollection.cs @@ -0,0 +1,58 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Core.Configuration +{ + using System; + using System.Collections.Generic; + + /// + /// A collection of objects. + /// +#if FEATURE_SERIALIZATION + [Serializable] +#endif + public class ConfigurationCollection : List + { + /// + /// Creates a new instance of ConfigurationCollection. + /// + public ConfigurationCollection() + { + } + + /// + /// Creates a new instance of ConfigurationCollection. + /// + public ConfigurationCollection(IEnumerable value) : base(value) + { + } + + public IConfiguration this[string name] + { + get + { + foreach(IConfiguration config in this) + { + if (name.Equals(config.Name)) + { + return config; + } + } + + return null; + } + } + } +} \ No newline at end of file diff --git a/Castle.Core/Core/Configuration/IConfiguration.cs b/Castle.Core/Core/Configuration/IConfiguration.cs new file mode 100644 index 0000000..935b9e4 --- /dev/null +++ b/Castle.Core/Core/Configuration/IConfiguration.cs @@ -0,0 +1,65 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Core.Configuration +{ + using System; + using System.Collections; + + /// + /// is a interface encapsulating a configuration node + /// used to retrieve configuration values. + /// + public interface IConfiguration + { + /// + /// Gets the name of the node. + /// + /// + /// The Name of the node. + /// + string Name { get; } + + /// + /// Gets the value of the node. + /// + /// + /// The Value of the node. + /// + string Value { get; } + + /// + /// Gets an of + /// elements containing all node children. + /// + /// The Collection of child nodes. + ConfigurationCollection Children { get; } + + /// + /// Gets an of the configuration attributes. + /// + ConfigurationAttributeCollection Attributes { get; } + + /// + /// Gets the value of the node and converts it + /// into specified . + /// + /// The + /// + /// The Default value returned if the conversion fails. + /// + /// The Value converted into the specified type. + object GetValue(Type type, object defaultValue); + } +} \ No newline at end of file diff --git a/Castle.Core/Core/Configuration/MutableConfiguration.cs b/Castle.Core/Core/Configuration/MutableConfiguration.cs new file mode 100644 index 0000000..f21ea90 --- /dev/null +++ b/Castle.Core/Core/Configuration/MutableConfiguration.cs @@ -0,0 +1,75 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Core.Configuration +{ + using System; + +#if FEATURE_SERIALIZATION + [Serializable] +#endif + public class MutableConfiguration : AbstractConfiguration + { + /// + /// Initializes a new instance of the class. + /// + /// The name. + public MutableConfiguration(string name) : this(name, null) + { + } + + public MutableConfiguration(string name, string value) + { + Name = name; + Value = value; + } + + /// + /// Gets the value of . + /// + /// + /// The Value of the . + /// + public new string Value + { + get { return base.Value; } + set { base.Value = value; } + } + + public static MutableConfiguration Create(string name) + { + return new MutableConfiguration(name); + } + + public MutableConfiguration Attribute(string name, string value) + { + Attributes[name] = value; + return this; + } + + public MutableConfiguration CreateChild(string name) + { + MutableConfiguration child = new MutableConfiguration(name); + Children.Add(child); + return child; + } + + public MutableConfiguration CreateChild(string name, string value) + { + MutableConfiguration child = new MutableConfiguration(name, value); + Children.Add(child); + return child; + } + } +} \ No newline at end of file diff --git a/Castle.Core/Core/Configuration/Xml/XmlConfigurationDeserializer.cs b/Castle.Core/Core/Configuration/Xml/XmlConfigurationDeserializer.cs new file mode 100644 index 0000000..322f996 --- /dev/null +++ b/Castle.Core/Core/Configuration/Xml/XmlConfigurationDeserializer.cs @@ -0,0 +1,80 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Core.Configuration.Xml +{ + using System.Text; + using System.Xml; + + public class XmlConfigurationDeserializer + { + /// + /// Deserializes the specified node into an abstract representation of configuration. + /// + /// The node. + public IConfiguration Deserialize(XmlNode node) + { + return GetDeserializedNode(node); + } + + /// + /// If a config value is an empty string we return null, this is to keep + /// backward compatibility with old code + /// + public static string GetConfigValue(string value) + { + if (value == string.Empty) + { + return null; + } + return value; + } + + public static IConfiguration GetDeserializedNode(XmlNode node) + { + var configChilds = new ConfigurationCollection(); + + var configValue = new StringBuilder(); + if (node.HasChildNodes) + { + foreach (XmlNode child in node.ChildNodes) + { + if (IsTextNode(child)) + { + configValue.Append(child.Value); + } + else if (child.NodeType == XmlNodeType.Element) + { + configChilds.Add(GetDeserializedNode(child)); + } + } + } + + var config = new MutableConfiguration(node.Name, GetConfigValue(configValue.ToString())); + foreach (XmlAttribute attribute in node.Attributes) + { + config.Attributes.Add(attribute.Name, attribute.Value); + } + + config.Children.AddRange(configChilds); + + return config; + } + + public static bool IsTextNode(XmlNode node) + { + return node.NodeType == XmlNodeType.Text || node.NodeType == XmlNodeType.CDATA; + } + } +} diff --git a/Castle.Core/Core/IServiceEnabledComponent.cs b/Castle.Core/Core/IServiceEnabledComponent.cs new file mode 100644 index 0000000..4e0acec --- /dev/null +++ b/Castle.Core/Core/IServiceEnabledComponent.cs @@ -0,0 +1,34 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Core +{ + using System; + + /// + /// Defines that the implementation wants a + /// in order to + /// access other components. The creator must be aware + /// that the component might (or might not) implement + /// the interface. + /// + /// + /// Used by Castle Project components to, for example, + /// gather logging factories + /// + public interface IServiceEnabledComponent + { + void Service(IServiceProvider provider); + } +} \ No newline at end of file diff --git a/Castle.Core/Core/IServiceProviderEx.cs b/Castle.Core/Core/IServiceProviderEx.cs new file mode 100644 index 0000000..8e81158 --- /dev/null +++ b/Castle.Core/Core/IServiceProviderEx.cs @@ -0,0 +1,26 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Core +{ + using System; + + /// + /// Increments IServiceProvider with a generic service resolution operation. + /// + public interface IServiceProviderEx : IServiceProvider + { + T GetService() where T : class; + } +} diff --git a/Castle.Core/Core/IServiceProviderExAccessor.cs b/Castle.Core/Core/IServiceProviderExAccessor.cs new file mode 100644 index 0000000..6e04b8c --- /dev/null +++ b/Castle.Core/Core/IServiceProviderExAccessor.cs @@ -0,0 +1,31 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Core +{ + /// + /// This interface should be implemented by classes + /// that are available in a bigger context, exposing + /// the container to different areas in the same application. + /// + /// For example, in Web application, the (global) HttpApplication + /// subclasses should implement this interface to expose + /// the configured container + /// + /// + public interface IServiceProviderExAccessor + { + IServiceProviderEx ServiceProvider { get; } + } +} \ No newline at end of file diff --git a/Castle.Core/Core/Internal/AttributesUtil.cs b/Castle.Core/Core/Internal/AttributesUtil.cs new file mode 100644 index 0000000..0455420 --- /dev/null +++ b/Castle.Core/Core/Internal/AttributesUtil.cs @@ -0,0 +1,146 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Core.Internal +{ + using System; + using System.Collections.Generic; + using System.ComponentModel; + using System.Linq; + using System.Reflection; + + /// + /// Helper class for retrieving attributes. + /// + public static class AttributesUtil + { + /// + /// Gets the attribute. + /// + /// The type. + /// The type attribute. + public static T GetAttribute(this Type type) where T : Attribute + { + return GetAttributes(type).FirstOrDefault(); + } + + /// + /// Gets the attributes. Does not consider inherited attributes! + /// + /// The type. + /// The type attributes. + public static IEnumerable GetAttributes(this Type type) where T : Attribute + { + foreach (T a in type.GetCustomAttributes(typeof(T), false)) + { + yield return a; + } + } + + /// + /// Gets the attribute. + /// + /// The member. + /// The member attribute. + public static T GetAttribute(this MemberInfo member) where T : Attribute + { + return GetAttributes(member).FirstOrDefault(); + } + + /// + /// Gets the attributes. Does not consider inherited attributes! + /// + /// The member. + /// The member attributes. + public static IEnumerable GetAttributes(this MemberInfo member) where T : Attribute + { + foreach (T a in member.GetCustomAttributes(typeof(T), false)) + { + yield return a; + } + } + + /// + /// Gets the type attribute. + /// + /// The type. + /// The type attribute. + public static T GetTypeAttribute(this Type type) where T : Attribute + { + var attribute = GetAttribute(type); + + if (attribute == null) + { + foreach (var baseInterface in type.GetInterfaces()) + { + attribute = GetTypeAttribute(baseInterface); + if (attribute != null) + { + break; + } + } + } + + return attribute; + } + + /// + /// Gets the type attributes. + /// + /// The type. + /// The type attributes. + public static T[] GetTypeAttributes(Type type) where T : Attribute + { + var attributes = GetAttributes(type).ToArray(); + + if (attributes.Length == 0) + { + foreach (var baseInterface in type.GetInterfaces()) + { + attributes = GetTypeAttributes(baseInterface); + if (attributes.Length > 0) + { + break; + } + } + } + + return attributes; + } + + public static AttributeUsageAttribute GetAttributeUsage(this Type attributeType) + { + var attributes = attributeType.GetCustomAttributes(true).ToArray(); + return attributes.Length != 0 ? attributes[0] : DefaultAttributeUsage; + } + + private static readonly AttributeUsageAttribute DefaultAttributeUsage = new AttributeUsageAttribute(AttributeTargets.All); + + /// + /// Gets the type converter. + /// + /// The member. + public static Type GetTypeConverter(MemberInfo member) + { + var attrib = GetAttribute(member); + + if (attrib != null) + { + return Type.GetType(attrib.ConverterTypeName); + } + + return null; + } + } +} \ No newline at end of file diff --git a/Castle.Core/Core/Internal/InterfaceAttributeUtil.cs b/Castle.Core/Core/Internal/InterfaceAttributeUtil.cs new file mode 100644 index 0000000..8943bf2 --- /dev/null +++ b/Castle.Core/Core/Internal/InterfaceAttributeUtil.cs @@ -0,0 +1,190 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Core.Internal +{ + using System; + using System.Collections.Generic; + using System.Diagnostics; + using System.Linq; + using System.Reflection; + + internal sealed class InterfaceAttributeUtil + { + private readonly Aged[] types; // in order from most to least derived + private readonly Dictionary> singletons; + private readonly List results; + + private int index; + + private Type CurrentType + { + get { return types[index].Value; } + } + + private int CurrentAge + { + get { return types[index].Age; } + } + + private bool IsMostDerivedType + { + get { return index == 0; } + } + + public static object[] GetAttributes(Type type, bool inherit) + { + if (type.IsInterface == false) + throw new ArgumentOutOfRangeException(nameof(type)); + + var attributes = type.GetCustomAttributes(false).ToArray(); + var baseTypes = type.GetInterfaces(); + + if (baseTypes.Length == 0 || !inherit) + return attributes; + + return new InterfaceAttributeUtil(type, baseTypes) + .GetAttributes(attributes); + } + + private InterfaceAttributeUtil(Type derivedType, Type[] baseTypes) + { + types = CollectTypes(derivedType, baseTypes); + singletons = new Dictionary>(); + results = new List(); + } + + private Aged[] CollectTypes(Type derivedType, Type[] baseTypes) + { + var ages = new Dictionary(); + int age; + + ages[derivedType] = 0; + + foreach (var baseType in baseTypes) + if (ShouldConsiderType(baseType)) + ages[baseType] = 1; + + foreach (var baseType in baseTypes) + if (ages.ContainsKey(baseType)) + foreach (var type in baseType.GetInterfaces()) + if (ages.TryGetValue(type, out age)) + ages[type] = ++age; + + return ages + .Select (a => new Aged(a.Key, a.Value)) + .OrderBy(t => t.Age) + .ToArray(); + } + + private object[] GetAttributes(object[] attributes) + { + for (index = types.Length - 1; index > 0; index--) + ProcessType(CurrentType.GetCustomAttributes(false).ToArray()); + + ProcessType(attributes); + + CollectSingletons(); + return results.ToArray(); + } + + private void ProcessType(object[] attributes) + { + foreach (var attribute in attributes) + { + var attributeType = attribute.GetType(); + var attributeUsage = attributeType.GetAttributeUsage(); + + if (IsMostDerivedType || attributeUsage.Inherited) + { + if (attributeUsage.AllowMultiple) + results.Add(attribute); + else + AddSingleton(attribute, attributeType); + } + } + } + + private void AddSingleton(object attribute, Type attributeType) + { + Aged singleton; + if (singletons.TryGetValue(attributeType, out singleton)) + { + if (singleton.Age == CurrentAge) + { + if (singleton.Value == ConflictMarker) + return; // already in conflict + else + attribute = ConflictMarker; + } + } + + singletons[attributeType] = MakeAged(attribute); + } + + private void CollectSingletons() + { + foreach (var entry in singletons) + { + var attribute = entry.Value.Value; + + if (attribute == ConflictMarker) + HandleAttributeConflict(entry.Key); + else + results.Add(attribute); + } + } + + private void HandleAttributeConflict(Type attributeType) + { + var message = string.Format + ( + "Cannot determine inherited attributes for interface type {0}. " + + "Conflicting attributes of type {1} exist in the inheritance graph.", + CurrentType .FullName, + attributeType.FullName + ); + + throw new InvalidOperationException(message); + } + + private static bool ShouldConsiderType(Type type) + { + var ns = type.Namespace; + return ns != "Castle.Components.DictionaryAdapter" + && ns != "System.ComponentModel"; + } + + private Aged MakeAged(T value) + { + return new Aged(value, CurrentAge); + } + + [DebuggerDisplay("{Value}, Age: {Age}")] + private sealed class Aged + { + public readonly T Value; + public readonly int Age; + + public Aged(T value, int age) + { + Value = value; + Age = age; + } + } + + private static readonly object + ConflictMarker = new object(); + } +} diff --git a/Castle.Core/Core/Internal/InternalsVisible.cs b/Castle.Core/Core/Internal/InternalsVisible.cs new file mode 100644 index 0000000..d735a6d --- /dev/null +++ b/Castle.Core/Core/Internal/InternalsVisible.cs @@ -0,0 +1,47 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Core.Internal +{ + public class InternalsVisible + { + /// + /// Constant to use when making assembly internals visible to Castle.Core + /// [assembly: InternalsVisibleTo(CoreInternalsVisible.ToCastleCore)] + /// + public const string ToCastleCore = + "Castle.Core, PublicKey=002400000480000094000000060200000024000052534131000400000100010077F5E87030DADCCCE6902C6ADAB7A987BD69CB5819991531F560785EACFC89B6FCDDF6BB2A00743A7194E454C0273447FC6EEC36474BA8E5A3823147D214298E4F9A631B1AFEE1A51FFEAE4672D498F14B000E3D321453CDD8AC064DE7E1CF4D222B7E81F54D4FD46725370D702A05B48738CC29D09228F1AA722AE1A9CA02FB"; + + /// + /// Constant to use when making assembly internals visible to proxy types generated by DynamicProxy. Required when proxying internal types. + /// [assembly: InternalsVisibleTo(CoreInternalsVisible.ToDynamicProxyGenAssembly2)] + /// + public const string ToDynamicProxyGenAssembly2 = + "DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7"; + + internal static readonly byte[] DynamicProxyGenAssembly2PublicKey = + { + 0x00, 0x24, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x06, 0x02, 0x00, 0x00, + 0x00, 0x24, 0x00, 0x00, 0x52, 0x53, 0x41, 0x31, 0x00, 0x04, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, + 0xc5, 0x47, 0xca, 0xc3, 0x7a, 0xbd, 0x99, 0xc8, 0xdb, 0x22, 0x5e, 0xf2, 0xf6, 0xc8, 0xa3, 0x60, + 0x2f, 0x3b, 0x36, 0x06, 0xcc, 0x98, 0x91, 0x60, 0x5d, 0x02, 0xba, 0xa5, 0x61, 0x04, 0xf4, 0xcf, + 0xc0, 0x73, 0x4a, 0xa3, 0x9b, 0x93, 0xbf, 0x78, 0x52, 0xf7, 0xd9, 0x26, 0x66, 0x54, 0x75, 0x3c, + 0xc2, 0x97, 0xe7, 0xd2, 0xed, 0xfe, 0x0b, 0xac, 0x1c, 0xdc, 0xf9, 0xf7, 0x17, 0x24, 0x15, 0x50, + 0xe0, 0xa7, 0xb1, 0x91, 0x19, 0x5b, 0x76, 0x67, 0xbb, 0x4f, 0x64, 0xbc, 0xb8, 0xe2, 0x12, 0x13, + 0x80, 0xfd, 0x1d, 0x9d, 0x46, 0xad, 0x2d, 0x92, 0xd2, 0xd1, 0x56, 0x05, 0x09, 0x39, 0x24, 0xcc, + 0xea, 0xf7, 0x4c, 0x48, 0x61, 0xef, 0xf6, 0x2a, 0xbf, 0x69, 0xb9, 0x29, 0x1e, 0xd0, 0xa3, 0x40, + 0xe1, 0x13, 0xbe, 0x11, 0xe6, 0xa7, 0xd3, 0x11, 0x3e, 0x92, 0x48, 0x4c, 0xf7, 0x04, 0x5c, 0xc7 + }; + } +} \ No newline at end of file diff --git a/Castle.Core/Core/Internal/SynchronizedDictionary.cs b/Castle.Core/Core/Internal/SynchronizedDictionary.cs new file mode 100644 index 0000000..4f354f3 --- /dev/null +++ b/Castle.Core/Core/Internal/SynchronizedDictionary.cs @@ -0,0 +1,120 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Core.Internal +{ + using System; + using System.Collections.Generic; + using System.Threading; + + internal sealed class SynchronizedDictionary : IDisposable + { + private Dictionary items; + private ReaderWriterLockSlim itemsLock; + + public SynchronizedDictionary() + { + items = new Dictionary(); + itemsLock = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion); + } + + public void AddOrUpdateWithoutTakingLock(TKey key, TValue value) + { + items[key] = value; + } + + public void Dispose() + { + itemsLock.Dispose(); + } + + public TValue GetOrAdd(TKey key, Func valueFactory) + { + TValue value; + + itemsLock.EnterReadLock(); + try + { + if (items.TryGetValue(key, out value)) + { + return value; + } + } + finally + { + itemsLock.ExitReadLock(); + } + + itemsLock.EnterUpgradeableReadLock(); + try + { + if (items.TryGetValue(key, out value)) + { + return value; + } + else + { + value = valueFactory.Invoke(key); + + itemsLock.EnterWriteLock(); + try + { + items.Add(key, value); + return value; + } + finally + { + itemsLock.ExitWriteLock(); + } + } + } + finally + { + itemsLock.ExitUpgradeableReadLock(); + } + } + + public TValue GetOrAddWithoutTakingLock(TKey key, Func valueFactory) + { + TValue value; + + if (items.TryGetValue(key, out value)) + { + return value; + } + else + { + value = valueFactory.Invoke(key); + items.Add(key, value); + return value; + } + } + + public void ForEach(Action action) + { + itemsLock.EnterReadLock(); + try + { + foreach (var item in items) + { + action.Invoke(item.Key, item.Value); + } + } + finally + { + itemsLock.ExitReadLock(); + } + } + } +} diff --git a/Castle.Core/Core/Internal/TypeExtensions.cs b/Castle.Core/Core/Internal/TypeExtensions.cs new file mode 100644 index 0000000..a89e1d9 --- /dev/null +++ b/Castle.Core/Core/Internal/TypeExtensions.cs @@ -0,0 +1,37 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Core.Internal +{ + using System; + using System.Reflection; + + internal static class TypeExtensions + { + /// + /// Find the best available name to describe a type. + /// + /// + /// Usually the best name will be , but + /// sometimes that's null (see http://msdn.microsoft.com/en-us/library/system.type.fullname%28v=vs.110%29.aspx) + /// in which case the method falls back to . + /// + /// the type to name + /// the best name + public static string GetBestName(this Type type) + { + return type.FullName ?? type.Name; + } + } +} diff --git a/Castle.Core/Core/Internal/WeakKey.cs b/Castle.Core/Core/Internal/WeakKey.cs new file mode 100644 index 0000000..26de6a1 --- /dev/null +++ b/Castle.Core/Core/Internal/WeakKey.cs @@ -0,0 +1,45 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Core.Internal +{ + using System; + + internal sealed class WeakKey : WeakReference + { + private readonly int hashCode; + + public WeakKey(object target, int hashCode) + : base(target) + { + this.hashCode = hashCode; + } + + public override object Target + { + get { return base.Target; } + set { throw new NotSupportedException("Dictionary keys are read-only."); } + } + + public override int GetHashCode() + { + return hashCode; + } + + public override bool Equals(object other) + { + return WeakKeyComparer.Default.Equals(this, other); + } + } +} \ No newline at end of file diff --git a/Castle.Core/Core/Internal/WeakKeyComparer.cs b/Castle.Core/Core/Internal/WeakKeyComparer.cs new file mode 100644 index 0000000..369a103 --- /dev/null +++ b/Castle.Core/Core/Internal/WeakKeyComparer.cs @@ -0,0 +1,71 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Core.Internal +{ + using System; + using System.Collections.Generic; + + internal class WeakKeyComparer : IEqualityComparer + where TKey : class + { + public static readonly WeakKeyComparer + Default = new WeakKeyComparer(EqualityComparer.Default); + + private readonly IEqualityComparer comparer; + + public WeakKeyComparer(IEqualityComparer comparer) + { + if (comparer == null) + throw new ArgumentNullException(nameof(comparer)); + + this.comparer = comparer; + } + + public object Wrap(TKey key) + { + return new WeakKey(key, comparer.GetHashCode(key)); + } + + public TKey Unwrap(object obj) + { + var weak = obj as WeakKey; + return (weak != null) + ? (TKey) weak.Target + : (TKey) obj; + } + + public int GetHashCode(object obj) + { + var weak = obj as WeakKey; + return (weak != null) + ? weak .GetHashCode() + : comparer.GetHashCode((TKey) obj); + } + + public new bool Equals(object objA, object objB) + { + var keyA = Unwrap(objA); + var keyB = Unwrap(objB); + + return (keyA != null) + ? (keyB != null) + ? comparer.Equals(keyA, keyB) + : false // live object cannot equal a collected object + : (keyB != null) + ? false // live object cannot equal a collected object + : ReferenceEquals(objA, objB); + } + } +} \ No newline at end of file diff --git a/Castle.Core/Core/Internal/WeakKeyDictionary.cs b/Castle.Core/Core/Internal/WeakKeyDictionary.cs new file mode 100644 index 0000000..a96ad10 --- /dev/null +++ b/Castle.Core/Core/Internal/WeakKeyDictionary.cs @@ -0,0 +1,246 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Core.Internal +{ + using System; + using System.Collections; + using System.Collections.Generic; + + internal class WeakKeyDictionary : IDictionary + where TKey : class + { + private readonly Dictionary dictionary; + private readonly WeakKeyComparer comparer; + private KeyCollection keys; + + private int age; // Incremented by operations + private const int AgeThreshold = 128; // Age at which to trim dead objects + + public WeakKeyDictionary() + : this(0, EqualityComparer.Default) { } + + public WeakKeyDictionary(int capacity) + : this(capacity, EqualityComparer.Default) { } + + public WeakKeyDictionary(IEqualityComparer comparer) + : this(0, comparer) { } + + public WeakKeyDictionary(int capacity, IEqualityComparer comparer) + { + this.comparer = new WeakKeyComparer(comparer); + this.dictionary = new Dictionary(capacity, this.comparer); + } + + public int Count + { + get { Age(1); return dictionary.Count; } + } + + bool ICollection>.IsReadOnly + { + get { return false; } + } + + public ICollection Keys + { + get { return keys ?? (keys = new KeyCollection(dictionary.Keys)); } + } + + public ICollection Values + { + get { return dictionary.Values; } + } + + public TValue this[TKey key] + { + get { Age(1); return dictionary[key]; } + set { Age(4); dictionary[comparer.Wrap(key)] = value; } + } + + public bool ContainsKey(TKey key) + { + Age(1); + return dictionary.ContainsKey(key); + } + + bool ICollection>.Contains(KeyValuePair item) + { + Age(1); + TValue candidate; + return dictionary.TryGetValue(item.Key, out candidate) + && EqualityComparer.Default.Equals(candidate, item.Value); + } + + public bool TryGetValue(TKey key, out TValue value) + { + Age(1); + return dictionary.TryGetValue(key, out value); + } + + public IEnumerator> GetEnumerator() + { + var hasDeadObjects = false; + + foreach (var wrapped in dictionary) + { + var item = new KeyValuePair + ( + comparer.Unwrap(wrapped.Key), + wrapped.Value + ); + + if (item.Key == null) + hasDeadObjects = true; + else + yield return item; + } + + if (hasDeadObjects) + TrimDeadObjects(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public void CopyTo(KeyValuePair[] array, int index) + { + foreach (var item in this) + array[index++] = item; + } + + public void Add(TKey key, TValue value) + { + Age(2); + dictionary.Add(comparer.Wrap(key), value); + } + + void ICollection>.Add(KeyValuePair item) + { + Add(item.Key, item.Value); + } + + public bool Remove(TKey key) + { + Age(4); + return dictionary.Remove(key); + } + + bool ICollection>.Remove(KeyValuePair item) + { + ICollection> collection = this; + return collection.Contains(item) && Remove(item.Key); + } + + public void Clear() + { + age = 0; + dictionary.Clear(); + } + + private void Age(int amount) + { + if ((age += amount) > AgeThreshold) + TrimDeadObjects(); + } + + public void TrimDeadObjects() + { + age = 0; + var removals = null as List; + + foreach (var key in dictionary.Keys) + { + if (comparer.Unwrap(key) == null) + { + if (removals == null) + removals = new List(); + removals.Add(key); + } + } + + if (removals != null) + foreach (var key in removals) + dictionary.Remove(key); + } + + private class KeyCollection : ICollection + { + private readonly ICollection keys; + + public KeyCollection(ICollection keys) + { + this.keys = keys; + } + + public int Count + { + get { return keys.Count; } + } + + bool ICollection.IsReadOnly + { + get { return true; } + } + + public bool Contains(TKey item) + { + return keys.Contains(item); + } + + public IEnumerator GetEnumerator() + { + foreach (var key in keys) + { + var target = (TKey) ((WeakKey) key).Target; + if (target != null) + yield return target; + } + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public void CopyTo(TKey[] array, int index) + { + foreach (var key in this) + array[index++] = key; + } + + void ICollection.Add(TKey item) + { + throw ReadOnlyCollectionError(); + } + + bool ICollection.Remove(TKey item) + { + throw ReadOnlyCollectionError(); + } + + void ICollection.Clear() + { + throw ReadOnlyCollectionError(); + } + + private static Exception ReadOnlyCollectionError() + { + return new NotSupportedException("The collection is read-only."); + } + } + } +} \ No newline at end of file diff --git a/Castle.Core/Core/Logging/AbstractExtendedLoggerFactory.cs b/Castle.Core/Core/Logging/AbstractExtendedLoggerFactory.cs new file mode 100644 index 0000000..8e7f423 --- /dev/null +++ b/Castle.Core/Core/Logging/AbstractExtendedLoggerFactory.cs @@ -0,0 +1,111 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Core.Logging +{ + using System; + using System.IO; + + public abstract class AbstractExtendedLoggerFactory : IExtendedLoggerFactory + { + /// + /// Creates a new extended logger, getting the logger name from the specified type. + /// + public virtual IExtendedLogger Create(Type type) + { + if (type == null) + { + throw new ArgumentNullException(nameof(type)); + } + + return Create(type.FullName); + } + + /// + /// Creates a new extended logger. + /// + public abstract IExtendedLogger Create(string name); + + /// + /// Creates a new extended logger, getting the logger name from the specified type. + /// + public virtual IExtendedLogger Create(Type type, LoggerLevel level) + { + if (type == null) + { + throw new ArgumentNullException(nameof(type)); + } + + return Create(type.FullName, level); + } + + /// + /// Creates a new extended logger. + /// + public abstract IExtendedLogger Create(string name, LoggerLevel level); + + /// + /// Creates a new logger, getting the logger name from the specified type. + /// + ILogger ILoggerFactory.Create(Type type) + { + return Create(type); + } + + /// + /// Creates a new logger. + /// + ILogger ILoggerFactory.Create(string name) + { + return Create(name); + } + + /// + /// Creates a new logger, getting the logger name from the specified type. + /// + ILogger ILoggerFactory.Create(Type type, LoggerLevel level) + { + return Create(type, level); + } + + /// + /// Creates a new logger. + /// + ILogger ILoggerFactory.Create(string name, LoggerLevel level) + { + return Create(name, level); + } + + /// + /// Gets the configuration file. + /// + /// i.e. log4net.config + protected static FileInfo GetConfigFile(string fileName) + { + FileInfo result; + + if (Path.IsPathRooted(fileName)) + { + result = new FileInfo(fileName); + } + else + { + string baseDirectory = AppDomain.CurrentDomain.BaseDirectory; + result = new FileInfo(Path.Combine(baseDirectory, fileName)); + } + + return result; + } + } +} \ No newline at end of file diff --git a/Castle.Core/Core/Logging/AbstractLoggerFactory.cs b/Castle.Core/Core/Logging/AbstractLoggerFactory.cs new file mode 100644 index 0000000..f5da938 --- /dev/null +++ b/Castle.Core/Core/Logging/AbstractLoggerFactory.cs @@ -0,0 +1,70 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Core.Logging +{ + using System; + using System.IO; + +#if FEATURE_SERIALIZATION + [Serializable] +#endif + public abstract class AbstractLoggerFactory : ILoggerFactory + { + public virtual ILogger Create(Type type) + { + if (type == null) + { + throw new ArgumentNullException(nameof(type)); + } + + return Create(type.FullName); + } + + public virtual ILogger Create(Type type, LoggerLevel level) + { + if (type == null) + { + throw new ArgumentNullException(nameof(type)); + } + + return Create(type.FullName, level); + } + + public abstract ILogger Create(string name); + + public abstract ILogger Create(string name, LoggerLevel level); + + /// + /// Gets the configuration file. + /// + /// i.e. log4net.config + protected static FileInfo GetConfigFile(string fileName) + { + FileInfo result; + + if (Path.IsPathRooted(fileName)) + { + result = new FileInfo(fileName); + } + else + { + string baseDirectory = AppDomain.CurrentDomain.BaseDirectory; + result = new FileInfo(Path.Combine(baseDirectory, fileName)); + } + + return result; + } + } +} \ No newline at end of file diff --git a/Castle.Core/Core/Logging/ConsoleFactory.cs b/Castle.Core/Core/Logging/ConsoleFactory.cs new file mode 100644 index 0000000..c456888 --- /dev/null +++ b/Castle.Core/Core/Logging/ConsoleFactory.cs @@ -0,0 +1,59 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Core.Logging +{ + using System; + +#if FEATURE_SERIALIZATION + [Serializable] +#endif + public class ConsoleFactory : ILoggerFactory + { + private LoggerLevel? level; + + public ConsoleFactory() + { + } + + public ConsoleFactory(LoggerLevel level) + { + this.level = level; + } + + public ILogger Create(Type type) + { + return Create(type.FullName); + } + + public ILogger Create(string name) + { + if (level.HasValue) + { + return Create(name, level.Value); + } + return new ConsoleLogger(name); + } + + public ILogger Create(Type type, LoggerLevel level) + { + return new ConsoleLogger(type.Name, level); + } + + public ILogger Create(string name, LoggerLevel level) + { + return new ConsoleLogger(name, level); + } + } +} \ No newline at end of file diff --git a/Castle.Core/Core/Logging/ConsoleLogger.cs b/Castle.Core/Core/Logging/ConsoleLogger.cs new file mode 100644 index 0000000..277b48f --- /dev/null +++ b/Castle.Core/Core/Logging/ConsoleLogger.cs @@ -0,0 +1,100 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Core.Logging +{ + using System; + using System.Globalization; + + /// + /// The Logger sending everything to the standard output streams. + /// This is mainly for the cases when you have a utility that + /// does not have a logger to supply. + /// +#if FEATURE_SERIALIZATION + [Serializable] +#endif + public class ConsoleLogger : LevelFilteredLogger + { + /// + /// Creates a new ConsoleLogger with the Level + /// set to LoggerLevel.Debug and the Name + /// set to string.Empty. + /// + public ConsoleLogger() : this(string.Empty, LoggerLevel.Debug) + { + } + + /// + /// Creates a new ConsoleLogger with the Name + /// set to string.Empty. + /// + /// The logs Level. + public ConsoleLogger(LoggerLevel logLevel) : this(string.Empty, logLevel) + { + } + + /// + /// Creates a new ConsoleLogger with the Level + /// set to LoggerLevel.Debug. + /// + /// The logs Name. + public ConsoleLogger(string name) : this(name, LoggerLevel.Debug) + { + } + + /// + /// Creates a new ConsoleLogger. + /// + /// The logs Name. + /// The logs Level. + public ConsoleLogger(string name, LoggerLevel logLevel) : base(name, logLevel) + { + } + + /// + /// A Common method to log. + /// + /// The level of logging + /// The name of the logger + /// The Message + /// The Exception + protected override void Log(LoggerLevel loggerLevel, string loggerName, string message, Exception exception) + { + Console.Out.WriteLine("[{0}] '{1}' {2}", loggerLevel, loggerName, message); + + if (exception != null) + { + Console.Out.WriteLine("[{0}] '{1}' {2}: {3} {4}", loggerLevel, loggerName, exception.GetType().FullName, + exception.Message, exception.StackTrace); + } + } + + /// + /// Returns a new ConsoleLogger with the name + /// added after this loggers name, with a dot in between. + /// + ///The added hierarchical name. + ///A new ConsoleLogger. + public override ILogger CreateChildLogger(string loggerName) + { + if (loggerName == null) + { + throw new ArgumentNullException(nameof(loggerName), "To create a child logger you must supply a non null name"); + } + + return new ConsoleLogger(string.Format(CultureInfo.CurrentCulture, "{0}.{1}", Name, loggerName), Level); + } + } +} \ No newline at end of file diff --git a/Castle.Core/Core/Logging/DiagnosticsLogger.cs b/Castle.Core/Core/Logging/DiagnosticsLogger.cs new file mode 100644 index 0000000..259747b --- /dev/null +++ b/Castle.Core/Core/Logging/DiagnosticsLogger.cs @@ -0,0 +1,146 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Core.Logging +{ + using System; + using System.Diagnostics; + using System.Globalization; + + /// + /// The Logger using standard Diagnostics namespace. + /// +#if FEATURE_SERIALIZATION + [Serializable] +#endif + public class DiagnosticsLogger : LevelFilteredLogger, IDisposable + { +#if FEATURE_SERIALIZATION + [NonSerialized] +#endif + private EventLog eventLog; + + /// + /// Creates a logger based on . + /// + /// + public DiagnosticsLogger(string logName) : this(logName, "default") + { + } + + /// + /// Creates a logger based on . + /// + /// + /// + public DiagnosticsLogger(string logName, string source) : base(LoggerLevel.Trace) + { + // Create the source, if it does not already exist. + if (!EventLog.SourceExists(source)) + { + EventLog.CreateEventSource(source, logName); + } + + eventLog = new EventLog(logName); + eventLog.Source = source; + } + + /// + /// Creates a logger based on . + /// + /// + /// + /// + public DiagnosticsLogger(string logName, string machineName, string source) + { + // Create the source, if it does not already exist. + if (!EventLog.SourceExists(source, machineName)) + { + var eventSourceCreationData = new EventSourceCreationData(source, logName); + eventSourceCreationData.MachineName = machineName; + EventLog.CreateEventSource(eventSourceCreationData); + } + + eventLog = new EventLog(logName, machineName, source); + } + + public override ILogger CreateChildLogger(string loggerName) + { + return new DiagnosticsLogger(eventLog.Log, eventLog.MachineName, eventLog.Source); + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + if (eventLog != null) + { + eventLog.Close(); + eventLog = null; + } + } + } + + protected override void Log(LoggerLevel loggerLevel, string loggerName, string message, Exception exception) + { + if (eventLog == null) + { + return; // just in case it was disposed + } + + var type = TranslateLevel(loggerLevel); + + string contentToLog; + + if (exception == null) + { + contentToLog = string.Format(CultureInfo.CurrentCulture, "[{0}] '{1}' message: {2}", loggerLevel, loggerName, + message); + } + else + { + contentToLog = string.Format(CultureInfo.CurrentCulture, "[{0}] '{1}' message: {2} exception: {3} {4} {5}", + loggerLevel, loggerName, message, exception.GetType(), exception.Message, + exception.StackTrace); + } + + eventLog.WriteEntry(contentToLog, type); + } + + ~DiagnosticsLogger() + { + Dispose(false); + } + + private static EventLogEntryType TranslateLevel(LoggerLevel level) + { + switch (level) + { + case LoggerLevel.Error: + case LoggerLevel.Fatal: + return EventLogEntryType.Error; + case LoggerLevel.Warn: + return EventLogEntryType.Warning; + default: + return EventLogEntryType.Information; + } + } + } +} diff --git a/Castle.Core/Core/Logging/DiagnosticsLoggerFactory.cs b/Castle.Core/Core/Logging/DiagnosticsLoggerFactory.cs new file mode 100644 index 0000000..78731f1 --- /dev/null +++ b/Castle.Core/Core/Logging/DiagnosticsLoggerFactory.cs @@ -0,0 +1,38 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Core.Logging +{ + using System; + +#if FEATURE_SERIALIZATION + [Serializable] +#endif + public class DiagnosticsLoggerFactory : AbstractLoggerFactory + { + private const string DefaultLogName = "CastleDefaultLogger"; + + public override ILogger Create(string name) + { + return new DiagnosticsLogger(DefaultLogName, name); + } + + public override ILogger Create(string name, LoggerLevel level) + { + var logger = new DiagnosticsLogger(DefaultLogName, name); + logger.Level = level; + return logger; + } + } +} diff --git a/Castle.Core/Core/Logging/IContextProperties.cs b/Castle.Core/Core/Logging/IContextProperties.cs new file mode 100644 index 0000000..9944c53 --- /dev/null +++ b/Castle.Core/Core/Logging/IContextProperties.cs @@ -0,0 +1,43 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Core.Logging +{ + /// + /// Interface for Context Properties implementations + /// + /// + /// + /// This interface defines a basic property get set accessor. + /// + /// + /// Based on the ContextPropertiesBase of log4net, by Nicko Cadell. + /// + /// + public interface IContextProperties + { + /// + /// Gets or sets the value of a property + /// + /// + /// The value for the property with the specified key + /// + /// + /// + /// Gets or sets the value of a property + /// + /// + object this[string key] { get; set; } + } +} \ No newline at end of file diff --git a/Castle.Core/Core/Logging/IContextStack.cs b/Castle.Core/Core/Logging/IContextStack.cs new file mode 100644 index 0000000..9d214a9 --- /dev/null +++ b/Castle.Core/Core/Logging/IContextStack.cs @@ -0,0 +1,29 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Core.Logging +{ + using System; + + public interface IContextStack + { + int Count { get; } + + void Clear(); + + string Pop(); + + IDisposable Push(string message); + } +} \ No newline at end of file diff --git a/Castle.Core/Core/Logging/IContextStacks.cs b/Castle.Core/Core/Logging/IContextStacks.cs new file mode 100644 index 0000000..6b8f2f4 --- /dev/null +++ b/Castle.Core/Core/Logging/IContextStacks.cs @@ -0,0 +1,21 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Core.Logging +{ + public interface IContextStacks + { + IContextStack this[string key] { get; } + } +} \ No newline at end of file diff --git a/Castle.Core/Core/Logging/IExtendedLogger.cs b/Castle.Core/Core/Logging/IExtendedLogger.cs new file mode 100644 index 0000000..65b13dd --- /dev/null +++ b/Castle.Core/Core/Logging/IExtendedLogger.cs @@ -0,0 +1,39 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Core.Logging +{ + /// + /// Provides an interface that supports and + /// allows the storage and retrieval of Contexts. These are supported in + /// both log4net and NLog. + /// + public interface IExtendedLogger : ILogger + { + /// + /// Exposes the Global Context of the extended logger. + /// + IContextProperties GlobalProperties { get; } + + /// + /// Exposes the Thread Context of the extended logger. + /// + IContextProperties ThreadProperties { get; } + + /// + /// Exposes the Thread Stack of the extended logger. + /// + IContextStacks ThreadStacks { get; } + } +} \ No newline at end of file diff --git a/Castle.Core/Core/Logging/IExtendedLoggerFactory.cs b/Castle.Core/Core/Logging/IExtendedLoggerFactory.cs new file mode 100644 index 0000000..d0b63b2 --- /dev/null +++ b/Castle.Core/Core/Logging/IExtendedLoggerFactory.cs @@ -0,0 +1,45 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Core.Logging +{ + using System; + + /// + /// Provides a factory that can produce either or + /// classes. + /// + public interface IExtendedLoggerFactory : ILoggerFactory + { + /// + /// Creates a new extended logger, getting the logger name from the specified type. + /// + new IExtendedLogger Create(Type type); + + /// + /// Creates a new extended logger. + /// + new IExtendedLogger Create(string name); + + /// + /// Creates a new extended logger, getting the logger name from the specified type. + /// + new IExtendedLogger Create(Type type, LoggerLevel level); + + /// + /// Creates a new extended logger. + /// + new IExtendedLogger Create(string name, LoggerLevel level); + } +} \ No newline at end of file diff --git a/Castle.Core/Core/Logging/ILogger.cs b/Castle.Core/Core/Logging/ILogger.cs new file mode 100644 index 0000000..036b9b3 --- /dev/null +++ b/Castle.Core/Core/Logging/ILogger.cs @@ -0,0 +1,374 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Core.Logging +{ + using System; + + /// + /// Manages logging. + /// + /// + /// This is a facade for the different logging subsystems. + /// It offers a simplified interface that follows IOC patterns + /// and a simplified priority/level/severity abstraction. + /// + public interface ILogger + { + /// + /// Determines if messages of priority "trace" will be logged. + /// + /// True if "trace" messages will be logged. + bool IsTraceEnabled { get; } + + /// + /// Determines if messages of priority "debug" will be logged. + /// + /// True if "debug" messages will be logged. + bool IsDebugEnabled { get; } + + /// + /// Determines if messages of priority "error" will be logged. + /// + /// True if "error" messages will be logged. + bool IsErrorEnabled { get; } + + /// + /// Determines if messages of priority "fatal" will be logged. + /// + /// True if "fatal" messages will be logged. + bool IsFatalEnabled { get; } + + /// + /// Determines if messages of priority "info" will be logged. + /// + /// True if "info" messages will be logged. + bool IsInfoEnabled { get; } + + /// + /// Determines if messages of priority "warn" will be logged. + /// + /// True if "warn" messages will be logged. + bool IsWarnEnabled { get; } + + /// + /// Create a new child logger. + /// The name of the child logger is [current-loggers-name].[passed-in-name] + /// + /// The Subname of this logger. + /// The New ILogger instance. + /// If the name has an empty element name. + ILogger CreateChildLogger(string loggerName); + + /// + /// Logs a trace message. + /// + /// The message to log + void Trace(string message); + + /// + /// Logs a trace message with lazily constructed message. The message will be constructed only if the is true. + /// + void Trace(Func messageFactory); + + /// + /// Logs a trace message. + /// + /// The exception to log + /// The message to log + void Trace(string message, Exception exception); + + /// + /// Logs a trace message. + /// + /// Format string for the message to log + /// Format arguments for the message to log + void TraceFormat(string format, params object[] args); + + /// + /// Logs a trace message. + /// + /// The exception to log + /// Format string for the message to log + /// Format arguments for the message to log + void TraceFormat(Exception exception, string format, params object[] args); + + /// + /// Logs a trace message. + /// + /// The format provider to use + /// Format string for the message to log + /// Format arguments for the message to log + void TraceFormat(IFormatProvider formatProvider, string format, params object[] args); + + /// + /// Logs a trace message. + /// + /// The exception to log + /// The format provider to use + /// Format string for the message to log + /// Format arguments for the message to log + void TraceFormat(Exception exception, IFormatProvider formatProvider, string format, params object[] args); + + /// + /// Logs a debug message. + /// + /// The message to log + void Debug(string message); + + /// + /// Logs a debug message with lazily constructed message. The message will be constructed only if the is true. + /// + void Debug(Func messageFactory); + + /// + /// Logs a debug message. + /// + /// The exception to log + /// The message to log + void Debug(string message, Exception exception); + + /// + /// Logs a debug message. + /// + /// Format string for the message to log + /// Format arguments for the message to log + void DebugFormat(string format, params object[] args); + + /// + /// Logs a debug message. + /// + /// The exception to log + /// Format string for the message to log + /// Format arguments for the message to log + void DebugFormat(Exception exception, string format, params object[] args); + + /// + /// Logs a debug message. + /// + /// The format provider to use + /// Format string for the message to log + /// Format arguments for the message to log + void DebugFormat(IFormatProvider formatProvider, string format, params object[] args); + + /// + /// Logs a debug message. + /// + /// The exception to log + /// The format provider to use + /// Format string for the message to log + /// Format arguments for the message to log + void DebugFormat(Exception exception, IFormatProvider formatProvider, string format, params object[] args); + + /// + /// Logs an error message. + /// + /// The message to log + void Error(string message); + + /// + /// Logs an error message with lazily constructed message. The message will be constructed only if the is true. + /// + void Error(Func messageFactory); + + /// + /// Logs an error message. + /// + /// The exception to log + /// The message to log + void Error(string message, Exception exception); + + /// + /// Logs an error message. + /// + /// Format string for the message to log + /// Format arguments for the message to log + void ErrorFormat(string format, params object[] args); + + /// + /// Logs an error message. + /// + /// The exception to log + /// Format string for the message to log + /// Format arguments for the message to log + void ErrorFormat(Exception exception, string format, params object[] args); + + /// + /// Logs an error message. + /// + /// The format provider to use + /// Format string for the message to log + /// Format arguments for the message to log + void ErrorFormat(IFormatProvider formatProvider, string format, params object[] args); + + /// + /// Logs an error message. + /// + /// The exception to log + /// The format provider to use + /// Format string for the message to log + /// Format arguments for the message to log + void ErrorFormat(Exception exception, IFormatProvider formatProvider, string format, params object[] args); + + /// + /// Logs a fatal message. + /// + /// The message to log + void Fatal(string message); + + /// + /// Logs a fatal message with lazily constructed message. The message will be constructed only if the is true. + /// + void Fatal(Func messageFactory); + + /// + /// Logs a fatal message. + /// + /// The exception to log + /// The message to log + void Fatal(string message, Exception exception); + + /// + /// Logs a fatal message. + /// + /// Format string for the message to log + /// Format arguments for the message to log + void FatalFormat(string format, params object[] args); + + /// + /// Logs a fatal message. + /// + /// The exception to log + /// Format string for the message to log + /// Format arguments for the message to log + void FatalFormat(Exception exception, string format, params object[] args); + + /// + /// Logs a fatal message. + /// + /// The format provider to use + /// Format string for the message to log + /// Format arguments for the message to log + void FatalFormat(IFormatProvider formatProvider, string format, params object[] args); + + /// + /// Logs a fatal message. + /// + /// The exception to log + /// The format provider to use + /// Format string for the message to log + /// Format arguments for the message to log + void FatalFormat(Exception exception, IFormatProvider formatProvider, string format, params object[] args); + + /// + /// Logs an info message. + /// + /// The message to log + void Info(string message); + + /// + /// Logs a info message with lazily constructed message. The message will be constructed only if the is true. + /// + void Info(Func messageFactory); + + /// + /// Logs an info message. + /// + /// The exception to log + /// The message to log + void Info(string message, Exception exception); + + /// + /// Logs an info message. + /// + /// Format string for the message to log + /// Format arguments for the message to log + void InfoFormat(string format, params object[] args); + + /// + /// Logs an info message. + /// + /// The exception to log + /// Format string for the message to log + /// Format arguments for the message to log + void InfoFormat(Exception exception, string format, params object[] args); + + /// + /// Logs an info message. + /// + /// The format provider to use + /// Format string for the message to log + /// Format arguments for the message to log + void InfoFormat(IFormatProvider formatProvider, string format, params object[] args); + + /// + /// Logs an info message. + /// + /// The exception to log + /// The format provider to use + /// Format string for the message to log + /// Format arguments for the message to log + void InfoFormat(Exception exception, IFormatProvider formatProvider, string format, params object[] args); + + /// + /// Logs a warn message. + /// + /// The message to log + void Warn(string message); + + /// + /// Logs a warn message with lazily constructed message. The message will be constructed only if the is true. + /// + void Warn(Func messageFactory); + + /// + /// Logs a warn message. + /// + /// The exception to log + /// The message to log + void Warn(string message, Exception exception); + + /// + /// Logs a warn message. + /// + /// Format string for the message to log + /// Format arguments for the message to log + void WarnFormat(string format, params object[] args); + + /// + /// Logs a warn message. + /// + /// The exception to log + /// Format string for the message to log + /// Format arguments for the message to log + void WarnFormat(Exception exception, string format, params object[] args); + + /// + /// Logs a warn message. + /// + /// The format provider to use + /// Format string for the message to log + /// Format arguments for the message to log + void WarnFormat(IFormatProvider formatProvider, string format, params object[] args); + + /// + /// Logs a warn message. + /// + /// The exception to log + /// The format provider to use + /// Format string for the message to log + /// Format arguments for the message to log + void WarnFormat(Exception exception, IFormatProvider formatProvider, string format, params object[] args); + } +} \ No newline at end of file diff --git a/Castle.Core/Core/Logging/ILoggerFactory.cs b/Castle.Core/Core/Logging/ILoggerFactory.cs new file mode 100644 index 0000000..7648bd6 --- /dev/null +++ b/Castle.Core/Core/Logging/ILoggerFactory.cs @@ -0,0 +1,44 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Core.Logging +{ + using System; + + /// + /// Manages the instantiation of s. + /// + public interface ILoggerFactory + { + /// + /// Creates a new logger, getting the logger name from the specified type. + /// + ILogger Create(Type type); + + /// + /// Creates a new logger. + /// + ILogger Create(string name); + + /// + /// Creates a new logger, getting the logger name from the specified type. + /// + ILogger Create(Type type, LoggerLevel level); + + /// + /// Creates a new logger. + /// + ILogger Create(string name, LoggerLevel level); + } +} \ No newline at end of file diff --git a/Castle.Core/Core/Logging/LevelFilteredLogger.cs b/Castle.Core/Core/Logging/LevelFilteredLogger.cs new file mode 100644 index 0000000..c0437fe --- /dev/null +++ b/Castle.Core/Core/Logging/LevelFilteredLogger.cs @@ -0,0 +1,787 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Core.Logging +{ + using System; + using System.Globalization; + + /// + /// The Level Filtered Logger class. This is a base class which + /// provides a LogLevel attribute and reroutes all functions into + /// one Log method. + /// +#if FEATURE_SERIALIZATION + [Serializable] +#endif + public abstract class LevelFilteredLogger : ILogger + { + private LoggerLevel level = LoggerLevel.Off; + private string name = "unnamed"; + + /// + /// Creates a new LevelFilteredLogger. + /// + protected LevelFilteredLogger() + { + } + + protected LevelFilteredLogger(string name) + { + ChangeName(name); + } + + protected LevelFilteredLogger(LoggerLevel loggerLevel) + { + level = loggerLevel; + } + + protected LevelFilteredLogger(string loggerName, LoggerLevel loggerLevel) : this(loggerLevel) + { + ChangeName(loggerName); + } + + public abstract ILogger CreateChildLogger(string loggerName); + + /// + /// The LoggerLevel that this logger + /// will be using. Defaults to LoggerLevel.Off + /// + public LoggerLevel Level + { + get { return level; } + set { level = value; } + } + + /// + /// The name that this logger will be using. + /// Defaults to string.Empty + /// + public string Name + { + get { return name; } + } + + #region ILogger implementation + + #region Trace + + /// + /// Logs a trace message. + /// + /// The message to log + public void Trace(string message) + { + if (IsTraceEnabled) + { + Log(LoggerLevel.Trace, message, null); + } + } + + /// + /// Logs a trace message. + /// + /// A functor to create the message + public void Trace(Func messageFactory) + { + if (IsTraceEnabled) + { + Log(LoggerLevel.Trace, messageFactory.Invoke(), null); + } + } + + /// + /// Logs a trace message. + /// + /// The exception to log + /// The message to log + public void Trace(string message, Exception exception) + { + if (IsTraceEnabled) + { + Log(LoggerLevel.Trace, message, exception); + } + } + + /// + /// Logs a trace message. + /// + /// Format string for the message to log + /// Format arguments for the message to log + public void TraceFormat(string format, params object[] args) + { + if (IsTraceEnabled) + { + Log(LoggerLevel.Trace, string.Format(CultureInfo.CurrentCulture, format, args), null); + } + } + + /// + /// Logs a trace message. + /// + /// The exception to log + /// Format string for the message to log + /// Format arguments for the message to log + public void TraceFormat(Exception exception, string format, params object[] args) + { + if (IsTraceEnabled) + { + Log(LoggerLevel.Trace, string.Format(CultureInfo.CurrentCulture, format, args), exception); + } + } + + /// + /// Logs a trace message. + /// + /// The format provider to use + /// Format string for the message to log + /// Format arguments for the message to log + public void TraceFormat(IFormatProvider formatProvider, string format, params object[] args) + { + if (IsTraceEnabled) + { + Log(LoggerLevel.Trace, string.Format(formatProvider, format, args), null); + } + } + + /// + /// Logs a trace message. + /// + /// The exception to log + /// The format provider to use + /// Format string for the message to log + /// Format arguments for the message to log + public void TraceFormat(Exception exception, IFormatProvider formatProvider, string format, params object[] args) + { + if (IsTraceEnabled) + { + Log(LoggerLevel.Trace, string.Format(formatProvider, format, args), exception); + } + } + + #endregion + + #region Debug + + /// + /// Logs a debug message. + /// + /// The message to log + public void Debug(string message) + { + if (!IsDebugEnabled) + { + return; + } + + Log(LoggerLevel.Debug, message, null); + } + + public void Debug(Func messageFactory) + { + if (!IsDebugEnabled) + { + return; + } + + Log(LoggerLevel.Debug, messageFactory.Invoke(), null); + } + + /// + /// Logs a debug message. + /// + /// The exception to log + /// The message to log + public void Debug(string message, Exception exception) + { + if (!IsDebugEnabled) + { + return; + } + + Log(LoggerLevel.Debug, message, exception); + } + + /// + /// Logs a debug message. + /// + /// Format string for the message to log + /// Format arguments for the message to log + public void DebugFormat(string format, params object[] args) + { + if (!IsDebugEnabled) + { + return; + } + + Log(LoggerLevel.Debug, string.Format(CultureInfo.CurrentCulture, format, args), null); + } + + /// + /// Logs a debug message. + /// + /// The exception to log + /// Format string for the message to log + /// Format arguments for the message to log + public void DebugFormat(Exception exception, string format, params object[] args) + { + if (!IsDebugEnabled) + { + return; + } + + Log(LoggerLevel.Debug, string.Format(CultureInfo.CurrentCulture, format, args), exception); + } + + /// + /// Logs a debug message. + /// + /// The format provider to use + /// Format string for the message to log + /// Format arguments for the message to log + public void DebugFormat(IFormatProvider formatProvider, string format, params object[] args) + { + if (!IsDebugEnabled) + { + return; + } + + Log(LoggerLevel.Debug, string.Format(formatProvider, format, args), null); + } + + /// + /// Logs a debug message. + /// + /// The exception to log + /// The format provider to use + /// Format string for the message to log + /// Format arguments for the message to log + public void DebugFormat(Exception exception, IFormatProvider formatProvider, string format, params object[] args) + { + if (!IsDebugEnabled) + { + return; + } + + Log(LoggerLevel.Debug, string.Format(formatProvider, format, args), exception); + } + + #endregion + + #region Info + + /// + /// Logs an info message. + /// + /// The message to log + public void Info(string message) + { + if (!IsInfoEnabled) + { + return; + } + + Log(LoggerLevel.Info, message, null); + } + + public void Info(Func messageFactory) + { + if (!IsInfoEnabled) + { + return; + } + + Log(LoggerLevel.Info, messageFactory.Invoke(), null); + } + + /// + /// Logs an info message. + /// + /// The exception to log + /// The message to log + public void Info(string message, Exception exception) + { + if (!IsInfoEnabled) + { + return; + } + + Log(LoggerLevel.Info, message, exception); + } + + /// + /// Logs an info message. + /// + /// Format string for the message to log + /// Format arguments for the message to log + public void InfoFormat(string format, params object[] args) + { + if (!IsInfoEnabled) + { + return; + } + + Log(LoggerLevel.Info, string.Format(CultureInfo.CurrentCulture, format, args), null); + } + + /// + /// Logs an info message. + /// + /// The exception to log + /// Format string for the message to log + /// Format arguments for the message to log + public void InfoFormat(Exception exception, string format, params object[] args) + { + if (!IsInfoEnabled) + { + return; + } + + Log(LoggerLevel.Info, string.Format(CultureInfo.CurrentCulture, format, args), exception); + } + + /// + /// Logs an info message. + /// + /// The format provider to use + /// Format string for the message to log + /// Format arguments for the message to log + public void InfoFormat(IFormatProvider formatProvider, string format, params object[] args) + { + if (!IsInfoEnabled) + { + return; + } + + Log(LoggerLevel.Info, string.Format(formatProvider, format, args), null); + } + + /// + /// Logs an info message. + /// + /// The exception to log + /// The format provider to use + /// Format string for the message to log + /// Format arguments for the message to log + public void InfoFormat(Exception exception, IFormatProvider formatProvider, string format, params object[] args) + { + if (!IsInfoEnabled) + { + return; + } + + Log(LoggerLevel.Info, string.Format(formatProvider, format, args), exception); + } + + #endregion + + #region Warn + + /// + /// Logs a warn message. + /// + /// The message to log + public void Warn(string message) + { + if (!IsWarnEnabled) + { + return; + } + + Log(LoggerLevel.Warn, message, null); + } + + public void Warn(Func messageFactory) + { + if (!IsWarnEnabled) + { + return; + } + + Log(LoggerLevel.Warn, messageFactory.Invoke(), null); + } + + /// + /// Logs a warn message. + /// + /// The exception to log + /// The message to log + public void Warn(string message, Exception exception) + { + if (!IsWarnEnabled) + { + return; + } + + Log(LoggerLevel.Warn, message, exception); + } + + /// + /// Logs a warn message. + /// + /// Format string for the message to log + /// Format arguments for the message to log + public void WarnFormat(string format, params object[] args) + { + if (!IsWarnEnabled) + { + return; + } + + Log(LoggerLevel.Warn, string.Format(CultureInfo.CurrentCulture, format, args), null); + } + + /// + /// Logs a warn message. + /// + /// The exception to log + /// Format string for the message to log + /// Format arguments for the message to log + public void WarnFormat(Exception exception, string format, params object[] args) + { + if (!IsWarnEnabled) + { + return; + } + + Log(LoggerLevel.Warn, string.Format(CultureInfo.CurrentCulture, format, args), exception); + } + + /// + /// Logs a warn message. + /// + /// The format provider to use + /// Format string for the message to log + /// Format arguments for the message to log + public void WarnFormat(IFormatProvider formatProvider, string format, params object[] args) + { + if (!IsWarnEnabled) + { + return; + } + + Log(LoggerLevel.Warn, string.Format(formatProvider, format, args), null); + } + + /// + /// Logs a warn message. + /// + /// The exception to log + /// The format provider to use + /// Format string for the message to log + /// Format arguments for the message to log + public void WarnFormat(Exception exception, IFormatProvider formatProvider, string format, params object[] args) + { + if (!IsWarnEnabled) + { + return; + } + + Log(LoggerLevel.Warn, string.Format(formatProvider, format, args), exception); + } + + #endregion + + #region Error + + /// + /// Logs an error message. + /// + /// The message to log + public void Error(string message) + { + if (!IsErrorEnabled) + { + return; + } + + Log(LoggerLevel.Error, message, null); + } + + public void Error(Func messageFactory) + { + if (!IsErrorEnabled) + { + return; + } + + Log(LoggerLevel.Error, messageFactory.Invoke(), null); + } + + /// + /// Logs an error message. + /// + /// The exception to log + /// The message to log + public void Error(string message, Exception exception) + { + if (!IsErrorEnabled) + { + return; + } + + Log(LoggerLevel.Error, message, exception); + } + + /// + /// Logs an error message. + /// + /// Format string for the message to log + /// Format arguments for the message to log + public void ErrorFormat(string format, params object[] args) + { + if (!IsErrorEnabled) + { + return; + } + + Log(LoggerLevel.Error, string.Format(CultureInfo.CurrentCulture, format, args), null); + } + + /// + /// Logs an error message. + /// + /// The exception to log + /// Format string for the message to log + /// Format arguments for the message to log + public void ErrorFormat(Exception exception, string format, params object[] args) + { + if (!IsErrorEnabled) + { + return; + } + + Log(LoggerLevel.Error, string.Format(CultureInfo.CurrentCulture, format, args), exception); + } + + /// + /// Logs an error message. + /// + /// The format provider to use + /// Format string for the message to log + /// Format arguments for the message to log + public void ErrorFormat(IFormatProvider formatProvider, string format, params object[] args) + { + if (!IsErrorEnabled) + { + return; + } + + Log(LoggerLevel.Error, string.Format(formatProvider, format, args), null); + } + + /// + /// Logs an error message. + /// + /// The exception to log + /// The format provider to use + /// Format string for the message to log + /// Format arguments for the message to log + public void ErrorFormat(Exception exception, IFormatProvider formatProvider, string format, params object[] args) + { + if (!IsErrorEnabled) + { + return; + } + + Log(LoggerLevel.Error, string.Format(formatProvider, format, args), exception); + } + + #endregion + + #region Fatal + + /// + /// Logs a fatal message. + /// + /// The message to log + public void Fatal(string message) + { + if (!IsFatalEnabled) + { + return; + } + + Log(LoggerLevel.Fatal, message, null); + } + + public void Fatal(Func messageFactory) + { + if (!IsFatalEnabled) + { + return; + } + + Log(LoggerLevel.Fatal, messageFactory.Invoke(), null); + } + + /// + /// Logs a fatal message. + /// + /// The exception to log + /// The message to log + public void Fatal(string message, Exception exception) + { + if (!IsFatalEnabled) + { + return; + } + + Log(LoggerLevel.Fatal, message, exception); + } + + /// + /// Logs a fatal message. + /// + /// Format string for the message to log + /// Format arguments for the message to log + public void FatalFormat(string format, params object[] args) + { + if (!IsFatalEnabled) + { + return; + } + + Log(LoggerLevel.Fatal, string.Format(CultureInfo.CurrentCulture, format, args), null); + } + + /// + /// Logs a fatal message. + /// + /// The exception to log + /// Format string for the message to log + /// Format arguments for the message to log + public void FatalFormat(Exception exception, string format, params object[] args) + { + if (!IsFatalEnabled) + { + return; + } + + Log(LoggerLevel.Fatal, string.Format(CultureInfo.CurrentCulture, format, args), exception); + } + + /// + /// Logs a fatal message. + /// + /// The format provider to use + /// Format string for the message to log + /// Format arguments for the message to log + public void FatalFormat(IFormatProvider formatProvider, string format, params object[] args) + { + if (!IsFatalEnabled) + { + return; + } + + Log(LoggerLevel.Fatal, string.Format(formatProvider, format, args), null); + } + + /// + /// Logs a fatal message. + /// + /// The exception to log + /// The format provider to use + /// Format string for the message to log + /// Format arguments for the message to log + public void FatalFormat(Exception exception, IFormatProvider formatProvider, string format, params object[] args) + { + if (!IsFatalEnabled) + { + return; + } + + Log(LoggerLevel.Fatal, string.Format(formatProvider, format, args), exception); + } + + #endregion + + /// + /// Determines if messages of priority "trace" will be logged. + /// + /// true if log level flags include the bit + public bool IsTraceEnabled + { + get { return (Level >= LoggerLevel.Trace); } + } + + /// + /// Determines if messages of priority "debug" will be logged. + /// + /// true if log level flags include the bit + public bool IsDebugEnabled + { + get { return (Level >= LoggerLevel.Debug); } + } + + /// + /// Determines if messages of priority "info" will be logged. + /// + /// true if log level flags include the bit + public bool IsInfoEnabled + { + get { return (Level >= LoggerLevel.Info); } + } + + /// + /// Determines if messages of priority "warn" will be logged. + /// + /// true if log level flags include the bit + public bool IsWarnEnabled + { + get { return (Level >= LoggerLevel.Warn); } + } + + /// + /// Determines if messages of priority "error" will be logged. + /// + /// true if log level flags include the bit + public bool IsErrorEnabled + { + get { return (Level >= LoggerLevel.Error); } + } + + /// + /// Determines if messages of priority "fatal" will be logged. + /// + /// true if log level flags include the bit + public bool IsFatalEnabled + { + get { return (Level >= LoggerLevel.Fatal); } + } + + #endregion + + /// + /// Implementors output the log content by implementing this method only. + /// Note that exception can be null + /// + protected abstract void Log(LoggerLevel loggerLevel, string loggerName, string message, Exception exception); + + protected void ChangeName(string newName) + { + if (newName == null) + { + throw new ArgumentNullException(nameof(newName)); + } + + name = newName; + } + + private void Log(LoggerLevel loggerLevel, string message, Exception exception) + { + Log(loggerLevel, Name, message, exception); + } + } +} \ No newline at end of file diff --git a/Castle.Core/Core/Logging/LoggerException.cs b/Castle.Core/Core/Logging/LoggerException.cs new file mode 100644 index 0000000..cf99979 --- /dev/null +++ b/Castle.Core/Core/Logging/LoggerException.cs @@ -0,0 +1,39 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Core.Logging +{ + using System; + using System.Runtime.Serialization; + + [Serializable] + public class LoggerException : Exception + { + public LoggerException() + { + } + + public LoggerException(string message) : base(message) + { + } + + public LoggerException(string message, Exception innerException) : base(message, innerException) + { + } + + protected LoggerException(SerializationInfo info, StreamingContext context) : base(info, context) + { + } + } +} \ No newline at end of file diff --git a/Castle.Core/Core/Logging/LoggerLevel.cs b/Castle.Core/Core/Logging/LoggerLevel.cs new file mode 100644 index 0000000..3ae8bb0 --- /dev/null +++ b/Castle.Core/Core/Logging/LoggerLevel.cs @@ -0,0 +1,51 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Core.Logging +{ + /// + /// Supporting Logger levels. + /// + public enum LoggerLevel + { + /// + /// Logging will be off + /// + Off = 0, + /// + /// Fatal logging level + /// + Fatal = 1, + /// + /// Error logging level + /// + Error = 2, + /// + /// Warn logging level + /// + Warn = 3, + /// + /// Info logging level + /// + Info = 4, + /// + /// Debug logging level + /// + Debug = 5, + /// + /// Trace logging level + /// + Trace = 6 + } +} \ No newline at end of file diff --git a/Castle.Core/Core/Logging/NullLogFactory.cs b/Castle.Core/Core/Logging/NullLogFactory.cs new file mode 100644 index 0000000..37479e2 --- /dev/null +++ b/Castle.Core/Core/Logging/NullLogFactory.cs @@ -0,0 +1,46 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Core.Logging +{ + using System; + + /// + /// NullLogFactory used when logging is turned off. + /// +#if FEATURE_SERIALIZATION + [Serializable] +#endif + public class NullLogFactory : AbstractLoggerFactory + { + /// + /// Creates an instance of ILogger with the specified name. + /// + /// Name. + public override ILogger Create(string name) + { + return NullLogger.Instance; + } + + /// + /// Creates an instance of ILogger with the specified name and LoggerLevel. + /// + /// Name. + /// Level. + public override ILogger Create(string name, LoggerLevel level) + { + return NullLogger.Instance; + } + } +} \ No newline at end of file diff --git a/Castle.Core/Core/Logging/NullLogger.cs b/Castle.Core/Core/Logging/NullLogger.cs new file mode 100644 index 0000000..b871dc3 --- /dev/null +++ b/Castle.Core/Core/Logging/NullLogger.cs @@ -0,0 +1,532 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Core.Logging +{ + using System; + + /// + /// The Null Logger class. This is useful for implementations where you need + /// to provide a logger to a utility class, but do not want any output from it. + /// It also helps when you have a utility that does not have a logger to supply. + /// + public class NullLogger : IExtendedLogger + { + public static readonly NullLogger Instance = new NullLogger(); + + /// + /// Returns empty context properties. + /// + public IContextProperties GlobalProperties + { + get { return NullContextProperties.Instance; } + } + + /// + /// Returns empty context properties. + /// + public IContextProperties ThreadProperties + { + get { return NullContextProperties.Instance; } + } + + /// + /// Returns empty context stacks. + /// + public IContextStacks ThreadStacks + { + get { return NullContextStacks.Instance; } + } + + /// + /// No-op. + /// + /// false + public bool IsTraceEnabled + { + get { return false; } + } + + /// + /// No-op. + /// + /// false + public bool IsDebugEnabled + { + get { return false; } + } + + /// + /// No-op. + /// + /// false + public bool IsErrorEnabled + { + get { return false; } + } + + /// + /// No-op. + /// + /// false + public bool IsFatalEnabled + { + get { return false; } + } + + /// + /// No-op. + /// + /// false + public bool IsInfoEnabled + { + get { return false; } + } + + /// + /// No-op. + /// + /// false + public bool IsWarnEnabled + { + get { return false; } + } + + /// + /// Returns this NullLogger. + /// + /// Ignored + /// This ILogger instance. + public ILogger CreateChildLogger(string loggerName) + { + return this; + } + + /// + /// No-op. + /// + /// Ignored + public void Trace(string message) + { + } + + public void Trace(Func messageFactory) + { + } + + /// + /// No-op. + /// + /// Ignored + /// Ignored + public void Trace(string message, Exception exception) + { + } + + /// + /// No-op. + /// + /// Ignored + /// Ignored + public void TraceFormat(string format, params object[] args) + { + } + + /// + /// No-op. + /// + /// Ignored + /// Ignored + /// Ignored + public void TraceFormat(Exception exception, string format, params object[] args) + { + } + + /// + /// No-op. + /// + /// Ignored + /// Ignored + /// Ignored + public void TraceFormat(IFormatProvider formatProvider, string format, params object[] args) + { + } + + /// + /// No-op. + /// + /// Ignored + /// Ignored + /// Ignored + /// Ignored + public void TraceFormat(Exception exception, IFormatProvider formatProvider, string format, params object[] args) + { + } + + /// + /// No-op. + /// + /// Ignored + public void Debug(string message) + { + } + + public void Debug(Func messageFactory) + { + } + + /// + /// No-op. + /// + /// Ignored + /// Ignored + public void Debug(string message, Exception exception) + { + } + + /// + /// No-op. + /// + /// Ignored + /// Ignored + public void DebugFormat(string format, params object[] args) + { + } + + /// + /// No-op. + /// + /// Ignored + /// Ignored + /// Ignored + public void DebugFormat(Exception exception, string format, params object[] args) + { + } + + /// + /// No-op. + /// + /// Ignored + /// Ignored + /// Ignored + public void DebugFormat(IFormatProvider formatProvider, string format, params object[] args) + { + } + + /// + /// No-op. + /// + /// Ignored + /// Ignored + /// Ignored + /// Ignored + public void DebugFormat(Exception exception, IFormatProvider formatProvider, string format, params object[] args) + { + } + + /// + /// No-op. + /// + /// Ignored + public void Error(string message) + { + } + + public void Error(Func messageFactory) + { + } + + /// + /// No-op. + /// + /// Ignored + /// Ignored + public void Error(string message, Exception exception) + { + } + + /// + /// No-op. + /// + /// Ignored + /// Ignored + public void ErrorFormat(string format, params object[] args) + { + } + + /// + /// No-op. + /// + /// Ignored + /// Ignored + /// Ignored + public void ErrorFormat(Exception exception, string format, params object[] args) + { + } + + /// + /// No-op. + /// + /// Ignored + /// Ignored + /// Ignored + public void ErrorFormat(IFormatProvider formatProvider, string format, params object[] args) + { + } + + /// + /// No-op. + /// + /// Ignored + /// Ignored + /// Ignored + /// Ignored + public void ErrorFormat(Exception exception, IFormatProvider formatProvider, string format, params object[] args) + { + } + + /// + /// No-op. + /// + /// Ignored + public void Fatal(string message) + { + } + + public void Fatal(Func messageFactory) + { + } + + /// + /// No-op. + /// + /// Ignored + /// Ignored + public void Fatal(string message, Exception exception) + { + } + + /// + /// No-op. + /// + /// Ignored + /// Ignored + public void FatalFormat(string format, params object[] args) + { + } + + /// + /// No-op. + /// + /// Ignored + /// Ignored + /// Ignored + public void FatalFormat(Exception exception, string format, params object[] args) + { + } + + /// + /// No-op. + /// + /// Ignored + /// Ignored + /// Ignored + public void FatalFormat(IFormatProvider formatProvider, string format, params object[] args) + { + } + + /// + /// No-op. + /// + /// Ignored + /// Ignored + /// Ignored + /// Ignored + public void FatalFormat(Exception exception, IFormatProvider formatProvider, string format, params object[] args) + { + } + + /// + /// No-op. + /// + /// Ignored + public void Info(string message) + { + } + + public void Info(Func messageFactory) + { + } + + /// + /// No-op. + /// + /// Ignored + /// Ignored + public void Info(string message, Exception exception) + { + } + + /// + /// No-op. + /// + /// Ignored + /// Ignored + public void InfoFormat(string format, params object[] args) + { + } + + /// + /// No-op. + /// + /// Ignored + /// Ignored + /// Ignored + public void InfoFormat(Exception exception, string format, params object[] args) + { + } + + /// + /// No-op. + /// + /// Ignored + /// Ignored + /// Ignored + public void InfoFormat(IFormatProvider formatProvider, string format, params object[] args) + { + } + + /// + /// No-op. + /// + /// Ignored + /// Ignored + /// Ignored + /// Ignored + public void InfoFormat(Exception exception, IFormatProvider formatProvider, string format, params object[] args) + { + } + + /// + /// No-op. + /// + /// Ignored + public void Warn(string message) + { + } + + public void Warn(Func messageFactory) + { + } + + /// + /// No-op. + /// + /// Ignored + /// Ignored + public void Warn(string message, Exception exception) + { + } + + /// + /// No-op. + /// + /// Ignored + /// Ignored + public void WarnFormat(string format, params object[] args) + { + } + + /// + /// No-op. + /// + /// Ignored + /// Ignored + /// Ignored + public void WarnFormat(Exception exception, string format, params object[] args) + { + } + + /// + /// No-op. + /// + /// Ignored + /// Ignored + /// Ignored + public void WarnFormat(IFormatProvider formatProvider, string format, params object[] args) + { + } + + /// + /// No-op. + /// + /// Ignored + /// Ignored + /// Ignored + /// Ignored + public void WarnFormat(Exception exception, IFormatProvider formatProvider, string format, params object[] args) + { + } + + private class NullContextProperties : IContextProperties + { + public static readonly NullContextProperties Instance = new NullContextProperties(); + + public object this[string key] + { + get { return null; } + set { } + } + } + + private class NullContextStack : IContextStack, IDisposable + { + public static readonly NullContextStack Instance = new NullContextStack(); + + public int Count + { + get { return 0; } + } + + public void Clear() + { + } + + public string Pop() + { + return null; + } + + public IDisposable Push(string message) + { + return this; + } + + public void Dispose() + { + GC.SuppressFinalize(this); + } + } + + private class NullContextStacks : IContextStacks + { + public static readonly NullContextStacks Instance = new NullContextStacks(); + + public IContextStack this[string key] + { + get { return NullContextStack.Instance; } + } + } + } +} \ No newline at end of file diff --git a/Castle.Core/Core/Logging/StreamLogger.cs b/Castle.Core/Core/Logging/StreamLogger.cs new file mode 100644 index 0000000..91e1b8c --- /dev/null +++ b/Castle.Core/Core/Logging/StreamLogger.cs @@ -0,0 +1,160 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Core.Logging +{ + using System; + using System.IO; + using System.Text; + + /// + /// The Stream Logger class. This class can stream log information + /// to any stream, it is suitable for storing a log file to disk, + /// or to a MemoryStream for testing your components. + /// + /// + /// This logger is not thread safe. + /// +#if FEATURE_SERIALIZATION + [Serializable] +#endif + public class StreamLogger : LevelFilteredLogger, IDisposable + { + private StreamWriter writer; + + /// + /// Creates a new StreamLogger with default encoding + /// and buffer size. Initial Level is set to Debug. + /// + /// + /// The name of the log. + /// + /// + /// The stream that will be used for logging, + /// seeking while the logger is alive + /// + public StreamLogger(string name, Stream stream) : this(name, new StreamWriter(stream)) + { + } + + /// + /// Creates a new StreamLogger with default buffer size. + /// Initial Level is set to Debug. + /// + /// + /// The name of the log. + /// + /// + /// The stream that will be used for logging, + /// seeking while the logger is alive + /// + /// + /// The encoding that will be used for this stream. + /// + /// + public StreamLogger(string name, Stream stream, Encoding encoding) : this(name, new StreamWriter(stream, encoding)) + { + } + + /// + /// Creates a new StreamLogger. + /// Initial Level is set to Debug. + /// + /// + /// The name of the log. + /// + /// + /// The stream that will be used for logging, + /// seeking while the logger is alive + /// + /// + /// The encoding that will be used for this stream. + /// + /// + /// + /// The buffer size that will be used for this stream. + /// + /// + public StreamLogger(string name, Stream stream, Encoding encoding, int bufferSize) + : this(name, new StreamWriter(stream, encoding, bufferSize)) + { + } + + ~StreamLogger() + { + Dispose(false); + } + + #region IDisposable Members + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + #endregion + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + if (writer != null) + { + writer.Dispose(); + writer = null; + } + } + } + + /// + /// Creates a new StreamLogger with + /// Debug as default Level. + /// + /// The name of the log. + /// The StreamWriter the log will write to. + protected StreamLogger(string name, StreamWriter writer) : base(name, LoggerLevel.Trace) + { + this.writer = writer; + writer.AutoFlush = true; + } + + protected override void Log(LoggerLevel loggerLevel, string loggerName, string message, Exception exception) + { + if (writer == null) + { + return; // just in case it's been disposed + } + + writer.WriteLine("[{0}] '{1}' {2}", loggerLevel, loggerName, message); + + if (exception != null) + { + writer.WriteLine("[{0}] '{1}' {2}: {3} {4}", + loggerLevel, + loggerName, + exception.GetType().FullName, + exception.Message, + exception.StackTrace); + } + } + + public override ILogger CreateChildLogger(string loggerName) + { + // TODO: We could create a ChildStreamLogger that didn't take ownership of the stream + + throw new NotSupportedException("A streamlogger does not support child loggers"); + } + } +} \ No newline at end of file diff --git a/Castle.Core/Core/Logging/StreamLoggerFactory.cs b/Castle.Core/Core/Logging/StreamLoggerFactory.cs new file mode 100644 index 0000000..78077f1 --- /dev/null +++ b/Castle.Core/Core/Logging/StreamLoggerFactory.cs @@ -0,0 +1,44 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Core.Logging +{ + using System; + using System.IO; + using System.Text; + + /// + /// Creates outputting + /// to files. The name of the file is derived from the log name + /// plus the 'log' extension. + /// +#if FEATURE_SERIALIZATION + [Serializable] +#endif + public class StreamLoggerFactory : AbstractLoggerFactory + { + public override ILogger Create(string name) + { + return new StreamLogger(name, new FileStream(name + ".log", FileMode.Append, FileAccess.Write)); + } + + public override ILogger Create(string name, LoggerLevel level) + { + var logger = + new StreamLogger(name, new FileStream(name + ".log", FileMode.Append, FileAccess.Write)); + logger.Level = level; + return logger; + } + } +} diff --git a/Castle.Core/Core/Logging/TraceLogger.cs b/Castle.Core/Core/Logging/TraceLogger.cs new file mode 100644 index 0000000..1584577 --- /dev/null +++ b/Castle.Core/Core/Logging/TraceLogger.cs @@ -0,0 +1,227 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Core.Logging +{ + using System; + using System.Diagnostics; + using System.Collections.Generic; + + /// + /// The TraceLogger sends all logging to the System.Diagnostics.TraceSource + /// built into the .net framework. + /// + /// + /// Logging can be configured in the system.diagnostics configuration + /// section. + /// + /// If logger doesn't find a source name with a full match it will + /// use source names which match the namespace partially. For example you can + /// configure from all castle components by adding a source name with the + /// name "Castle". + /// + /// If no portion of the namespace matches the source named "Default" will + /// be used. + /// + public class TraceLogger : LevelFilteredLogger + { + private static readonly Dictionary cache = new Dictionary(); + + private TraceSource traceSource; + + /// + /// Build a new trace logger based on the named TraceSource + /// + /// The name used to locate the best TraceSource. In most cases comes from the using type's fullname. + public TraceLogger(string name) + : base(name) + { + Initialize(); + Level = MapLoggerLevel(traceSource.Switch.Level); + } + + /// + /// Build a new trace logger based on the named TraceSource + /// + /// The name used to locate the best TraceSource. In most cases comes from the using type's fullname. + /// The default logging level at which this source should write messages. In almost all cases this + /// default value will be overridden in the config file. + public TraceLogger(string name, LoggerLevel level) + : base(name, level) + { + Initialize(); + Level = MapLoggerLevel(traceSource.Switch.Level); + } + + /// + /// Create a new child logger. + /// The name of the child logger is [current-loggers-name].[passed-in-name] + /// + /// The Subname of this logger. + /// The New ILogger instance. + public override ILogger CreateChildLogger(string loggerName) + { + return InternalCreateChildLogger(loggerName); + } + + private ILogger InternalCreateChildLogger(string loggerName) + { + return new TraceLogger(string.Concat(Name, ".", loggerName), Level); + } + + protected override void Log(LoggerLevel loggerLevel, string loggerName, string message, Exception exception) + { + if (exception == null) + { + traceSource.TraceEvent(MapTraceEventType(loggerLevel), 0, message); + } + else + { + traceSource.TraceData(MapTraceEventType(loggerLevel), 0, message, exception); + } + } + + private void Initialize() + { + lock (cache) + { + // because TraceSource is meant to be used as a static member, and because + // building up the configuration inheritance is non-trivial, the instances + // themselves are cached for so multiple TraceLogger instances will reuse + // the named TraceSources which have been created + + if (cache.TryGetValue(Name, out traceSource)) + { + return; + } + + var defaultLevel = MapSourceLevels(Level); + traceSource = new TraceSource(Name, defaultLevel); + + // no further action necessary when the named source is configured + if (IsSourceConfigured(traceSource)) + { + cache.Add(Name, traceSource); + return; + } + + // otherwise hunt for a shorter source that been configured + var foundSource = new TraceSource("Default", defaultLevel); + + var searchName = ShortenName(Name); + while (!string.IsNullOrEmpty(searchName)) + { + var searchSource = new TraceSource(searchName, defaultLevel); + if (IsSourceConfigured(searchSource)) + { + foundSource = searchSource; + break; + } + + searchName = ShortenName(searchName); + } + + // reconfigure the created source to act like the found source + traceSource.Switch = foundSource.Switch; + traceSource.Listeners.Clear(); + foreach (TraceListener listener in foundSource.Listeners) + { + traceSource.Listeners.Add(listener); + } + + cache.Add(Name, traceSource); + } + } + + private static string ShortenName(string name) + { + var lastDot = name.LastIndexOf('.'); + if (lastDot != -1) + { + return name.Substring(0, lastDot); + } + return null; + } + + private static bool IsSourceConfigured(TraceSource source) + { + if (source.Listeners.Count == 1 && + source.Listeners[0] is DefaultTraceListener && + source.Listeners[0].Name == "Default") + { + return false; + } + return true; + } + + private static LoggerLevel MapLoggerLevel(SourceLevels level) + { + switch (level) + { + case SourceLevels.All: + return LoggerLevel.Trace; + case SourceLevels.Verbose: + return LoggerLevel.Debug; + case SourceLevels.Information: + return LoggerLevel.Info; + case SourceLevels.Warning: + return LoggerLevel.Warn; + case SourceLevels.Error: + return LoggerLevel.Error; + case SourceLevels.Critical: + return LoggerLevel.Fatal; + } + return LoggerLevel.Off; + } + + private static SourceLevels MapSourceLevels(LoggerLevel level) + { + switch (level) + { + case LoggerLevel.Trace: + return SourceLevels.All; + case LoggerLevel.Debug: + return SourceLevels.Verbose; + case LoggerLevel.Info: + return SourceLevels.Information; + case LoggerLevel.Warn: + return SourceLevels.Warning; + case LoggerLevel.Error: + return SourceLevels.Error; + case LoggerLevel.Fatal: + return SourceLevels.Critical; + } + return SourceLevels.Off; + } + + private static TraceEventType MapTraceEventType(LoggerLevel level) + { + switch (level) + { + case LoggerLevel.Trace: + case LoggerLevel.Debug: + return TraceEventType.Verbose; + case LoggerLevel.Info: + return TraceEventType.Information; + case LoggerLevel.Warn: + return TraceEventType.Warning; + case LoggerLevel.Error: + return TraceEventType.Error; + case LoggerLevel.Fatal: + return TraceEventType.Critical; + } + return TraceEventType.Verbose; + } + } +} \ No newline at end of file diff --git a/Castle.Core/Core/Logging/TraceLoggerFactory.cs b/Castle.Core/Core/Logging/TraceLoggerFactory.cs new file mode 100644 index 0000000..06dfea0 --- /dev/null +++ b/Castle.Core/Core/Logging/TraceLoggerFactory.cs @@ -0,0 +1,57 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Core.Logging +{ + /// + /// Used to create the TraceLogger implementation of ILogger interface. See . + /// + public class TraceLoggerFactory : AbstractLoggerFactory + { + private readonly LoggerLevel? level; + + public TraceLoggerFactory() + { + } + + public TraceLoggerFactory(LoggerLevel level) + { + this.level = level; + } + + public override ILogger Create(string name) + { + if (level.HasValue) + { + return Create(name, level.Value); + } + return InternalCreate(name); + } + + private ILogger InternalCreate(string name) + { + return new TraceLogger(name); + } + + public override ILogger Create(string name, LoggerLevel level) + { + return InternalCreate(name, level); + } + + private ILogger InternalCreate(string name, LoggerLevel level) + { + return new TraceLogger(name, level); + } + } +} \ No newline at end of file diff --git a/Castle.Core/Core/ProxyServices.cs b/Castle.Core/Core/ProxyServices.cs new file mode 100644 index 0000000..04e239f --- /dev/null +++ b/Castle.Core/Core/ProxyServices.cs @@ -0,0 +1,41 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Core +{ + using System; + using System.Reflection; + + /// + /// List of utility methods related to dynamic proxy operations + /// + public static class ProxyServices + { + /// + /// Determines whether the specified type is a proxy generated by + /// DynamicProxy (1 or 2). + /// + /// The type. + /// + /// true if it is a proxy; otherwise, false. + /// + public static bool IsDynamicProxy(Type type) + { + string assemblyName = type.Assembly.FullName; + + return (assemblyName.StartsWith("DynamicAssemblyProxyGen", StringComparison.Ordinal) || + assemblyName.StartsWith("DynamicProxyGenAssembly2", StringComparison.Ordinal)); + } + } +} diff --git a/Castle.Core/Core/ReferenceEqualityComparer.cs b/Castle.Core/Core/ReferenceEqualityComparer.cs new file mode 100644 index 0000000..3b91551 --- /dev/null +++ b/Castle.Core/Core/ReferenceEqualityComparer.cs @@ -0,0 +1,58 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Core +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.Runtime.CompilerServices; + +#if FEATURE_SERIALIZATION + [Serializable] +#endif + public class ReferenceEqualityComparer : IEqualityComparer, IEqualityComparer + { + private static readonly ReferenceEqualityComparer instance = new ReferenceEqualityComparer(); + + private ReferenceEqualityComparer() + { + } + + public int GetHashCode(object obj) + { + return RuntimeHelpers.GetHashCode(obj); + } + + bool IEqualityComparer.Equals(object x, object y) + { + return ReferenceEquals(x, y); + } + + bool IEqualityComparer.Equals(T x, T y) + { + return ReferenceEquals(x, y); + } + + int IEqualityComparer.GetHashCode(T obj) + { + return RuntimeHelpers.GetHashCode(obj); + } + + public static ReferenceEqualityComparer Instance + { + get { return instance; } + } + } +} \ No newline at end of file diff --git a/Castle.Core/Core/ReflectionBasedDictionaryAdapter.cs b/Castle.Core/Core/ReflectionBasedDictionaryAdapter.cs new file mode 100644 index 0000000..3080f05 --- /dev/null +++ b/Castle.Core/Core/ReflectionBasedDictionaryAdapter.cs @@ -0,0 +1,299 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Core +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.Linq; + using System.Reflection; + + /// + /// Readonly implementation of which uses an anonymous object as its source. Uses names of properties as keys, and property values as... well - values. Keys are not case sensitive. + /// + public sealed class ReflectionBasedDictionaryAdapter : IDictionary + { + private readonly Dictionary properties = + new Dictionary(StringComparer.OrdinalIgnoreCase); + + /// + /// Initializes a new instance of the class. + /// + /// The target. + public ReflectionBasedDictionaryAdapter(object target) + { + if (target == null) + { + throw new ArgumentNullException(nameof(target)); + } + Read(properties, target); + } + + /// + /// Gets the number of elements contained in the . + /// + /// The number of elements contained in the . + public int Count + { + get { return properties.Count; } + } + + /// + /// Gets a value indicating whether access to the is synchronized (thread safe). + /// + /// true if access to the is synchronized (thread safe); otherwise, false. + public bool IsSynchronized + { + get { return false; } + } + + /// + /// Gets an object that can be used to synchronize access to the . + /// + /// An object that can be used to synchronize access to the . + public object SyncRoot + { + get { return properties; } + } + + /// + /// Gets a value indicating whether the object is read-only. + /// + /// true if the object is read-only; otherwise, false. + public bool IsReadOnly + { + get { return true; } + } + + /// + /// Gets or sets the with the specified key. + /// + public object this[object key] + { + get + { + object value; + properties.TryGetValue(key.ToString(), out value); + return value; + } + set { throw new NotImplementedException(); } + } + + /// + /// Gets an object containing the keys of the object. + /// + /// An object containing the keys of the object. + public ICollection Keys + { + get { return properties.Keys; } + } + + /// + /// Gets an object containing the values in the object. + /// + /// An object containing the values in the object. + public ICollection Values + { + get { return properties.Values; } + } + + /// + /// Gets a value indicating whether the object has a fixed size. + /// + /// true if the object has a fixed size; otherwise, false. + bool IDictionary.IsFixedSize + { + get { throw new NotImplementedException(); } + } + + /// + /// Adds an element with the provided key and value to the object. + /// + /// The to use as the key of the element to add. + /// The to use as the value of the element to add. + /// + /// is null. + /// An element with the same key already exists in the object. + /// The is read-only.-or- The has a fixed size. + public void Add(object key, object value) + { + throw new NotImplementedException(); + } + + /// + /// Removes all elements from the object. + /// + /// The object is read-only. + public void Clear() + { + throw new NotImplementedException(); + } + + /// + /// Determines whether the object contains an element with the specified key. + /// + /// The key to locate in the object. + /// + /// true if the contains an element with the key; otherwise, false. + /// + /// + /// is null. + public bool Contains(object key) + { + return properties.ContainsKey(key.ToString()); + } + + /// + /// Removes the element with the specified key from the object. + /// + /// The key of the element to remove. + /// + /// is null. + /// The object is read-only.-or- The has a fixed size. + public void Remove(object key) + { + } + + /// + /// Returns an enumerator that iterates through a collection. + /// + /// + /// An object that can be used to iterate through the collection. + /// + public IEnumerator GetEnumerator() + { + return new DictionaryEntryEnumeratorAdapter(properties.GetEnumerator()); + } + + /// + /// Copies the elements of the to an , starting at a particular index. + /// + /// The one-dimensional that is the destination of the elements copied from . The must have zero-based indexing. + /// The zero-based index in at which copying begins. + /// + /// is null. + /// + /// is less than zero. + /// + /// is multidimensional.-or- is equal to or greater than the length of .-or- The number of elements in the source is greater than the available space from to the end of the destination . + /// The type of the source cannot be cast automatically to the type of the destination . + void ICollection.CopyTo(Array array, int index) + { + throw new NotImplementedException(); + } + + /// + /// Returns an object for the object. + /// + /// + /// An object for the object. + /// + IDictionaryEnumerator IDictionary.GetEnumerator() + { + return new DictionaryEntryEnumeratorAdapter(properties.GetEnumerator()); + } + + /// + /// Reads values of properties from and inserts them into using property names as keys. + /// + public static void Read(IDictionary targetDictionary, object valuesAsAnonymousObject) + { + var targetType = valuesAsAnonymousObject.GetType(); + foreach (var property in GetReadableProperties(targetType)) + { + var value = GetPropertyValue(valuesAsAnonymousObject, property); + targetDictionary[property.Name] = value; + } + } + + private static object GetPropertyValue(object target, PropertyInfo property) + { + return property.GetValue(target, null); + } + + private static IEnumerable GetReadableProperties(Type targetType) + { + return targetType.GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(IsReadable); + } + + private static bool IsReadable(PropertyInfo property) + { + return property.CanRead && property.GetIndexParameters().Length == 0; + } + + private class DictionaryEntryEnumeratorAdapter : IDictionaryEnumerator + { + private readonly IDictionaryEnumerator enumerator; + private KeyValuePair current; + + public DictionaryEntryEnumeratorAdapter(IDictionaryEnumerator enumerator) + { + this.enumerator = enumerator; + } + + public DictionaryEntry Entry + { + get { return new DictionaryEntry(Key, Value); } + } + + public object Key + { + get { return current.Key; } + } + + public object Value + { + get { return current.Value; } + } + + public object Current + { + get { return new DictionaryEntry(Key, Value); } + } + + public bool MoveNext() + { + var moved = enumerator.MoveNext(); + + if (moved) + { + current = (KeyValuePair)enumerator.Current; + } + + return moved; + } + + public void Reset() + { + enumerator.Reset(); + } + } + } +} \ No newline at end of file diff --git a/Castle.Core/Core/Resource/AbstractResource.cs b/Castle.Core/Core/Resource/AbstractResource.cs new file mode 100644 index 0000000..e339cd4 --- /dev/null +++ b/Castle.Core/Core/Resource/AbstractResource.cs @@ -0,0 +1,46 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Core.Resource +{ + using System; + using System.IO; + using System.Text; + + public abstract class AbstractResource : IResource + { + protected static readonly string DefaultBasePath = AppDomain.CurrentDomain.BaseDirectory; + + public virtual string FileBasePath + { + get { return DefaultBasePath; } + } + + public abstract TextReader GetStreamReader(); + + public abstract TextReader GetStreamReader(Encoding encoding); + + public abstract IResource CreateRelative(string relativePath); + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + } + } +} diff --git a/Castle.Core/Core/Resource/AbstractStreamResource.cs b/Castle.Core/Core/Resource/AbstractStreamResource.cs new file mode 100644 index 0000000..3afa4c8 --- /dev/null +++ b/Castle.Core/Core/Resource/AbstractStreamResource.cs @@ -0,0 +1,54 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Core.Resource +{ + using System.IO; + using System.Text; + + public delegate Stream StreamFactory(); + + /// + /// + /// + public abstract class AbstractStreamResource : AbstractResource + { + /// + /// This returns a new stream instance each time it is called. + /// It is the responsibility of the caller to dispose of this stream + /// + private StreamFactory createStream; + + ~AbstractStreamResource() + { + Dispose(false); + } + + public StreamFactory CreateStream + { + get { return createStream; } + set { createStream = value; } + } + + public override TextReader GetStreamReader() + { + return new StreamReader(CreateStream()); + } + + public override TextReader GetStreamReader(Encoding encoding) + { + return new StreamReader(CreateStream(), encoding); + } + } +} \ No newline at end of file diff --git a/Castle.Core/Core/Resource/AssemblyBundleResource.cs b/Castle.Core/Core/Resource/AssemblyBundleResource.cs new file mode 100644 index 0000000..272c036 --- /dev/null +++ b/Castle.Core/Core/Resource/AssemblyBundleResource.cs @@ -0,0 +1,72 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Core.Resource +{ + using System; + using System.Globalization; + using System.IO; + using System.Reflection; + using System.Resources; + using System.Text; + + public class AssemblyBundleResource : AbstractResource + { + private readonly CustomUri resource; + + public AssemblyBundleResource(CustomUri resource) + { + this.resource = resource; + } + + public override TextReader GetStreamReader() + { + var assembly = ObtainAssembly(resource.Host); + + var paths = resource.Path.Split(new[] {'/'}, StringSplitOptions.RemoveEmptyEntries); + if (paths.Length != 2) + { + throw new ResourceException("AssemblyBundleResource does not support paths with more than 2 levels in depth. See " + + resource.Path); + } + + var rm = new ResourceManager(paths[0], assembly); + + return new StringReader(rm.GetString(paths[1])); + } + + public override TextReader GetStreamReader(Encoding encoding) + { + return GetStreamReader(); + } + + public override IResource CreateRelative(string relativePath) + { + throw new NotImplementedException(); + } + + private static Assembly ObtainAssembly(string assemblyName) + { + try + { + return Assembly.Load(assemblyName); + } + catch (Exception ex) + { + var message = string.Format(CultureInfo.InvariantCulture, "The assembly {0} could not be loaded", assemblyName); + throw new ResourceException(message, ex); + } + } + } +} \ No newline at end of file diff --git a/Castle.Core/Core/Resource/AssemblyResource.cs b/Castle.Core/Core/Resource/AssemblyResource.cs new file mode 100644 index 0000000..08882f2 --- /dev/null +++ b/Castle.Core/Core/Resource/AssemblyResource.cs @@ -0,0 +1,156 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Core.Resource +{ + using System; + using System.Globalization; + using System.IO; + using System.Reflection; + + public class AssemblyResource : AbstractStreamResource + { + private string assemblyName; + private string resourcePath; + private string basePath; + + public AssemblyResource(CustomUri resource) + { + CreateStream = delegate + { + return CreateResourceFromUri(resource, null); + }; + } + + public AssemblyResource(CustomUri resource, string basePath) + { + CreateStream = delegate + { + return CreateResourceFromUri(resource, basePath); + }; + } + + public AssemblyResource(string resource) + { + CreateStream = delegate + { + return CreateResourceFromPath(resource, basePath); + }; + } + + public override IResource CreateRelative(string relativePath) + { + throw new NotImplementedException(); + } + + public override string ToString() + { + return string.Format(CultureInfo.CurrentCulture, "AssemblyResource: [{0}] [{1}]", assemblyName, resourcePath); + } + + private Stream CreateResourceFromPath(string resource, string path) + { + if (!resource.StartsWith("assembly" + CustomUri.SchemeDelimiter, StringComparison.CurrentCulture)) + { + resource = "assembly" + CustomUri.SchemeDelimiter + resource; + } + + return CreateResourceFromUri(new CustomUri(resource), path); + } + + private Stream CreateResourceFromUri(CustomUri resourcex, string path) + { + if (resourcex == null) throw new ArgumentNullException(nameof(resourcex)); + + assemblyName = resourcex.Host; + resourcePath = ConvertToResourceName(assemblyName, resourcex.Path); + + Assembly assembly = ObtainAssembly(assemblyName); + + string[] names = assembly.GetManifestResourceNames(); + + string nameFound = GetNameFound(names); + + if (nameFound == null) + { + resourcePath = resourcex.Path.Replace('/', '.').Substring(1); + nameFound = GetNameFound(names); + } + + if (nameFound == null) + { + string message = string.Format(CultureInfo.InvariantCulture, "The assembly resource {0} could not be located", resourcePath); + throw new ResourceException(message); + } + + basePath = ConvertToPath(resourcePath); + + return assembly.GetManifestResourceStream(nameFound); + } + + private string GetNameFound(string[] names) + { + string nameFound = null; + foreach(string name in names) + { + if (string.Compare(resourcePath, name, StringComparison.OrdinalIgnoreCase) == 0) + { + nameFound = name; + break; + } + } + return nameFound; + } + + private string ConvertToResourceName(string assembly, string resource) + { + assembly = GetSimpleName(assembly); + // TODO: use path for relative name construction + return string.Format(CultureInfo.CurrentCulture, "{0}{1}", assembly, resource.Replace('/', '.')); + } + + private string GetSimpleName(string assembly) + { + int indexOfComma = assembly.IndexOf(','); + if(indexOfComma<0) + { + return assembly; + } + return assembly.Substring(0, indexOfComma); + } + + private string ConvertToPath(string resource) + { + string path = resource.Replace('.', '/'); + if (path[0] != '/') + { + path = string.Format(CultureInfo.CurrentCulture, "/{0}", path); + } + return path; + } + + private static Assembly ObtainAssembly(string assemblyName) + { + try + { + return Assembly.Load(assemblyName); + } + catch (Exception ex) + { + string message = string.Format(CultureInfo.InvariantCulture, "The assembly {0} could not be loaded", assemblyName); + throw new ResourceException(message, ex); + } + } + } +} diff --git a/Castle.Core/Core/Resource/AssemblyResourceFactory.cs b/Castle.Core/Core/Resource/AssemblyResourceFactory.cs new file mode 100644 index 0000000..1122c44 --- /dev/null +++ b/Castle.Core/Core/Resource/AssemblyResourceFactory.cs @@ -0,0 +1,41 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Core.Resource +{ + using System; + + public class AssemblyResourceFactory : IResourceFactory + { + public bool Accept(CustomUri uri) + { + return "assembly".Equals(uri.Scheme); + } + + public IResource Create(CustomUri uri) + { + return Create(uri, null); + } + + public IResource Create(CustomUri uri, string basePath) + { + if (basePath == null) + { + return new AssemblyResource(uri); + } + + return new AssemblyResource(uri, basePath); + } + } +} \ No newline at end of file diff --git a/Castle.Core/Core/Resource/ConfigResource.cs b/Castle.Core/Core/Resource/ConfigResource.cs new file mode 100644 index 0000000..cdefe0d --- /dev/null +++ b/Castle.Core/Core/Resource/ConfigResource.cs @@ -0,0 +1,78 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#if FEATURE_SYSTEM_CONFIGURATION + +namespace Castle.Core.Resource +{ + using System; + using System.Configuration; + using System.Globalization; + using System.IO; + using System.Text; + using System.Xml; + + public class ConfigResource : AbstractResource + { + private readonly XmlNode configSectionNode; + private readonly string sectionName; + + public ConfigResource() : this("castle") + { + } + + public ConfigResource(CustomUri uri) : this(uri.Host) + { + } + + public ConfigResource(string sectionName) + { + this.sectionName = sectionName; + + XmlNode node = (XmlNode) ConfigurationManager.GetSection(sectionName); + + if (node == null) + { + string message = string.Format(CultureInfo.InvariantCulture, + "Could not find section '{0}' in the configuration file associated with this domain.", sectionName); + throw new ConfigurationErrorsException(message); + } + + // TODO: Check whether it's CData section + configSectionNode = node; + } + + public override TextReader GetStreamReader() + { + return new StringReader(configSectionNode.OuterXml); + } + + public override TextReader GetStreamReader(Encoding encoding) + { + throw new NotSupportedException("Encoding is not supported"); + } + + public override IResource CreateRelative(string relativePath) + { + return new ConfigResource(relativePath); + } + + public override string ToString() + { + return string.Format(CultureInfo.CurrentCulture, "ConfigResource: [{0}]", sectionName); + } + } +} + +#endif \ No newline at end of file diff --git a/Castle.Core/Core/Resource/ConfigResourceFactory.cs b/Castle.Core/Core/Resource/ConfigResourceFactory.cs new file mode 100644 index 0000000..bb94c75 --- /dev/null +++ b/Castle.Core/Core/Resource/ConfigResourceFactory.cs @@ -0,0 +1,44 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#if FEATURE_SYSTEM_CONFIGURATION + +namespace Castle.Core.Resource +{ + using System; + + public class ConfigResourceFactory : IResourceFactory + { + public ConfigResourceFactory() + { + } + + public bool Accept(CustomUri uri) + { + return "config".Equals(uri.Scheme); + } + + public IResource Create(CustomUri uri) + { + return new ConfigResource(uri); + } + + public IResource Create(CustomUri uri, string basePath) + { + return Create(uri); + } + } +} + +#endif \ No newline at end of file diff --git a/Castle.Core/Core/Resource/CustomUri.cs b/Castle.Core/Core/Resource/CustomUri.cs new file mode 100644 index 0000000..fe19ab1 --- /dev/null +++ b/Castle.Core/Core/Resource/CustomUri.cs @@ -0,0 +1,139 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Core.Resource +{ + using System; + using System.Text; + +#if FEATURE_SERIALIZATION + [Serializable] +#endif + public sealed class CustomUri + { + public static readonly string SchemeDelimiter = "://"; + public static readonly string UriSchemeFile = "file"; + public static readonly string UriSchemeAssembly = "assembly"; + + private string scheme; + private string host; + private string path; + private bool isUnc; + private bool isFile; + private bool isAssembly; + + public CustomUri(string resourceIdentifier) + { + if (resourceIdentifier == null) + { + throw new ArgumentNullException(nameof(resourceIdentifier)); + } + if (resourceIdentifier == string.Empty) + { + throw new ArgumentException("Empty resource identifier is not allowed", nameof(resourceIdentifier)); + } + + ParseIdentifier(resourceIdentifier); + } + + public bool IsUnc + { + get { return isUnc; } + } + + public bool IsFile + { + get { return isFile; } + } + + public bool IsAssembly + { + get { return isAssembly; } + } + + public string Scheme + { + get { return scheme; } + } + + public string Host + { + get { return host; } + } + + public string Path + { + get { return path; } + } + + private void ParseIdentifier(string identifier) + { + int comma = identifier.IndexOf(':'); + + if (comma == -1 && !(identifier[0] == '\\' && identifier[1] == '\\') && identifier[0] != '/') + { + throw new ArgumentException("Invalid Uri: no scheme delimiter found on " + identifier); + } + + bool translateSlashes = true; + + if (identifier[0] == '\\' && identifier[1] == '\\') + { + // Unc + + isUnc = true; + isFile = true; + scheme = UriSchemeFile; + translateSlashes = false; + } + else if (identifier[comma + 1] == '/' && identifier[comma + 2] == '/') + { + // Extract scheme + + scheme = identifier.Substring(0, comma); + + isFile = (scheme == UriSchemeFile); + isAssembly = (scheme == UriSchemeAssembly); + + identifier = identifier.Substring(comma + SchemeDelimiter.Length); + } + else + { + isFile = true; + scheme = UriSchemeFile; + } + + var sb = new StringBuilder(); + foreach(char ch in identifier.ToCharArray()) + { + if (translateSlashes && (ch == '\\' || ch == '/')) + { + if (host == null && !IsFile) + { + host = sb.ToString(); + sb.Length = 0; + } + + sb.Append('/'); + } + else + { + sb.Append(ch); + } + } + + path = Environment.ExpandEnvironmentVariables(sb.ToString()); + } + } +} \ No newline at end of file diff --git a/Castle.Core/Core/Resource/FileResource.cs b/Castle.Core/Core/Resource/FileResource.cs new file mode 100644 index 0000000..39854ba --- /dev/null +++ b/Castle.Core/Core/Resource/FileResource.cs @@ -0,0 +1,119 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Core.Resource +{ + using System; + using System.Globalization; + using System.IO; + + /// + /// + /// + public class FileResource : AbstractStreamResource + { + private string filePath; + private string basePath; + + public FileResource(CustomUri resource) + { + CreateStream = delegate + { + return CreateStreamFromUri(resource, DefaultBasePath); + }; + } + + public FileResource(CustomUri resource, string basePath) + { + CreateStream = delegate + { + return CreateStreamFromUri(resource, basePath); + }; + } + + public FileResource(string resourceName) + { + CreateStream = delegate + { + return CreateStreamFromPath(resourceName, DefaultBasePath); + }; + } + + public FileResource(string resourceName, string basePath) + { + CreateStream = delegate + { + return CreateStreamFromPath(resourceName, basePath); + }; + } + + public override string ToString() + { + return string.Format(CultureInfo.CurrentCulture, "FileResource: [{0}] [{1}]", filePath, basePath); + } + + public override string FileBasePath + { + get { return basePath; } + } + + public override IResource CreateRelative(string relativePath) + { + return new FileResource(relativePath, basePath); + } + + private Stream CreateStreamFromUri(CustomUri resource, string rootPath) + { + if (resource == null) throw new ArgumentNullException(nameof(resource)); + if (rootPath == null) throw new ArgumentNullException(nameof(rootPath)); + + if (!resource.IsFile) + throw new ArgumentException("The specified resource is not a file", nameof(resource)); + + return CreateStreamFromPath(resource.Path, rootPath); + } + + private Stream CreateStreamFromPath(string resourcePath, string rootPath) + { + if (resourcePath == null) + throw new ArgumentNullException(nameof(resourcePath)); + if (rootPath == null) + throw new ArgumentNullException(nameof(rootPath)); + + if (!Path.IsPathRooted(resourcePath) || !File.Exists(resourcePath)) + { + // For a relative path, we use the basePath to + // resolve the full path + + resourcePath = Path.Combine(rootPath, resourcePath); + } + + CheckFileExists(resourcePath); + + this.filePath = Path.GetFileName(resourcePath); + this.basePath = Path.GetDirectoryName(resourcePath); + + return File.OpenRead(resourcePath); + } + + private static void CheckFileExists(string path) + { + if (!File.Exists(path)) + { + string message = string.Format(CultureInfo.InvariantCulture, "File {0} could not be found", new FileInfo(path).FullName); + throw new ResourceException(message); + } + } + } +} \ No newline at end of file diff --git a/Castle.Core/Core/Resource/FileResourceFactory.cs b/Castle.Core/Core/Resource/FileResourceFactory.cs new file mode 100644 index 0000000..2d8fead --- /dev/null +++ b/Castle.Core/Core/Resource/FileResourceFactory.cs @@ -0,0 +1,46 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Core.Resource +{ + using System; + + /// + /// + /// + public class FileResourceFactory : IResourceFactory + { + public FileResourceFactory() + { + } + + public bool Accept(CustomUri uri) + { + return "file".Equals(uri.Scheme); + } + + public IResource Create(CustomUri uri) + { + return Create(uri, null); + } + + public IResource Create(CustomUri uri, string basePath) + { + if (basePath != null) + return new FileResource(uri, basePath); + else + return new FileResource(uri); + } + } +} diff --git a/Castle.Core/Core/Resource/IResource.cs b/Castle.Core/Core/Resource/IResource.cs new file mode 100644 index 0000000..9651ed2 --- /dev/null +++ b/Castle.Core/Core/Resource/IResource.cs @@ -0,0 +1,56 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Core.Resource +{ + using System; + using System.IO; + using System.Text; + + /// + /// Represents a 'streamable' resource. Can + /// be a file, a resource in an assembly. + /// + public interface IResource : IDisposable + { + /// + /// Only valid for resources that + /// can be obtained through relative paths + /// + string FileBasePath { get; } + + /// + /// Returns a reader for the stream + /// + /// + /// It's up to the caller to dispose the reader. + /// + TextReader GetStreamReader(); + + /// + /// Returns a reader for the stream + /// + /// + /// It's up to the caller to dispose the reader. + /// + TextReader GetStreamReader(Encoding encoding); + + /// + /// Returns an instance of + /// created according to the relativePath + /// using itself as the root. + /// + IResource CreateRelative(string relativePath); + } +} \ No newline at end of file diff --git a/Castle.Core/Core/Resource/IResourceFactory.cs b/Castle.Core/Core/Resource/IResourceFactory.cs new file mode 100644 index 0000000..7950da1 --- /dev/null +++ b/Castle.Core/Core/Resource/IResourceFactory.cs @@ -0,0 +1,48 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Core.Resource +{ + using System; + + /// + /// Depicts the contract for resource factories. + /// + public interface IResourceFactory + { + /// + /// Used to check whether the resource factory + /// is able to deal with the given resource + /// identifier. + /// + /// + /// Implementors should return true + /// only if the given identifier is supported + /// by the resource factory + /// + bool Accept(CustomUri uri); + + /// + /// Creates an instance + /// for the given resource identifier + /// + IResource Create(CustomUri uri); + + /// + /// Creates an instance + /// for the given resource identifier + /// + IResource Create(CustomUri uri, string basePath); + } +} \ No newline at end of file diff --git a/Castle.Core/Core/Resource/ResourceException.cs b/Castle.Core/Core/Resource/ResourceException.cs new file mode 100644 index 0000000..f71e2ea --- /dev/null +++ b/Castle.Core/Core/Resource/ResourceException.cs @@ -0,0 +1,39 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Core.Resource +{ + using System; + using System.Runtime.Serialization; + + [Serializable] + public class ResourceException : Exception + { + public ResourceException() + { + } + + public ResourceException(string message) : base(message) + { + } + + public ResourceException(string message, Exception innerException) : base(message, innerException) + { + } + + protected ResourceException(SerializationInfo info, StreamingContext context) : base(info, context) + { + } + } +} \ No newline at end of file diff --git a/Castle.Core/Core/Resource/StaticContentResource.cs b/Castle.Core/Core/Resource/StaticContentResource.cs new file mode 100644 index 0000000..8182afc --- /dev/null +++ b/Castle.Core/Core/Resource/StaticContentResource.cs @@ -0,0 +1,48 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Core.Resource +{ + using System; + using System.IO; + using System.Text; + + /// + /// Adapts a static string content as an + /// + public class StaticContentResource : AbstractResource + { + private readonly string contents; + + public StaticContentResource(string contents) + { + this.contents = contents; + } + + public override TextReader GetStreamReader() + { + return new StringReader(contents); + } + + public override TextReader GetStreamReader(Encoding encoding) + { + throw new NotImplementedException(); + } + + public override IResource CreateRelative(string relativePath) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/Castle.Core/Core/Resource/UncResource.cs b/Castle.Core/Core/Resource/UncResource.cs new file mode 100644 index 0000000..3fcc5f6 --- /dev/null +++ b/Castle.Core/Core/Resource/UncResource.cs @@ -0,0 +1,102 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Core.Resource +{ + using System; + using System.Globalization; + using System.IO; + + /// + /// Enable access to files on network shares + /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Unc")] + public class UncResource : AbstractStreamResource + { + private string basePath; + private string filePath; + + public UncResource(CustomUri resource) + { + CreateStream = delegate + { + return CreateStreamFromUri(resource, DefaultBasePath); + }; + } + + public UncResource(CustomUri resource, string basePath) + { + CreateStream = delegate + { + return CreateStreamFromUri(resource, basePath); + }; + } + + public UncResource(string resourceName) : this(new CustomUri(resourceName)) + { + } + + public UncResource(string resourceName, string basePath) : this(new CustomUri(resourceName), basePath) + { + } + + public override string FileBasePath + { + get { return basePath; } + } + + public override IResource CreateRelative(string relativePath) + { + return new UncResource(Path.Combine(basePath, relativePath)); + } + + public override string ToString() + { + return string.Format(CultureInfo.CurrentCulture, "UncResource: [{0}] [{1}]", filePath, basePath); + } + + private Stream CreateStreamFromUri(CustomUri resource, string rootPath) + { + if (resource == null) + throw new ArgumentNullException(nameof(resource)); + if (!resource.IsUnc) + throw new ArgumentException("Resource must be an Unc", nameof(resource)); + if (!resource.IsFile) + throw new ArgumentException("The specified resource is not a file", nameof(resource)); + + string resourcePath = resource.Path; + + if (!File.Exists(resourcePath) && rootPath != null) + { + resourcePath = Path.Combine(rootPath, resourcePath); + } + + filePath = Path.GetFileName(resourcePath); + basePath = Path.GetDirectoryName(resourcePath); + + CheckFileExists(resourcePath); + + return File.OpenRead(resourcePath); + } + + private static void CheckFileExists(string path) + { + if (!File.Exists(path)) + { + string message = string.Format(CultureInfo.InvariantCulture, "File {0} could not be found", path); + throw new ResourceException(message); + } + } + } +} \ No newline at end of file diff --git a/Castle.Core/Core/Resource/UncResourceFactory.cs b/Castle.Core/Core/Resource/UncResourceFactory.cs new file mode 100644 index 0000000..6a66730 --- /dev/null +++ b/Castle.Core/Core/Resource/UncResourceFactory.cs @@ -0,0 +1,40 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Core.Resource +{ + using System; + + public class UncResourceFactory : IResourceFactory + { + public UncResourceFactory() + { + } + + public bool Accept(CustomUri uri) + { + return uri.IsUnc; + } + + public IResource Create(CustomUri uri) + { + return new UncResource(uri); + } + + public IResource Create(CustomUri uri, string basePath) + { + return new UncResource(uri, basePath); + } + } +} \ No newline at end of file diff --git a/Castle.Core/Core/Smtp/DefaultSmtpSender.cs b/Castle.Core/Core/Smtp/DefaultSmtpSender.cs new file mode 100644 index 0000000..030b24d --- /dev/null +++ b/Castle.Core/Core/Smtp/DefaultSmtpSender.cs @@ -0,0 +1,250 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma warning disable 618 // Mono marked SmtpClient obsolete + +namespace Castle.Core.Smtp +{ + using System; + using System.Collections.Generic; + using System.ComponentModel; + using System.Net; + using System.Net.Mail; + + using Castle.Core.Internal; + + /// + /// Default implementation. + /// + public class DefaultSmtpSender : IEmailSender + { + private bool asyncSend; + private readonly string hostname; + private int port = 25; + private int? timeout; + private bool useSsl; + + /// + /// Initializes a new instance of the class based on the configuration provided in the application configuration file. + /// + /// + /// This constructor is based on the default configuration in the application configuration file. + /// + public DefaultSmtpSender() { } + + /// + /// This service implementation + /// requires a host name in order to work + /// + /// The smtp server name + public DefaultSmtpSender(string hostname) + { + this.hostname = hostname; + } + + /// + /// Gets or sets the port used to + /// access the SMTP server + /// + public int Port + { + get { return port; } + set { port = value; } + } + + /// + /// Gets the hostname. + /// + /// The hostname. + public string Hostname + { + get { return hostname; } + } + + /// + /// Gets or sets a value which is used to + /// configure if emails are going to be sent asynchronously or not. + /// + public bool AsyncSend + { + get { return asyncSend; } + set { asyncSend = value; } + } + + /// + /// Gets or sets a value that specifies + /// the amount of time after which a synchronous Send call times out. + /// + public int Timeout + { + get { return timeout.HasValue ? timeout.Value : 0; } + set { timeout = value; } + } + + /// + /// Gets or sets a value indicating whether the email should be sent using + /// a secure communication channel. + /// + /// true if should use SSL; otherwise, false. + public bool UseSsl + { + get { return useSsl; } + set { useSsl = value; } + } + + /// + /// Sends a message. + /// + /// If any of the parameters is null + /// From field + /// To field + /// e-mail's subject + /// message's body + public void Send(string from, string to, string subject, string messageText) + { + if (from == null) throw new ArgumentNullException(nameof(from)); + if (to == null) throw new ArgumentNullException(nameof(to)); + if (subject == null) throw new ArgumentNullException(nameof(subject)); + if (messageText == null) throw new ArgumentNullException(nameof(messageText)); + + Send(new MailMessage(from, to, subject, messageText)); + } + + /// + /// Sends a message. + /// + /// If the message is null + /// Message instance + public void Send(MailMessage message) + { + InternalSend(message); + } + + private void InternalSend(MailMessage message) + { + if (message == null) throw new ArgumentNullException(nameof(message)); + + if (asyncSend) + { + // The MailMessage must be disposed after sending the email. + // The code creates a delegate for deleting the mail and adds + // it to the smtpClient. + // After the mail is sent, the message is disposed and the + // eventHandler removed from the smtpClient. + + SmtpClient smtpClient = CreateSmtpClient(); + Guid msgGuid = new Guid(); + SendCompletedEventHandler sceh = null; + sceh = delegate(object sender, AsyncCompletedEventArgs e) + { + if (msgGuid == (Guid)e.UserState) + message.Dispose(); + // The handler itself, cannot be null, test omitted + smtpClient.SendCompleted -= sceh; + }; + smtpClient.SendCompleted += sceh; + smtpClient.SendAsync(message, msgGuid); + } + else + { + using (message) + { + SmtpClient smtpClient = CreateSmtpClient(); + + smtpClient.Send(message); + } + } + } + + public void Send(IEnumerable messages) + { + foreach (MailMessage message in messages) + { + Send(message); + } + } + + /// + /// Gets or sets the domain. + /// + /// The domain. + public string Domain { get; set; } + + /// + /// Gets or sets the name of the user. + /// + /// The name of the user. + public string UserName { get; set; } + + /// + /// Gets or sets the password. + /// + /// The password. + public string Password { get; set; } + + /// + /// Configures the sender + /// with port information and eventual credential + /// informed + /// + /// Message instance + protected virtual void Configure(SmtpClient smtpClient) + { + smtpClient.Credentials = null; + + if (HasCredentials) + { + var credentials = new NetworkCredential(UserName, Password, Domain); + smtpClient.Credentials = credentials; + } + + if (timeout.HasValue) + { + smtpClient.Timeout = timeout.Value; + } + + if (useSsl) + { + smtpClient.EnableSsl = useSsl; + } + } + + /// + /// Gets a value indicating whether credentials were informed. + /// + /// + /// if this instance has credentials; otherwise, . + /// + private bool HasCredentials + { + get { return !string.IsNullOrEmpty(UserName); } + } + + private SmtpClient CreateSmtpClient() + { + if (string.IsNullOrEmpty(hostname)) + { + // No hostname configured, use the settings provided in system.net.smtp (SmtpClient default behavior) + return new SmtpClient(); + } + + // A hostname is provided - init and configure using configured settings + var smtpClient = new SmtpClient(hostname, port); + Configure(smtpClient); + return smtpClient; + } + } +} + +#pragma warning restore 618 // Mono marked SmtpClient obsolete diff --git a/Castle.Core/Core/Smtp/IEmailSender.cs b/Castle.Core/Core/Smtp/IEmailSender.cs new file mode 100644 index 0000000..9f01f54 --- /dev/null +++ b/Castle.Core/Core/Smtp/IEmailSender.cs @@ -0,0 +1,46 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Core.Smtp +{ + using System.Collections.Generic; + using System.Net.Mail; + + /// + /// Email sender abstraction. + /// + public interface IEmailSender + { + /// + /// Sends a mail message. + /// + /// From field + /// To field + /// E-mail's subject + /// message's body + void Send(string from, string to, string subject, string messageText); + + /// + /// Sends a message. + /// + /// Message instance + void Send(MailMessage message); + + /// + /// Sends multiple messages. + /// + /// List of messages + void Send(IEnumerable messages); + } +} diff --git a/Castle.Core/Core/StringObjectDictionaryAdapter.cs b/Castle.Core/Core/StringObjectDictionaryAdapter.cs new file mode 100644 index 0000000..9cedaff --- /dev/null +++ b/Castle.Core/Core/StringObjectDictionaryAdapter.cs @@ -0,0 +1,227 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Core +{ + using System; + using System.Collections; + using System.Collections.Generic; + + public sealed class StringObjectDictionaryAdapter : IDictionary + { + private readonly IDictionary dictionary; + + public StringObjectDictionaryAdapter(IDictionary dictionary) + { + this.dictionary = dictionary; + } + + bool IDictionary.ContainsKey(string key) + { + return dictionary.Contains(key); + } + + void IDictionary.Add(string key, object value) + { + throw new NotImplementedException(); + } + + bool IDictionary.Remove(string key) + { + throw new NotImplementedException(); + } + + bool IDictionary.TryGetValue(string key, out object value) + { + value = null; + if (dictionary.Contains(key)) + { + value = dictionary[key]; + return true; + } + else + { + return false; + } + } + + object IDictionary.this[string key] + { + get { return dictionary[key]; } + set { throw new NotImplementedException(); } + } + + ICollection IDictionary.Keys + { + get + { + string[] keys = new string[Count]; + dictionary.Keys.CopyTo(keys, 0); + return keys; + } + } + + ICollection IDictionary.Values + { + get + { + object[] values = new object[Count]; + dictionary.Values.CopyTo(values, 0); + return values; + } + } + + void ICollection>.Add(KeyValuePair item) + { + throw new NotImplementedException(); + } + + bool ICollection>.Contains(KeyValuePair item) + { + throw new NotImplementedException(); + } + + void ICollection>.CopyTo(KeyValuePair[] array, int arrayIndex) + { + throw new NotImplementedException(); + } + + bool ICollection>.Remove(KeyValuePair item) + { + throw new NotImplementedException(); + } + + IEnumerator> IEnumerable>.GetEnumerator() + { + return new EnumeratorAdapter(this); + } + + public bool Contains(object key) + { + return dictionary.Contains(key); + } + + public void Add(object key, object value) + { + dictionary.Add(key, value); + } + + public void Clear() + { + dictionary.Clear(); + } + + public void Remove(object key) + { + dictionary.Remove(key); + } + + public object this[object key] + { + get { return dictionary[key]; } + set { dictionary[key] = value; } + } + + public ICollection Keys + { + get { return dictionary.Keys; } + } + + public ICollection Values + { + get { return dictionary.Values; } + } + + public bool IsReadOnly + { + get { return dictionary.IsReadOnly; } + } + + public bool IsFixedSize + { + get { return dictionary.IsFixedSize; } + } + + public void CopyTo(Array array, int index) + { + dictionary.CopyTo(array, index); + } + + public int Count + { + get { return dictionary.Count; } + } + + public object SyncRoot + { + get { return dictionary.SyncRoot; } + } + + public bool IsSynchronized + { + get { return dictionary.IsSynchronized; } + } + + public IEnumerator GetEnumerator() + { + return ((IEnumerable) dictionary).GetEnumerator(); + } + + internal class EnumeratorAdapter : IEnumerator> + { + private readonly StringObjectDictionaryAdapter adapter; + private IEnumerator keyEnumerator; + private string currentKey; + private object currentValue; + + public EnumeratorAdapter(StringObjectDictionaryAdapter adapter) + { + this.adapter = adapter; + keyEnumerator = ((IDictionary) adapter).Keys.GetEnumerator(); + } + + public bool MoveNext() + { + if (keyEnumerator.MoveNext()) + { + currentKey = keyEnumerator.Current; + currentValue = adapter[currentKey]; + return true; + } + + return false; + } + + public void Reset() + { + keyEnumerator.Reset(); + } + + public object Current + { + get { return new KeyValuePair(currentKey, currentValue); } + } + + KeyValuePair IEnumerator>.Current + { + get { return new KeyValuePair(currentKey, currentValue); } + } + + public void Dispose() + { + GC.SuppressFinalize(this); + } + } + } +} diff --git a/Castle.Core/DynamicProxy/AbstractInvocation.cs b/Castle.Core/DynamicProxy/AbstractInvocation.cs new file mode 100644 index 0000000..30197b8 --- /dev/null +++ b/Castle.Core/DynamicProxy/AbstractInvocation.cs @@ -0,0 +1,211 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy +{ + using System; + using System.Diagnostics; + using System.Reflection; + + public abstract class AbstractInvocation : IInvocation + { + private readonly IInterceptor[] interceptors; + private readonly object[] arguments; + private int currentInterceptorIndex = -1; + private Type[] genericMethodArguments; + private readonly MethodInfo proxiedMethod; + protected readonly object proxyObject; + + protected AbstractInvocation( + object proxy, + IInterceptor[] interceptors, + MethodInfo proxiedMethod, + object[] arguments) + { + Debug.Assert(proxiedMethod != null); + proxyObject = proxy; + this.interceptors = interceptors; + this.proxiedMethod = proxiedMethod; + this.arguments = arguments; + } + + public void SetGenericMethodArguments(Type[] arguments) + { + genericMethodArguments = arguments; + } + + public abstract object InvocationTarget { get; } + + public abstract Type TargetType { get; } + + public abstract MethodInfo MethodInvocationTarget { get; } + + public Type[] GenericArguments + { + get { return genericMethodArguments; } + } + + public object Proxy + { + get { return proxyObject; } + } + + public MethodInfo Method + { + get { return proxiedMethod; } + } + + public MethodInfo GetConcreteMethod() + { + return EnsureClosedMethod(Method); + } + + public MethodInfo GetConcreteMethodInvocationTarget() + { + // it is ensured by the InvocationHelper that method will be closed + var method = MethodInvocationTarget; + Debug.Assert(method == null || method.IsGenericMethodDefinition == false, + "method == null || method.IsGenericMethodDefinition == false"); + return method; + } + + public object ReturnValue { get; set; } + + public object[] Arguments + { + get { return arguments; } + } + + public void SetArgumentValue(int index, object value) + { + arguments[index] = value; + } + + public object GetArgumentValue(int index) + { + return arguments[index]; + } + + public void Proceed() + { + if (interceptors == null) + // not yet fully initialized? probably, an intercepted method is called while we are being deserialized + { + InvokeMethodOnTarget(); + return; + } + + currentInterceptorIndex++; + try + { + if (currentInterceptorIndex == interceptors.Length) + { + InvokeMethodOnTarget(); + } + else if (currentInterceptorIndex > interceptors.Length) + { + throw new InvalidOperationException( + "Cannot proceed past the end of the interception pipeline. " + + "This likely signifies a bug in the calling code."); + } + else + { + interceptors[currentInterceptorIndex].Intercept(this); + } + } + finally + { + currentInterceptorIndex--; + } + } + + public IInvocationProceedInfo CaptureProceedInfo() + { + return new ProceedInfo(this); + } + + protected abstract void InvokeMethodOnTarget(); + + protected void ThrowOnNoTarget() + { + // let's try to build as friendly message as we can + string interceptorsMessage; + if (interceptors.Length == 0) + { + interceptorsMessage = "There are no interceptors specified"; + } + else + { + interceptorsMessage = "The interceptor attempted to 'Proceed'"; + } + + string methodKindIs; + string methodKindDescription; + if (Method.DeclaringType.IsClass && Method.IsAbstract) + { + methodKindIs = "is abstract"; + methodKindDescription = "an abstract method"; + } + else + { + methodKindIs = "has no target"; + methodKindDescription = "method without target"; + } + + var message = string.Format("This is a DynamicProxy2 error: {0} for method '{1}' which {2}. " + + "When calling {3} there is no implementation to 'proceed' to and " + + "it is the responsibility of the interceptor to mimic the implementation " + + "(set return value, out arguments etc)", + interceptorsMessage, Method, methodKindIs, methodKindDescription); + + throw new NotImplementedException(message); + } + + private MethodInfo EnsureClosedMethod(MethodInfo method) + { + if (method.ContainsGenericParameters) + { + Debug.Assert(genericMethodArguments != null); + return method.GetGenericMethodDefinition().MakeGenericMethod(genericMethodArguments); + } + return method; + } + + private sealed class ProceedInfo : IInvocationProceedInfo + { + private readonly AbstractInvocation invocation; + private readonly int interceptorIndex; + + public ProceedInfo(AbstractInvocation invocation) + { + this.invocation = invocation; + this.interceptorIndex = invocation.currentInterceptorIndex; + } + + public void Invoke() + { + var previousInterceptorIndex = invocation.currentInterceptorIndex; + try + { + invocation.currentInterceptorIndex = interceptorIndex; + invocation.Proceed(); + } + finally + { + invocation.currentInterceptorIndex = previousInterceptorIndex; + } + } + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/AllMethodsHook.cs b/Castle.Core/DynamicProxy/AllMethodsHook.cs new file mode 100644 index 0000000..9424c14 --- /dev/null +++ b/Castle.Core/DynamicProxy/AllMethodsHook.cs @@ -0,0 +1,56 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy +{ + using System; + using System.Collections.Generic; + using System.Reflection; + +#if FEATURE_SERIALIZATION + [Serializable] +#endif + public class AllMethodsHook : IProxyGenerationHook + { + protected static readonly ICollection SkippedTypes = new[] + { + typeof(object), + typeof(MarshalByRefObject), + typeof(ContextBoundObject) + }; + + public virtual bool ShouldInterceptMethod(Type type, MethodInfo methodInfo) + { + return SkippedTypes.Contains(methodInfo.DeclaringType) == false; + } + + public virtual void NonProxyableMemberNotification(Type type, MemberInfo memberInfo) + { + } + + public virtual void MethodsInspected() + { + } + + public override bool Equals(object obj) + { + return obj != null && obj.GetType() == GetType(); + } + + public override int GetHashCode() + { + return GetType().GetHashCode(); + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Contributors/ClassMembersCollector.cs b/Castle.Core/DynamicProxy/Contributors/ClassMembersCollector.cs new file mode 100644 index 0000000..1200cda --- /dev/null +++ b/Castle.Core/DynamicProxy/Contributors/ClassMembersCollector.cs @@ -0,0 +1,46 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Contributors +{ + using System; + using System.Reflection; + + using Castle.DynamicProxy.Generators; + + internal class ClassMembersCollector : MembersCollector + { + public ClassMembersCollector(Type targetType) + : base(targetType) + { + } + + protected override MetaMethod GetMethodToGenerate(MethodInfo method, IProxyGenerationHook hook, bool isStandalone) + { + if (ProxyUtil.IsAccessibleMethod(method) == false) + { + return null; + } + + var accepted = AcceptMethod(method, true, hook); + if (!accepted && !method.IsAbstract) + { + //we don't need to do anything... + return null; + } + + return new MetaMethod(method, method, isStandalone, accepted, !method.IsAbstract); + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Contributors/ClassProxySerializableContributor.cs b/Castle.Core/DynamicProxy/Contributors/ClassProxySerializableContributor.cs new file mode 100644 index 0000000..44d04a4 --- /dev/null +++ b/Castle.Core/DynamicProxy/Contributors/ClassProxySerializableContributor.cs @@ -0,0 +1,247 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#if FEATURE_SERIALIZATION + +namespace Castle.DynamicProxy.Contributors +{ + using System; + using System.Collections.Generic; + using System.Diagnostics; + using System.Linq; + using System.Reflection; + using System.Runtime.Serialization; + + using Castle.DynamicProxy.Generators; + using Castle.DynamicProxy.Generators.Emitters; + using Castle.DynamicProxy.Generators.Emitters.SimpleAST; + using Castle.DynamicProxy.Internal; + using Castle.DynamicProxy.Tokens; + + internal class ClassProxySerializableContributor : SerializableContributor + { + private bool delegateToBaseGetObjectData; + private ConstructorInfo serializationConstructor; + private readonly IList serializedFields = new List(); + + public ClassProxySerializableContributor(Type targetType, Type[] interfaces, string typeId) + : base(targetType, interfaces, typeId) + { + Debug.Assert(targetType.IsSerializable, "This contributor is intended for serializable types only."); + } + + public override void CollectElementsToProxy(IProxyGenerationHook hook, MetaType model) + { + delegateToBaseGetObjectData = VerifyIfBaseImplementsGetObjectData(targetType, model, out var getObjectData); + + // This contributor is going to add a `GetObjectData` method to the proxy type. + // If a method with the same name and signature exists in the proxied class type, + // and another contributor has decided to proxy it, we need to tell it not to. + // Otherwise, we'll end up with two implementations! + + if (getObjectData == null) + { + // `VerifyIfBaseImplementsGetObjectData` only searches for `GetObjectData` + // in the implementation map for `ISerializable`. In the best case, it was + // already found there. If not, we need to look again, since *any* method + // with the same signature is a problem. + + var getObjectDataMethod = targetType.GetMethod( + "GetObjectData", + BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, + null, + new[] { typeof(SerializationInfo), typeof(StreamingContext) }, + null); + + if (getObjectDataMethod != null) + { + getObjectData = model.FindMethod(getObjectDataMethod); + } + } + + if (getObjectData != null && getObjectData.Proxyable) + { + getObjectData.Ignore = true; + } + } + + public override void Generate(ClassEmitter @class) + { + ImplementGetObjectData(@class); + Constructor(@class); + } + + protected override void AddAddValueInvocation(ArgumentReference serializationInfo, MethodEmitter getObjectData, + FieldReference field) + { + serializedFields.Add(field); + base.AddAddValueInvocation(serializationInfo, getObjectData, field); + } + + protected override void CustomizeGetObjectData(CodeBuilder codebuilder, ArgumentReference serializationInfo, + ArgumentReference streamingContext, ClassEmitter emitter) + { + codebuilder.AddStatement( + new MethodInvocationExpression( + serializationInfo, + SerializationInfoMethods.AddValue_Bool, + new LiteralStringExpression("__delegateToBase"), + new LiteralBoolExpression(delegateToBaseGetObjectData))); + + if (delegateToBaseGetObjectData == false) + { + EmitCustomGetObjectData(codebuilder, serializationInfo); + return; + } + + EmitCallToBaseGetObjectData(codebuilder, serializationInfo, streamingContext); + } + + private void EmitCustomGetObjectData(CodeBuilder codebuilder, ArgumentReference serializationInfo) + { + var members = codebuilder.DeclareLocal(typeof(MemberInfo[])); + var data = codebuilder.DeclareLocal(typeof(object[])); + + var getSerializableMembers = new MethodInvocationExpression( + null, + FormatterServicesMethods.GetSerializableMembers, + new TypeTokenExpression(targetType)); + codebuilder.AddStatement(new AssignStatement(members, getSerializableMembers)); + + // Sort to keep order on both serialize and deserialize side the same, c.f DYNPROXY-ISSUE-127 + var callSort = new MethodInvocationExpression( + null, + TypeUtilMethods.Sort, + members); + codebuilder.AddStatement(new AssignStatement(members, callSort)); + + var getObjectData = new MethodInvocationExpression( + null, + FormatterServicesMethods.GetObjectData, + SelfReference.Self, + members); + codebuilder.AddStatement(new AssignStatement(data, getObjectData)); + + var addValue = new MethodInvocationExpression( + serializationInfo, + SerializationInfoMethods.AddValue_Object, + new LiteralStringExpression("__data"), + data); + codebuilder.AddStatement(addValue); + } + + private void EmitCallToBaseGetObjectData(CodeBuilder codebuilder, ArgumentReference serializationInfo, + ArgumentReference streamingContext) + { + var baseGetObjectData = targetType.GetMethod("GetObjectData", + new[] { typeof(SerializationInfo), typeof(StreamingContext) }); + + codebuilder.AddStatement( + new MethodInvocationExpression( + baseGetObjectData, + serializationInfo, + streamingContext)); + } + + private void Constructor(ClassEmitter emitter) + { + if (!delegateToBaseGetObjectData) + { + return; + } + GenerateSerializationConstructor(emitter); + } + + private void GenerateSerializationConstructor(ClassEmitter emitter) + { + var serializationInfo = new ArgumentReference(typeof(SerializationInfo)); + var streamingContext = new ArgumentReference(typeof(StreamingContext)); + + var ctor = emitter.CreateConstructor(serializationInfo, streamingContext); + + ctor.CodeBuilder.AddStatement( + new ConstructorInvocationStatement(serializationConstructor, + serializationInfo, + streamingContext)); + + foreach (var field in serializedFields) + { + var getValue = new MethodInvocationExpression(serializationInfo, + SerializationInfoMethods.GetValue, + new LiteralStringExpression(field.Reference.Name), + new TypeTokenExpression(field.Reference.FieldType)); + ctor.CodeBuilder.AddStatement(new AssignStatement( + field, + new ConvertExpression(field.Reference.FieldType, + typeof(object), + getValue))); + } + ctor.CodeBuilder.AddStatement(new ReturnStatement()); + } + + private bool VerifyIfBaseImplementsGetObjectData(Type baseType, MetaType model, out MetaMethod getObjectData) + { + getObjectData = null; + + if (!typeof(ISerializable).IsAssignableFrom(baseType)) + { + return false; + } + + if (baseType.IsDelegateType()) + { + //working around bug in CLR which returns true for "does this type implement ISerializable" for delegates + return false; + } + + // If base type implements ISerializable, we have to make sure + // the GetObjectData is marked as virtual + var getObjectDataMethod = baseType.GetInterfaceMap(typeof(ISerializable)).TargetMethods[0]; + if (getObjectDataMethod.IsPrivate) //explicit interface implementation + { + return false; + } + + if (!getObjectDataMethod.IsVirtual || getObjectDataMethod.IsFinal) + { + var message = string.Format("The type {0} implements ISerializable, but GetObjectData is not marked as virtual. " + + "Dynamic Proxy needs types implementing ISerializable to mark GetObjectData as virtual " + + "to ensure correct serialization process.", + baseType.FullName); + throw new ArgumentException(message); + } + + getObjectData = model.FindMethod(getObjectDataMethod); + + serializationConstructor = baseType.GetConstructor( + BindingFlags.Instance | BindingFlags.Public | + BindingFlags.NonPublic, + null, + new[] { typeof(SerializationInfo), typeof(StreamingContext) }, + null); + + if (serializationConstructor == null) + { + var message = string.Format("The type {0} implements ISerializable, " + + "but failed to provide a deserialization constructor", + baseType.FullName); + throw new ArgumentException(message); + } + + return true; + } + } +} + +#endif diff --git a/Castle.Core/DynamicProxy/Contributors/ClassProxyTargetContributor.cs b/Castle.Core/DynamicProxy/Contributors/ClassProxyTargetContributor.cs new file mode 100644 index 0000000..6b72d99 --- /dev/null +++ b/Castle.Core/DynamicProxy/Contributors/ClassProxyTargetContributor.cs @@ -0,0 +1,180 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Contributors +{ + using System; + using System.Collections.Generic; + using System.Diagnostics; + using System.Linq; + using System.Reflection; + using System.Reflection.Emit; + + using Castle.DynamicProxy.Generators; + using Castle.DynamicProxy.Generators.Emitters; + using Castle.DynamicProxy.Generators.Emitters.SimpleAST; + using Castle.DynamicProxy.Internal; + using Castle.DynamicProxy.Tokens; + + internal class ClassProxyTargetContributor : CompositeTypeContributor + { + private readonly Type targetType; + + public ClassProxyTargetContributor(Type targetType, INamingScope namingScope) + : base(namingScope) + { + this.targetType = targetType; + } + + protected override IEnumerable GetCollectors() + { + var targetItem = new ClassMembersCollector(targetType) { Logger = Logger }; + yield return targetItem; + + foreach (var @interface in interfaces) + { + var item = new InterfaceMembersOnClassCollector(@interface, true, + targetType.GetInterfaceMap(@interface)) { Logger = Logger }; + yield return item; + } + } + + protected override MethodGenerator GetMethodGenerator(MetaMethod method, ClassEmitter @class, + OverrideMethodDelegate overrideMethod) + { + if (method.Ignore) + { + return null; + } + + if (!method.Proxyable) + { + return new MinimialisticMethodGenerator(method, + overrideMethod); + } + + if (ExplicitlyImplementedInterfaceMethod(method)) + { + return ExplicitlyImplementedInterfaceMethodGenerator(method, @class, overrideMethod); + } + + var invocation = GetInvocationType(method, @class); + + GetTargetExpressionDelegate getTargetTypeExpression = (c, m) => new TypeTokenExpression(targetType); + + return new MethodWithInvocationGenerator(method, + @class.GetField("__interceptors"), + invocation, + getTargetTypeExpression, + getTargetTypeExpression, + overrideMethod, + null); + } + + private Type BuildInvocationType(MetaMethod method, ClassEmitter @class) + { + var methodInfo = method.Method; + if (!method.HasTarget) + { + return new InheritanceInvocationTypeGenerator(targetType, + method, + null, null) + .Generate(@class, namingScope) + .BuildType(); + } + var callback = CreateCallbackMethod(@class, methodInfo, method.MethodOnTarget); + return new InheritanceInvocationTypeGenerator(callback.DeclaringType, + method, + callback, null) + .Generate(@class, namingScope) + .BuildType(); + } + + private MethodBuilder CreateCallbackMethod(ClassEmitter emitter, MethodInfo methodInfo, MethodInfo methodOnTarget) + { + var targetMethod = methodOnTarget ?? methodInfo; + var callBackMethod = emitter.CreateMethod(namingScope.GetUniqueName(methodInfo.Name + "_callback"), targetMethod); + + if (targetMethod.IsGenericMethod) + { + targetMethod = targetMethod.MakeGenericMethod(callBackMethod.GenericTypeParams.AsTypeArray()); + } + + // invocation on base class + + callBackMethod.CodeBuilder.AddStatement( + new ReturnStatement( + new MethodInvocationExpression(SelfReference.Self, + targetMethod, + callBackMethod.Arguments))); + + return callBackMethod.MethodBuilder; + } + + private bool ExplicitlyImplementedInterfaceMethod(MetaMethod method) + { + return method.MethodOnTarget.IsPrivate; + } + + private MethodGenerator ExplicitlyImplementedInterfaceMethodGenerator(MetaMethod method, ClassEmitter @class, + OverrideMethodDelegate overrideMethod) + { + var @delegate = GetDelegateType(method, @class); + var contributor = GetContributor(@delegate, method); + var invocation = new InheritanceInvocationTypeGenerator(targetType, method, null, contributor) + .Generate(@class, namingScope) + .BuildType(); + return new MethodWithInvocationGenerator(method, + @class.GetField("__interceptors"), + invocation, + (c, m) => new TypeTokenExpression(targetType), + overrideMethod, + contributor); + } + + private IInvocationCreationContributor GetContributor(Type @delegate, MetaMethod method) + { + if (@delegate.IsGenericType == false) + { + return new InvocationWithDelegateContributor(@delegate, targetType, method, namingScope); + } + return new InvocationWithGenericDelegateContributor(@delegate, + method, + new FieldReference(InvocationMethods.ProxyObject)); + } + + private Type GetDelegateType(MetaMethod method, ClassEmitter @class) + { + var scope = @class.ModuleScope; + var key = new CacheKey( + typeof(Delegate), + targetType, + new[] { method.MethodOnTarget.ReturnType } + .Concat(ArgumentsUtil.GetTypes(method.MethodOnTarget.GetParameters())). + ToArray(), + null); + + return scope.TypeCache.GetOrAddWithoutTakingLock(key, _ => + new DelegateTypeGenerator(method, targetType) + .Generate(@class, namingScope) + .BuildType()); + } + + private Type GetInvocationType(MetaMethod method, ClassEmitter @class) + { + // NOTE: No caching since invocation is tied to this specific proxy type via its invocation method + return BuildInvocationType(method, @class); + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Contributors/ClassProxyWithTargetTargetContributor.cs b/Castle.Core/DynamicProxy/Contributors/ClassProxyWithTargetTargetContributor.cs new file mode 100644 index 0000000..3b709b1 --- /dev/null +++ b/Castle.Core/DynamicProxy/Contributors/ClassProxyWithTargetTargetContributor.cs @@ -0,0 +1,180 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Contributors +{ + using System; + using System.Collections.Generic; + using System.Diagnostics; + using System.Linq; + using System.Reflection; + + using Castle.DynamicProxy.Generators; + using Castle.DynamicProxy.Generators.Emitters; + using Castle.DynamicProxy.Generators.Emitters.SimpleAST; + using Castle.DynamicProxy.Tokens; + + internal class ClassProxyWithTargetTargetContributor : CompositeTypeContributor + { + private readonly Type targetType; + + public ClassProxyWithTargetTargetContributor(Type targetType, INamingScope namingScope) + : base(namingScope) + { + this.targetType = targetType; + } + + protected override IEnumerable GetCollectors() + { + var targetItem = new WrappedClassMembersCollector(targetType) { Logger = Logger }; + yield return targetItem; + + foreach (var @interface in interfaces) + { + var item = new InterfaceMembersOnClassCollector(@interface, true, + targetType.GetInterfaceMap(@interface)) { Logger = Logger }; + yield return item; + } + } + + protected override MethodGenerator GetMethodGenerator(MetaMethod method, ClassEmitter @class, + OverrideMethodDelegate overrideMethod) + { + if (method.Ignore) + { + return null; + } + + var methodIsDirectlyAccessible = IsDirectlyAccessible(method); + + if (!method.Proxyable) + { + if (methodIsDirectlyAccessible) + { + return new ForwardingMethodGenerator(method, overrideMethod, (c, m) => c.GetField("__target")); + } + else + { + return IndirectlyCalledMethodGenerator(method, @class, overrideMethod, skipInterceptors: true); + } + } + + if (!methodIsDirectlyAccessible) + { + return IndirectlyCalledMethodGenerator(method, @class, overrideMethod); + } + + var invocation = GetInvocationType(method, @class); + + return new MethodWithInvocationGenerator(method, + @class.GetField("__interceptors"), + invocation, + (c, m) => c.GetField("__target"), + overrideMethod, + null); + } + + private Type BuildInvocationType(MetaMethod method, ClassEmitter @class) + { + if (!method.HasTarget) + { + return new InheritanceInvocationTypeGenerator(targetType, + method, + null, null) + .Generate(@class, namingScope) + .BuildType(); + } + return new CompositionInvocationTypeGenerator(method.Method.DeclaringType, + method, + method.Method, + false, + null) + .Generate(@class, namingScope) + .BuildType(); + } + + private IInvocationCreationContributor GetContributor(Type @delegate, MetaMethod method) + { + if (@delegate.IsGenericType == false) + { + return new InvocationWithDelegateContributor(@delegate, targetType, method, namingScope); + } + return new InvocationWithGenericDelegateContributor(@delegate, + method, + new FieldReference(InvocationMethods.CompositionInvocationTarget)); + } + + private Type GetDelegateType(MetaMethod method, ClassEmitter @class) + { + var scope = @class.ModuleScope; + var key = new CacheKey( + typeof(Delegate), + targetType, + new[] { method.MethodOnTarget.ReturnType } + .Concat(ArgumentsUtil.GetTypes(method.MethodOnTarget.GetParameters())). + ToArray(), + null); + + return scope.TypeCache.GetOrAddWithoutTakingLock(key, _ => + new DelegateTypeGenerator(method, targetType) + .Generate(@class, namingScope) + .BuildType()); + } + + private Type GetInvocationType(MetaMethod method, ClassEmitter @class) + { + var scope = @class.ModuleScope; + var invocationInterfaces = new[] { typeof(IInvocation) }; + + var key = new CacheKey(method.Method, CompositionInvocationTypeGenerator.BaseType, invocationInterfaces, null); + + // no locking required as we're already within a lock + + return scope.TypeCache.GetOrAddWithoutTakingLock(key, _ => BuildInvocationType(method, @class)); + } + + private MethodGenerator IndirectlyCalledMethodGenerator(MetaMethod method, ClassEmitter proxy, + OverrideMethodDelegate overrideMethod, + bool skipInterceptors = false) + { + var @delegate = GetDelegateType(method, proxy); + var contributor = GetContributor(@delegate, method); + var invocation = new CompositionInvocationTypeGenerator(targetType, method, null, false, contributor) + .Generate(proxy, namingScope) + .BuildType(); + + IExpression expression; + if (skipInterceptors) + { + expression = NullExpression.Instance; + } + else + { + expression = proxy.GetField("__interceptors"); + } + + return new MethodWithInvocationGenerator(method, + expression, + invocation, + (c, m) => c.GetField("__target"), + overrideMethod, + contributor); + } + + private bool IsDirectlyAccessible(MetaMethod method) + { + return method.MethodOnTarget.IsPublic; + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Contributors/CompositeTypeContributor.cs b/Castle.Core/DynamicProxy/Contributors/CompositeTypeContributor.cs new file mode 100644 index 0000000..fc34dff --- /dev/null +++ b/Castle.Core/DynamicProxy/Contributors/CompositeTypeContributor.cs @@ -0,0 +1,184 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Contributors +{ + using System; + using System.Collections.Generic; + using System.Diagnostics; + using System.Reflection; + + using Castle.Core.Logging; + using Castle.DynamicProxy.Generators; + using Castle.DynamicProxy.Generators.Emitters; + using Castle.DynamicProxy.Internal; + + internal abstract class CompositeTypeContributor : ITypeContributor + { + protected readonly INamingScope namingScope; + + protected readonly ICollection interfaces = new HashSet(); + + private ILogger logger = NullLogger.Instance; + private readonly List properties = new List(); + private readonly List events = new List(); + private readonly List methods = new List(); + + protected CompositeTypeContributor(INamingScope namingScope) + { + this.namingScope = namingScope; + } + + public ILogger Logger + { + get { return logger; } + set { logger = value; } + } + + public void CollectElementsToProxy(IProxyGenerationHook hook, MetaType model) + { + Debug.Assert(hook != null); + Debug.Assert(model != null); + + var sink = new MembersCollectorSink(model, this); + + foreach (var collector in GetCollectors()) + { + collector.CollectMembersToProxy(hook, sink); + } + } + + protected abstract IEnumerable GetCollectors(); + + public virtual void Generate(ClassEmitter @class) + { + foreach (var method in methods) + { + if (!method.Standalone) + { + continue; + } + + ImplementMethod(method, + @class, + @class.CreateMethod); + } + + foreach (var property in properties) + { + ImplementProperty(@class, property); + } + + foreach (var @event in events) + { + ImplementEvent(@class, @event); + } + } + + public void AddInterfaceToProxy(Type @interface) + { + Debug.Assert(@interface != null, "@interface == null", "Shouldn't be adding empty interfaces..."); + Debug.Assert(@interface.IsInterface || @interface.IsDelegateType(), "@interface.IsInterface || @interface.IsDelegateType()", "Should be adding interfaces or delegate types only..."); + Debug.Assert(!interfaces.Contains(@interface), "!interfaces.ContainsKey(@interface)", + "Shouldn't be adding same interface twice..."); + + interfaces.Add(@interface); + } + + private void ImplementEvent(ClassEmitter emitter, MetaEvent @event) + { + @event.BuildEventEmitter(emitter); + ImplementMethod(@event.Adder, emitter, @event.Emitter.CreateAddMethod); + ImplementMethod(@event.Remover, emitter, @event.Emitter.CreateRemoveMethod); + } + + private void ImplementProperty(ClassEmitter emitter, MetaProperty property) + { + property.BuildPropertyEmitter(emitter); + if (property.CanRead) + { + ImplementMethod(property.Getter, emitter, property.Emitter.CreateGetMethod); + } + + if (property.CanWrite) + { + ImplementMethod(property.Setter, emitter, property.Emitter.CreateSetMethod); + } + } + + protected abstract MethodGenerator GetMethodGenerator(MetaMethod method, ClassEmitter @class, + OverrideMethodDelegate overrideMethod); + + private void ImplementMethod(MetaMethod method, ClassEmitter @class, + OverrideMethodDelegate overrideMethod) + { + { + var generator = GetMethodGenerator(method, @class, overrideMethod); + if (generator == null) + { + return; + } + var proxyMethod = generator.Generate(@class, namingScope); + foreach (var attribute in method.Method.GetNonInheritableAttributes()) + { + proxyMethod.DefineCustomAttribute(attribute.Builder); + } + } + } + + private sealed class MembersCollectorSink : IMembersCollectorSink + { + private readonly MetaType model; + private readonly CompositeTypeContributor contributor; + + public MembersCollectorSink(MetaType model, CompositeTypeContributor contributor) + { + this.model = model; + this.contributor = contributor; + } + + // You may have noticed that most contributors do not query `MetaType` at all, + // but only their own collections. So perhaps you are wondering why collected + // type elements are added to `model` at all, and not just to `contributor`? + // + // TL;DR: This prevents member name collisions in the generated proxy type. + // + // `MetaType` uses `MetaTypeElementCollection`s internally, which switches members + // to explicit implementation whenever a name collision with a previously added + // member occurs. + // + // It would be pointless to do this at the level of the individual contributor, + // because name collisions could still occur across several contributors. This + // is why they all share the same `MetaType` instance. + + public void Add(MetaEvent @event) + { + model.AddEvent(@event); + contributor.events.Add(@event); + } + + public void Add(MetaMethod method) + { + model.AddMethod(method); + contributor.methods.Add(method); + } + + public void Add(MetaProperty property) + { + model.AddProperty(property); + contributor.properties.Add(property); + } + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Contributors/DelegateTypeMembersCollector.cs b/Castle.Core/DynamicProxy/Contributors/DelegateTypeMembersCollector.cs new file mode 100644 index 0000000..d3f7970 --- /dev/null +++ b/Castle.Core/DynamicProxy/Contributors/DelegateTypeMembersCollector.cs @@ -0,0 +1,42 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Contributors +{ + using System; + using System.Reflection; + + using Castle.DynamicProxy.Generators; + using Castle.DynamicProxy.Internal; + + internal sealed class DelegateTypeMembersCollector : MembersCollector + { + public DelegateTypeMembersCollector(Type delegateType) + : base(delegateType) + { + } + + protected override MetaMethod GetMethodToGenerate(MethodInfo method, IProxyGenerationHook hook, bool isStandalone) + { + if (method.Name == "Invoke" && method.DeclaringType.IsDelegateType()) + { + return new MetaMethod(method, method, isStandalone, true, false); + } + else + { + return null; + } + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Contributors/Delegates.cs b/Castle.Core/DynamicProxy/Contributors/Delegates.cs new file mode 100644 index 0000000..60a64d6 --- /dev/null +++ b/Castle.Core/DynamicProxy/Contributors/Delegates.cs @@ -0,0 +1,28 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Contributors +{ + using System.Reflection; + + using Castle.DynamicProxy.Generators.Emitters; + using Castle.DynamicProxy.Generators.Emitters.SimpleAST; + + internal delegate MethodEmitter OverrideMethodDelegate( + string name, MethodAttributes attributes, MethodInfo methodToOverride); + + internal delegate IExpression GetTargetExpressionDelegate(ClassEmitter @class, MethodInfo method); + + internal delegate Reference GetTargetReferenceDelegate(ClassEmitter @class, MethodInfo method); +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Contributors/FieldReferenceComparer.cs b/Castle.Core/DynamicProxy/Contributors/FieldReferenceComparer.cs new file mode 100644 index 0000000..1a658b4 --- /dev/null +++ b/Castle.Core/DynamicProxy/Contributors/FieldReferenceComparer.cs @@ -0,0 +1,37 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Contributors +{ + using System; + using System.Collections.Generic; + + internal class FieldReferenceComparer : IComparer + { + public int Compare(Type x, Type y) + { + if (x == null) + { + throw new ArgumentNullException(nameof(x)); + } + + if (y == null) + { + throw new ArgumentNullException(nameof(y)); + } + + return string.CompareOrdinal(x.FullName, y.FullName); + } + } +} diff --git a/Castle.Core/DynamicProxy/Contributors/IInvocationCreationContributor.cs b/Castle.Core/DynamicProxy/Contributors/IInvocationCreationContributor.cs new file mode 100644 index 0000000..87b94f8 --- /dev/null +++ b/Castle.Core/DynamicProxy/Contributors/IInvocationCreationContributor.cs @@ -0,0 +1,33 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Contributors +{ + using System.Reflection; + + using Castle.DynamicProxy.Generators.Emitters; + using Castle.DynamicProxy.Generators.Emitters.SimpleAST; + + internal interface IInvocationCreationContributor + { + ConstructorEmitter CreateConstructor(ArgumentReference[] baseCtorArguments, AbstractTypeEmitter invocation); + + MethodInfo GetCallbackMethod(); + + MethodInvocationExpression GetCallbackMethodInvocation(AbstractTypeEmitter invocation, IExpression[] args, + Reference targetField, MethodEmitter invokeMethodOnTarget); + + IExpression[] GetConstructorInvocationArguments(IExpression[] arguments, ClassEmitter proxy); + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Contributors/IMembersCollectorSink.cs b/Castle.Core/DynamicProxy/Contributors/IMembersCollectorSink.cs new file mode 100644 index 0000000..0afd234 --- /dev/null +++ b/Castle.Core/DynamicProxy/Contributors/IMembersCollectorSink.cs @@ -0,0 +1,25 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Contributors +{ + using Castle.DynamicProxy.Generators; + + internal interface IMembersCollectorSink + { + void Add(MetaEvent @event); + void Add(MetaMethod method); + void Add(MetaProperty property); + } +} diff --git a/Castle.Core/DynamicProxy/Contributors/ITypeContributor.cs b/Castle.Core/DynamicProxy/Contributors/ITypeContributor.cs new file mode 100644 index 0000000..64ab060 --- /dev/null +++ b/Castle.Core/DynamicProxy/Contributors/ITypeContributor.cs @@ -0,0 +1,29 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Contributors +{ + using Castle.DynamicProxy.Generators; + using Castle.DynamicProxy.Generators.Emitters; + + /// + /// Interface describing elements composing generated type + /// + internal interface ITypeContributor + { + void CollectElementsToProxy(IProxyGenerationHook hook, MetaType model); + + void Generate(ClassEmitter @class); + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Contributors/InterfaceMembersCollector.cs b/Castle.Core/DynamicProxy/Contributors/InterfaceMembersCollector.cs new file mode 100644 index 0000000..bb0fdc8 --- /dev/null +++ b/Castle.Core/DynamicProxy/Contributors/InterfaceMembersCollector.cs @@ -0,0 +1,40 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Contributors +{ + using System; + using System.Reflection; + + using Castle.DynamicProxy.Generators; + + internal class InterfaceMembersCollector : MembersCollector + { + public InterfaceMembersCollector(Type @interface) + : base(@interface) + { + } + + protected override MetaMethod GetMethodToGenerate(MethodInfo method, IProxyGenerationHook hook, bool isStandalone) + { + if (ProxyUtil.IsAccessibleMethod(method) == false) + { + return null; + } + + var proxyable = AcceptMethod(method, false, hook); + return new MetaMethod(method, method, isStandalone, proxyable, false); + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Contributors/InterfaceMembersOnClassCollector.cs b/Castle.Core/DynamicProxy/Contributors/InterfaceMembersOnClassCollector.cs new file mode 100644 index 0000000..3e643cf --- /dev/null +++ b/Castle.Core/DynamicProxy/Contributors/InterfaceMembersOnClassCollector.cs @@ -0,0 +1,68 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Contributors +{ + using System; + using System.Reflection; + + using Castle.DynamicProxy.Generators; + + internal class InterfaceMembersOnClassCollector : MembersCollector + { + private readonly InterfaceMapping map; + private readonly bool onlyProxyVirtual; + + public InterfaceMembersOnClassCollector(Type type, bool onlyProxyVirtual, InterfaceMapping map) : base(type) + { + this.onlyProxyVirtual = onlyProxyVirtual; + this.map = map; + } + + protected override MetaMethod GetMethodToGenerate(MethodInfo method, IProxyGenerationHook hook, bool isStandalone) + { + if (ProxyUtil.IsAccessibleMethod(method) == false) + { + return null; + } + + if (onlyProxyVirtual && IsVirtuallyImplementedInterfaceMethod(method)) + { + return null; + } + + var methodOnTarget = GetMethodOnTarget(method); + + var proxyable = AcceptMethod(method, onlyProxyVirtual, hook); + return new MetaMethod(method, methodOnTarget, isStandalone, proxyable, methodOnTarget.IsPrivate == false); + } + + private MethodInfo GetMethodOnTarget(MethodInfo method) + { + var index = Array.IndexOf(map.InterfaceMethods, method); + if (index == -1) + { + return null; + } + + return map.TargetMethods[index]; + } + + private bool IsVirtuallyImplementedInterfaceMethod(MethodInfo method) + { + var info = GetMethodOnTarget(method); + return info != null && info.IsFinal == false; + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Contributors/InterfaceProxySerializableContributor.cs b/Castle.Core/DynamicProxy/Contributors/InterfaceProxySerializableContributor.cs new file mode 100644 index 0000000..2d30dbc --- /dev/null +++ b/Castle.Core/DynamicProxy/Contributors/InterfaceProxySerializableContributor.cs @@ -0,0 +1,54 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#if FEATURE_SERIALIZATION + +namespace Castle.DynamicProxy.Contributors +{ + using System; + + using Castle.DynamicProxy.Generators.Emitters; + using Castle.DynamicProxy.Generators.Emitters.SimpleAST; + using Castle.DynamicProxy.Tokens; + + internal class InterfaceProxySerializableContributor : SerializableContributor + { + public InterfaceProxySerializableContributor(Type targetType, string proxyGeneratorId, Type[] interfaces) + : base(targetType, interfaces, proxyGeneratorId) + { + } + + protected override void CustomizeGetObjectData(CodeBuilder codebuilder, ArgumentReference serializationInfo, + ArgumentReference streamingContext, ClassEmitter emitter) + { + var targetField = emitter.GetField("__target"); + + codebuilder.AddStatement( + new MethodInvocationExpression( + serializationInfo, + SerializationInfoMethods.AddValue_Object, + new LiteralStringExpression("__targetFieldType"), + new LiteralStringExpression(targetField.Reference.FieldType.AssemblyQualifiedName))); + + codebuilder.AddStatement( + new MethodInvocationExpression( + serializationInfo, + SerializationInfoMethods.AddValue_Object, + new LiteralStringExpression("__theInterface"), + new LiteralStringExpression(targetType.AssemblyQualifiedName))); + } + } +} + +#endif diff --git a/Castle.Core/DynamicProxy/Contributors/InterfaceProxyTargetContributor.cs b/Castle.Core/DynamicProxy/Contributors/InterfaceProxyTargetContributor.cs new file mode 100644 index 0000000..deb0cde --- /dev/null +++ b/Castle.Core/DynamicProxy/Contributors/InterfaceProxyTargetContributor.cs @@ -0,0 +1,101 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Contributors +{ + using System; + using System.Collections.Generic; + using System.Diagnostics; + using System.Reflection; + + using Castle.DynamicProxy.Generators; + using Castle.DynamicProxy.Generators.Emitters; + + internal class InterfaceProxyTargetContributor : CompositeTypeContributor + { + private readonly bool canChangeTarget; + private readonly Type proxyTargetType; + + public InterfaceProxyTargetContributor(Type proxyTargetType, bool canChangeTarget, INamingScope namingScope) + : base(namingScope) + { + this.proxyTargetType = proxyTargetType; + this.canChangeTarget = canChangeTarget; + } + + protected override IEnumerable GetCollectors() + { + foreach (var @interface in interfaces) + { + var item = GetCollectorForInterface(@interface); + item.Logger = Logger; + yield return item; + } + } + + protected virtual MembersCollector GetCollectorForInterface(Type @interface) + { + return new InterfaceMembersOnClassCollector(@interface, false, + proxyTargetType.GetInterfaceMap(@interface)); + } + + protected override MethodGenerator GetMethodGenerator(MetaMethod method, ClassEmitter @class, + OverrideMethodDelegate overrideMethod) + { + if (!method.Proxyable) + { + return new ForwardingMethodGenerator(method, + overrideMethod, + (c, m) => c.GetField("__target")); + } + + var invocation = GetInvocationType(method, @class); + + return new MethodWithInvocationGenerator(method, + @class.GetField("__interceptors"), + invocation, + (c, m) => c.GetField("__target"), + overrideMethod, + null); + } + + private Type GetInvocationType(MetaMethod method, ClassEmitter @class) + { + var scope = @class.ModuleScope; + + Type[] invocationInterfaces; + if (canChangeTarget) + { + invocationInterfaces = new[] { typeof(IInvocation), typeof(IChangeProxyTarget) }; + } + else + { + invocationInterfaces = new[] { typeof(IInvocation) }; + } + + var key = new CacheKey(method.Method, CompositionInvocationTypeGenerator.BaseType, invocationInterfaces, null); + + // no locking required as we're already within a lock + + return scope.TypeCache.GetOrAddWithoutTakingLock(key, _ => + new CompositionInvocationTypeGenerator(method.Method.DeclaringType, + method, + method.Method, + canChangeTarget, + null) + .Generate(@class, namingScope) + .BuildType()); + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Contributors/InterfaceProxyWithOptionalTargetContributor.cs b/Castle.Core/DynamicProxy/Contributors/InterfaceProxyWithOptionalTargetContributor.cs new file mode 100644 index 0000000..858a6fb --- /dev/null +++ b/Castle.Core/DynamicProxy/Contributors/InterfaceProxyWithOptionalTargetContributor.cs @@ -0,0 +1,43 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Contributors +{ + using Castle.DynamicProxy.Generators; + using Castle.DynamicProxy.Generators.Emitters; + + internal class InterfaceProxyWithOptionalTargetContributor : InterfaceProxyWithoutTargetContributor + { + private readonly GetTargetReferenceDelegate getTargetReference; + + public InterfaceProxyWithOptionalTargetContributor(INamingScope namingScope, GetTargetExpressionDelegate getTarget, + GetTargetReferenceDelegate getTargetReference) + : base(namingScope, getTarget) + { + this.getTargetReference = getTargetReference; + canChangeTarget = true; + } + + protected override MethodGenerator GetMethodGenerator(MetaMethod method, ClassEmitter @class, + OverrideMethodDelegate overrideMethod) + { + if (!method.Proxyable) + { + return new OptionallyForwardingMethodGenerator(method, overrideMethod, getTargetReference); + } + + return base.GetMethodGenerator(method, @class, overrideMethod); + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Contributors/InterfaceProxyWithTargetInterfaceTargetContributor.cs b/Castle.Core/DynamicProxy/Contributors/InterfaceProxyWithTargetInterfaceTargetContributor.cs new file mode 100644 index 0000000..b1f4525 --- /dev/null +++ b/Castle.Core/DynamicProxy/Contributors/InterfaceProxyWithTargetInterfaceTargetContributor.cs @@ -0,0 +1,34 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Contributors +{ + using System; + + using Castle.DynamicProxy.Generators; + + internal class InterfaceProxyWithTargetInterfaceTargetContributor : InterfaceProxyTargetContributor + { + public InterfaceProxyWithTargetInterfaceTargetContributor(Type proxyTargetType, bool allowChangeTarget, + INamingScope namingScope) + : base(proxyTargetType, allowChangeTarget, namingScope) + { + } + + protected override MembersCollector GetCollectorForInterface(Type @interface) + { + return new InterfaceMembersCollector(@interface); + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Contributors/InterfaceProxyWithoutTargetContributor.cs b/Castle.Core/DynamicProxy/Contributors/InterfaceProxyWithoutTargetContributor.cs new file mode 100644 index 0000000..3910e42 --- /dev/null +++ b/Castle.Core/DynamicProxy/Contributors/InterfaceProxyWithoutTargetContributor.cs @@ -0,0 +1,97 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Contributors +{ + using System; + using System.Collections.Generic; + using System.Diagnostics; + + using Castle.DynamicProxy.Generators; + using Castle.DynamicProxy.Generators.Emitters; + using Castle.DynamicProxy.Internal; + + internal class InterfaceProxyWithoutTargetContributor : CompositeTypeContributor + { + private readonly GetTargetExpressionDelegate getTargetExpression; + protected bool canChangeTarget = false; + + public InterfaceProxyWithoutTargetContributor(INamingScope namingScope, GetTargetExpressionDelegate getTarget) + : base(namingScope) + { + getTargetExpression = getTarget; + } + + protected override IEnumerable GetCollectors() + { + foreach (var @interface in interfaces) + { + var item = new InterfaceMembersCollector(@interface); + yield return item; + } + } + + protected override MethodGenerator GetMethodGenerator(MetaMethod method, ClassEmitter @class, + OverrideMethodDelegate overrideMethod) + { + if (!method.Proxyable) + { + return new MinimialisticMethodGenerator(method, overrideMethod); + } + + var invocation = GetInvocationType(method, @class); + return new MethodWithInvocationGenerator(method, + @class.GetField("__interceptors"), + invocation, + getTargetExpression, + overrideMethod, + null); + } + + private Type GetInvocationType(MetaMethod method, ClassEmitter emitter) + { + var methodInfo = method.Method; + + if (canChangeTarget == false && methodInfo.IsAbstract) + { + // We do not need to generate a custom invocation type because no custom implementation + // for `InvokeMethodOnTarget` will be needed (proceeding to target isn't possible here): + return typeof(InterfaceMethodWithoutTargetInvocation); + } + + var scope = emitter.ModuleScope; + Type[] invocationInterfaces; + if (canChangeTarget) + { + invocationInterfaces = new[] { typeof(IInvocation), typeof(IChangeProxyTarget) }; + } + else + { + invocationInterfaces = new[] { typeof(IInvocation) }; + } + var key = new CacheKey(methodInfo, CompositionInvocationTypeGenerator.BaseType, invocationInterfaces, null); + + // no locking required as we're already within a lock + + return scope.TypeCache.GetOrAddWithoutTakingLock(key, _ => + new CompositionInvocationTypeGenerator(methodInfo.DeclaringType, + method, + methodInfo, + canChangeTarget, + null) + .Generate(emitter, namingScope) + .BuildType()); + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Contributors/InvocationWithDelegateContributor.cs b/Castle.Core/DynamicProxy/Contributors/InvocationWithDelegateContributor.cs new file mode 100644 index 0000000..48f7d29 --- /dev/null +++ b/Castle.Core/DynamicProxy/Contributors/InvocationWithDelegateContributor.cs @@ -0,0 +1,107 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Contributors +{ + using System; + using System.Diagnostics; + using System.Reflection; + + using Castle.DynamicProxy.Generators; + using Castle.DynamicProxy.Generators.Emitters; + using Castle.DynamicProxy.Generators.Emitters.SimpleAST; + using Castle.DynamicProxy.Tokens; + + internal class InvocationWithDelegateContributor : IInvocationCreationContributor + { + private readonly Type delegateType; + private readonly MetaMethod method; + private readonly INamingScope namingScope; + private readonly Type targetType; + + public InvocationWithDelegateContributor(Type delegateType, Type targetType, MetaMethod method, + INamingScope namingScope) + { + Debug.Assert(delegateType.IsGenericType == false, "delegateType.IsGenericType == false"); + this.delegateType = delegateType; + this.targetType = targetType; + this.method = method; + this.namingScope = namingScope; + } + + public ConstructorEmitter CreateConstructor(ArgumentReference[] baseCtorArguments, AbstractTypeEmitter invocation) + { + var arguments = GetArguments(baseCtorArguments); + var constructor = invocation.CreateConstructor(arguments); + + var delegateField = invocation.CreateField("delegate", delegateType); + constructor.CodeBuilder.AddStatement(new AssignStatement(delegateField, arguments[0])); + return constructor; + } + + public MethodInfo GetCallbackMethod() + { + return delegateType.GetMethod("Invoke"); + } + + public MethodInvocationExpression GetCallbackMethodInvocation(AbstractTypeEmitter invocation, IExpression[] args, + Reference targetField, + MethodEmitter invokeMethodOnTarget) + { + var allArgs = GetAllArgs(args, targetField); + var @delegate = (Reference)invocation.GetField("delegate"); + + return new MethodInvocationExpression(@delegate, GetCallbackMethod(), allArgs); + } + + public IExpression[] GetConstructorInvocationArguments(IExpression[] arguments, ClassEmitter proxy) + { + var allArguments = new IExpression[arguments.Length + 1]; + allArguments[0] = BuildDelegateToken(proxy); + Array.Copy(arguments, 0, allArguments, 1, arguments.Length); + return allArguments; + } + + private FieldReference BuildDelegateToken(ClassEmitter proxy) + { + var callback = proxy.CreateStaticField(namingScope.GetUniqueName("callback_" + method.Method.Name), delegateType); + var createDelegate = new MethodInvocationExpression( + null, + DelegateMethods.CreateDelegate, + new TypeTokenExpression(delegateType), + NullExpression.Instance, + new MethodTokenExpression(method.MethodOnTarget)); + var bindDelegate = new AssignStatement(callback, new ConvertExpression(delegateType, createDelegate)); + + proxy.ClassConstructor.CodeBuilder.AddStatement(bindDelegate); + return callback; + } + + private IExpression[] GetAllArgs(IExpression[] args, Reference targetField) + { + var allArgs = new IExpression[args.Length + 1]; + args.CopyTo(allArgs, 1); + allArgs[0] = new ConvertExpression(targetType, targetField); + return allArgs; + } + + private ArgumentReference[] GetArguments(ArgumentReference[] baseCtorArguments) + { + var arguments = new ArgumentReference[baseCtorArguments.Length + 1]; + arguments[0] = new ArgumentReference(delegateType); + baseCtorArguments.CopyTo(arguments, 1); + return arguments; + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Contributors/InvocationWithGenericDelegateContributor.cs b/Castle.Core/DynamicProxy/Contributors/InvocationWithGenericDelegateContributor.cs new file mode 100644 index 0000000..3dbeaf5 --- /dev/null +++ b/Castle.Core/DynamicProxy/Contributors/InvocationWithGenericDelegateContributor.cs @@ -0,0 +1,88 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Contributors +{ + using System; + using System.Diagnostics; + using System.Linq; + using System.Reflection; + + using Castle.DynamicProxy.Generators; + using Castle.DynamicProxy.Generators.Emitters; + using Castle.DynamicProxy.Generators.Emitters.SimpleAST; + using Castle.DynamicProxy.Internal; + using Castle.DynamicProxy.Tokens; + + internal class InvocationWithGenericDelegateContributor : IInvocationCreationContributor + { + private readonly Type delegateType; + private readonly MetaMethod method; + private readonly Reference targetReference; + + public InvocationWithGenericDelegateContributor(Type delegateType, MetaMethod method, Reference targetReference) + { + Debug.Assert(delegateType.IsGenericType, "delegateType.IsGenericType"); + this.delegateType = delegateType; + this.method = method; + this.targetReference = targetReference; + } + + public ConstructorEmitter CreateConstructor(ArgumentReference[] baseCtorArguments, AbstractTypeEmitter invocation) + { + return invocation.CreateConstructor(baseCtorArguments); + } + + public MethodInfo GetCallbackMethod() + { + return delegateType.GetMethod("Invoke"); + } + + public MethodInvocationExpression GetCallbackMethodInvocation(AbstractTypeEmitter invocation, IExpression[] args, + Reference targetField, + MethodEmitter invokeMethodOnTarget) + { + var @delegate = GetDelegate(invocation, invokeMethodOnTarget); + return new MethodInvocationExpression(@delegate, GetCallbackMethod(), args); + } + + public IExpression[] GetConstructorInvocationArguments(IExpression[] arguments, ClassEmitter proxy) + { + return arguments; + } + + private Reference GetDelegate(AbstractTypeEmitter invocation, MethodEmitter invokeMethodOnTarget) + { + var genericTypeParameters = invocation.GenericTypeParams.AsTypeArray(); + var closedDelegateType = delegateType.MakeGenericType(genericTypeParameters); + var localReference = invokeMethodOnTarget.CodeBuilder.DeclareLocal(closedDelegateType); + var closedMethodOnTarget = method.MethodOnTarget.MakeGenericMethod(genericTypeParameters); + invokeMethodOnTarget.CodeBuilder.AddStatement( + SetDelegate(localReference, targetReference, closedDelegateType, closedMethodOnTarget)); + return localReference; + } + + private AssignStatement SetDelegate(LocalReference localDelegate, Reference localTarget, + Type closedDelegateType, MethodInfo closedMethodOnTarget) + { + var delegateCreateDelegate = new MethodInvocationExpression( + null, + DelegateMethods.CreateDelegate, + new TypeTokenExpression(closedDelegateType), + localTarget, + new MethodTokenExpression(closedMethodOnTarget)); + return new AssignStatement(localDelegate, new ConvertExpression(closedDelegateType, delegateCreateDelegate)); + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Contributors/MembersCollector.cs b/Castle.Core/DynamicProxy/Contributors/MembersCollector.cs new file mode 100644 index 0000000..6ca7a9a --- /dev/null +++ b/Castle.Core/DynamicProxy/Contributors/MembersCollector.cs @@ -0,0 +1,228 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Contributors +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Reflection; + + using Castle.Core.Logging; + using Castle.DynamicProxy.Generators; + using Castle.DynamicProxy.Internal; + + internal abstract class MembersCollector + { + private const BindingFlags Flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance; + private ILogger logger = NullLogger.Instance; + + protected readonly Type type; + + protected MembersCollector(Type type) + { + this.type = type; + } + + public ILogger Logger + { + get { return logger; } + set { logger = value; } + } + + public virtual void CollectMembersToProxy(IProxyGenerationHook hook, IMembersCollectorSink sink) + { + var checkedMethods = new HashSet(); + + CollectProperties(); + CollectEvents(); + // Methods go last, because properties and events have methods too (getters/setters add/remove) + // and we don't want to get duplicates, so we collect property and event methods first + // then we collect methods, and add only these that aren't there yet + CollectMethods(); + + void CollectProperties() + { + var propertiesFound = type.GetProperties(Flags); + foreach (var property in propertiesFound) + { + AddProperty(property); + } + } + + void CollectEvents() + { + var eventsFound = type.GetEvents(Flags); + foreach (var @event in eventsFound) + { + AddEvent(@event); + } + } + + void CollectMethods() + { + var methodsFound = MethodFinder.GetAllInstanceMethods(type, Flags); + foreach (var method in methodsFound) + { + AddMethod(method, true); + } + } + + void AddProperty(PropertyInfo property) + { + MetaMethod getter = null; + MetaMethod setter = null; + + if (property.CanRead) + { + var getMethod = property.GetGetMethod(true); + getter = AddMethod(getMethod, false); + } + + if (property.CanWrite) + { + var setMethod = property.GetSetMethod(true); + setter = AddMethod(setMethod, false); + } + + if (setter == null && getter == null) + { + return; + } + + var nonInheritableAttributes = property.GetNonInheritableAttributes(); + var arguments = property.GetIndexParameters(); + + sink.Add(new MetaProperty(property, + getter, + setter, + nonInheritableAttributes.Select(a => a.Builder), + arguments.Select(a => a.ParameterType).ToArray())); + } + + void AddEvent(EventInfo @event) + { + var addMethod = @event.GetAddMethod(true); + var removeMethod = @event.GetRemoveMethod(true); + MetaMethod adder = null; + MetaMethod remover = null; + + if (addMethod != null) + { + adder = AddMethod(addMethod, false); + } + + if (removeMethod != null) + { + remover = AddMethod(removeMethod, false); + } + + if (adder == null && remover == null) + { + return; + } + + sink.Add(new MetaEvent(@event, adder, remover, EventAttributes.None)); + } + + MetaMethod AddMethod(MethodInfo method, bool isStandalone) + { + if (checkedMethods.Add(method) == false) + { + return null; + } + + var methodToGenerate = GetMethodToGenerate(method, hook, isStandalone); + if (methodToGenerate != null) + { + sink.Add(methodToGenerate); + } + + return methodToGenerate; + } + } + + protected abstract MetaMethod GetMethodToGenerate(MethodInfo method, IProxyGenerationHook hook, bool isStandalone); + + /// + /// Performs some basic screening and invokes the + /// to select methods. + /// + protected bool AcceptMethod(MethodInfo method, bool onlyVirtuals, IProxyGenerationHook hook) + { + return AcceptMethodPreScreen(method, onlyVirtuals, hook) && hook.ShouldInterceptMethod(type, method); + } + + /// + /// Performs some basic screening to filter out non-interceptable methods. + /// + /// + /// The will get invoked for non-interceptable method notification only; + /// it does not get asked whether or not to intercept the . + /// + protected bool AcceptMethodPreScreen(MethodInfo method, bool onlyVirtuals, IProxyGenerationHook hook) + { + if (IsInternalAndNotVisibleToDynamicProxy(method)) + { + return false; + } + + var isOverridable = method.IsVirtual && !method.IsFinal; + if (onlyVirtuals && !isOverridable) + { + if (method.DeclaringType != typeof(MarshalByRefObject) && + method.IsGetType() == false && + method.IsMemberwiseClone() == false) + { + Logger.DebugFormat("Excluded non-overridable method {0} on {1} because it cannot be intercepted.", method.Name, + method.DeclaringType.FullName); + hook.NonProxyableMemberNotification(type, method); + } + return false; + } + + // we can never intercept a sealed (final) method + if (method.IsFinal) + { + Logger.DebugFormat("Excluded sealed method {0} on {1} because it cannot be intercepted.", method.Name, + method.DeclaringType.FullName); + return false; + } + + //can only proxy methods that are public or protected (or internals that have already been checked above) + if ((method.IsPublic || method.IsFamily || method.IsAssembly || method.IsFamilyOrAssembly || method.IsFamilyAndAssembly) == false) + { + return false; + } + + if (method.DeclaringType == typeof(MarshalByRefObject)) + { + return false; + } + + if (method.IsFinalizer()) + { + return false; + } + + return true; + } + + private static bool IsInternalAndNotVisibleToDynamicProxy(MethodInfo method) + { + return ProxyUtil.IsInternal(method) && + ProxyUtil.AreInternalsVisibleToDynamicProxy(method.DeclaringType.Assembly) == false; + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Contributors/MixinContributor.cs b/Castle.Core/DynamicProxy/Contributors/MixinContributor.cs new file mode 100644 index 0000000..e607099 --- /dev/null +++ b/Castle.Core/DynamicProxy/Contributors/MixinContributor.cs @@ -0,0 +1,153 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Contributors +{ + using System; + using System.Collections.Generic; + using System.Diagnostics; + using System.Reflection; + + using Castle.DynamicProxy.Generators; + using Castle.DynamicProxy.Generators.Emitters; + using Castle.DynamicProxy.Generators.Emitters.SimpleAST; + using Castle.DynamicProxy.Internal; + + internal class MixinContributor : CompositeTypeContributor + { + private readonly bool canChangeTarget; + private readonly IList empty = new List(); + private readonly IDictionary fields = new SortedDictionary(new FieldReferenceComparer()); + private readonly GetTargetExpressionDelegate getTargetExpression; + + public MixinContributor(INamingScope namingScope, bool canChangeTarget) + : base(namingScope) + { + this.canChangeTarget = canChangeTarget; + getTargetExpression = BuildGetTargetExpression(); + } + + public IEnumerable Fields + { + get { return fields.Values; } + } + + public void AddEmptyInterface(Type @interface) + { + Debug.Assert(@interface != null, "@interface == null", "Shouldn't be adding empty interfaces..."); + Debug.Assert(@interface.IsInterface, "@interface.IsInterface", "Should be adding interfaces only..."); + Debug.Assert(!interfaces.Contains(@interface), "!interfaces.Contains(@interface)", + "Shouldn't be adding same interface twice..."); + Debug.Assert(!empty.Contains(@interface), "!empty.Contains(@interface)", + "Shouldn't be adding same interface twice..."); + empty.Add(@interface); + } + + public override void Generate(ClassEmitter @class) + { + foreach (var @interface in interfaces) + { + fields[@interface] = BuildTargetField(@class, @interface); + } + + foreach (var emptyInterface in empty) + { + fields[emptyInterface] = BuildTargetField(@class, emptyInterface); + } + + base.Generate(@class); + } + + protected override IEnumerable GetCollectors() + { + foreach (var @interface in interfaces) + { + MembersCollector item; + if (@interface.IsInterface) + { + item = new InterfaceMembersCollector(@interface); + } + else + { + Debug.Assert(@interface.IsDelegateType()); + item = new DelegateTypeMembersCollector(@interface); + } + yield return item; + } + } + + protected override MethodGenerator GetMethodGenerator(MetaMethod method, ClassEmitter @class, + OverrideMethodDelegate overrideMethod) + { + if (!method.Proxyable) + { + return new ForwardingMethodGenerator(method, + overrideMethod, + (c, i) => fields[i.DeclaringType]); + } + + var invocation = GetInvocationType(method, @class); + return new MethodWithInvocationGenerator(method, + @class.GetField("__interceptors"), + invocation, + getTargetExpression, + overrideMethod, + null); + } + + private GetTargetExpressionDelegate BuildGetTargetExpression() + { + if (!canChangeTarget) + { + return (c, m) => fields[m.DeclaringType]; + } + + return (c, m) => new NullCoalescingOperatorExpression( + new AsTypeReference(c.GetField("__target"), m.DeclaringType), + fields[m.DeclaringType]); + } + + private FieldReference BuildTargetField(ClassEmitter @class, Type type) + { + var name = "__mixin_" + type.FullName.Replace(".", "_"); + return @class.CreateField(namingScope.GetUniqueName(name), type); + } + + private Type GetInvocationType(MetaMethod method, ClassEmitter emitter) + { + var scope = emitter.ModuleScope; + Type[] invocationInterfaces; + if (canChangeTarget) + { + invocationInterfaces = new[] { typeof(IInvocation), typeof(IChangeProxyTarget) }; + } + else + { + invocationInterfaces = new[] { typeof(IInvocation) }; + } + var key = new CacheKey(method.Method, CompositionInvocationTypeGenerator.BaseType, invocationInterfaces, null); + + // no locking required as we're already within a lock + + return scope.TypeCache.GetOrAddWithoutTakingLock(key, _ => + new CompositionInvocationTypeGenerator(method.Method.DeclaringType, + method, + method.Method, + canChangeTarget, + null) + .Generate(emitter, namingScope) + .BuildType()); + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Contributors/NonInheritableAttributesContributor.cs b/Castle.Core/DynamicProxy/Contributors/NonInheritableAttributesContributor.cs new file mode 100644 index 0000000..0f30bec --- /dev/null +++ b/Castle.Core/DynamicProxy/Contributors/NonInheritableAttributesContributor.cs @@ -0,0 +1,47 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Contributors +{ + using System; + + using Castle.DynamicProxy.Generators; + using Castle.DynamicProxy.Generators.Emitters; + using Castle.DynamicProxy.Internal; + + /// + /// Reproduces the proxied type's non-inheritable custom attributes on the proxy type. + /// + internal sealed class NonInheritableAttributesContributor : ITypeContributor + { + private readonly Type targetType; + + public NonInheritableAttributesContributor(Type targetType) + { + this.targetType = targetType; + } + + public void Generate(ClassEmitter emitter) + { + foreach (var attribute in targetType.GetNonInheritableAttributes()) + { + emitter.DefineCustomAttribute(attribute.Builder); + } + } + + public void CollectElementsToProxy(IProxyGenerationHook hook, MetaType model) + { + } + } +} diff --git a/Castle.Core/DynamicProxy/Contributors/ProxyTargetAccessorContributor.cs b/Castle.Core/DynamicProxy/Contributors/ProxyTargetAccessorContributor.cs new file mode 100644 index 0000000..32cdec1 --- /dev/null +++ b/Castle.Core/DynamicProxy/Contributors/ProxyTargetAccessorContributor.cs @@ -0,0 +1,74 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Contributors +{ + using System; + + using Castle.DynamicProxy.Generators; + using Castle.DynamicProxy.Generators.Emitters; + using Castle.DynamicProxy.Generators.Emitters.SimpleAST; + + /// + /// Adds an implementation for to the proxy type. + /// + internal sealed class ProxyTargetAccessorContributor : ITypeContributor + { + private readonly Func getTargetReference; + private readonly Type targetType; + + public ProxyTargetAccessorContributor(Func getTargetReference, Type targetType) + { + this.getTargetReference = getTargetReference; + this.targetType = targetType; + } + + public void CollectElementsToProxy(IProxyGenerationHook hook, MetaType model) + { + } + + public void Generate(ClassEmitter emitter) + { + var interceptorsField = emitter.GetField("__interceptors"); + var targetReference = getTargetReference(); + + var dynProxyGetTarget = emitter.CreateMethod(nameof(IProxyTargetAccessor.DynProxyGetTarget), typeof(object)); + + dynProxyGetTarget.CodeBuilder.AddStatement( + new ReturnStatement(new ConvertExpression(typeof(object), targetType, targetReference))); + + var dynProxySetTarget = emitter.CreateMethod(nameof(IProxyTargetAccessor.DynProxySetTarget), typeof(void), typeof(object)); + + // we can only change the target of the interface proxy + if (targetReference is FieldReference targetField) + { + dynProxySetTarget.CodeBuilder.AddStatement( + new AssignStatement(targetField, + new ConvertExpression(targetField.Fieldbuilder.FieldType, dynProxySetTarget.Arguments[0]))); + } + else + { + dynProxySetTarget.CodeBuilder.AddStatement( + new ThrowStatement(typeof(InvalidOperationException), "Cannot change the target of the class proxy.")); + } + + dynProxySetTarget.CodeBuilder.AddStatement(new ReturnStatement()); + + var getInterceptors = emitter.CreateMethod(nameof(IProxyTargetAccessor.GetInterceptors), typeof(IInterceptor[])); + + getInterceptors.CodeBuilder.AddStatement( + new ReturnStatement(interceptorsField)); + } + } +} diff --git a/Castle.Core/DynamicProxy/Contributors/SerializableContributor.cs b/Castle.Core/DynamicProxy/Contributors/SerializableContributor.cs new file mode 100644 index 0000000..c4ff339 --- /dev/null +++ b/Castle.Core/DynamicProxy/Contributors/SerializableContributor.cs @@ -0,0 +1,153 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#if FEATURE_SERIALIZATION + +namespace Castle.DynamicProxy.Contributors +{ + using System; + using System.Runtime.Serialization; + + using Castle.DynamicProxy.Generators; + using Castle.DynamicProxy.Generators.Emitters; + using Castle.DynamicProxy.Generators.Emitters.SimpleAST; + using Castle.DynamicProxy.Serialization; + using Castle.DynamicProxy.Tokens; + + internal abstract class SerializableContributor : ITypeContributor + { + protected readonly Type targetType; + private readonly string proxyTypeId; + private readonly Type[] interfaces; + + protected SerializableContributor(Type targetType, Type[] interfaces, string proxyTypeId) + { + this.targetType = targetType; + this.proxyTypeId = proxyTypeId; + this.interfaces = interfaces ?? Type.EmptyTypes; + } + + public virtual void Generate(ClassEmitter @class) + { + ImplementGetObjectData(@class); + } + + protected void ImplementGetObjectData(ClassEmitter emitter) + { + var getObjectData = emitter.CreateMethod("GetObjectData", typeof(void), + new[] { typeof(SerializationInfo), typeof(StreamingContext) }); + var info = getObjectData.Arguments[0]; + + var typeLocal = getObjectData.CodeBuilder.DeclareLocal(typeof(Type)); + + getObjectData.CodeBuilder.AddStatement( + new AssignStatement( + typeLocal, + new MethodInvocationExpression( + null, + TypeMethods.StaticGetType, + new LiteralStringExpression(typeof(ProxyObjectReference).AssemblyQualifiedName), + new LiteralBoolExpression(true), + new LiteralBoolExpression(false)))); + + getObjectData.CodeBuilder.AddStatement( + new MethodInvocationExpression( + info, + SerializationInfoMethods.SetType, + typeLocal)); + + foreach (var field in emitter.GetAllFields()) + { + if (field.Reference.IsStatic) + { + continue; + } + if (field.Reference.IsNotSerialized) + { + continue; + } + AddAddValueInvocation(info, getObjectData, field); + } + + var interfacesLocal = getObjectData.CodeBuilder.DeclareLocal(typeof(string[])); + + getObjectData.CodeBuilder.AddStatement( + new AssignStatement( + interfacesLocal, + new NewArrayExpression(interfaces.Length, typeof(string)))); + + for (var i = 0; i < interfaces.Length; i++) + { + getObjectData.CodeBuilder.AddStatement( + new AssignArrayStatement( + interfacesLocal, + i, + new LiteralStringExpression(interfaces[i].AssemblyQualifiedName))); + } + + getObjectData.CodeBuilder.AddStatement( + new MethodInvocationExpression( + info, + SerializationInfoMethods.AddValue_Object, + new LiteralStringExpression("__interfaces"), + interfacesLocal)); + + getObjectData.CodeBuilder.AddStatement( + new MethodInvocationExpression( + info, + SerializationInfoMethods.AddValue_Object, + new LiteralStringExpression("__baseType"), + new LiteralStringExpression(emitter.BaseType.AssemblyQualifiedName))); + + getObjectData.CodeBuilder.AddStatement( + new MethodInvocationExpression( + info, + SerializationInfoMethods.AddValue_Object, + new LiteralStringExpression("__proxyGenerationOptions"), + emitter.GetField("proxyGenerationOptions"))); + + getObjectData.CodeBuilder.AddStatement( + new MethodInvocationExpression( + info, + SerializationInfoMethods.AddValue_Object, + new LiteralStringExpression("__proxyTypeId"), + new LiteralStringExpression(proxyTypeId))); + + CustomizeGetObjectData(getObjectData.CodeBuilder, info, getObjectData.Arguments[1], emitter); + + getObjectData.CodeBuilder.AddStatement(new ReturnStatement()); + } + + protected virtual void AddAddValueInvocation(ArgumentReference serializationInfo, MethodEmitter getObjectData, + FieldReference field) + { + getObjectData.CodeBuilder.AddStatement( + new MethodInvocationExpression( + serializationInfo, + SerializationInfoMethods.AddValue_Object, + new LiteralStringExpression(field.Reference.Name), + field)); + return; + } + + protected abstract void CustomizeGetObjectData(CodeBuilder builder, ArgumentReference serializationInfo, + ArgumentReference streamingContext, ClassEmitter emitter); + + public virtual void CollectElementsToProxy(IProxyGenerationHook hook, MetaType model) + { + } + } +} + +#endif diff --git a/Castle.Core/DynamicProxy/Contributors/WrappedClassMembersCollector.cs b/Castle.Core/DynamicProxy/Contributors/WrappedClassMembersCollector.cs new file mode 100644 index 0000000..eca2214 --- /dev/null +++ b/Castle.Core/DynamicProxy/Contributors/WrappedClassMembersCollector.cs @@ -0,0 +1,82 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Contributors +{ + using System; + using System.Reflection; + using System.Runtime.CompilerServices; + + using Castle.DynamicProxy.Generators; + using Castle.DynamicProxy.Generators.Emitters; + using Castle.DynamicProxy.Internal; + + internal class WrappedClassMembersCollector : ClassMembersCollector + { + public WrappedClassMembersCollector(Type type) : base(type) + { + } + + public override void CollectMembersToProxy(IProxyGenerationHook hook, IMembersCollectorSink sink) + { + base.CollectMembersToProxy(hook, sink); + CollectFields(hook); + // TODO: perhaps we should also look for nested classes... + } + + protected override MetaMethod GetMethodToGenerate(MethodInfo method, IProxyGenerationHook hook, bool isStandalone) + { + if (ProxyUtil.IsAccessibleMethod(method) == false) + { + return null; + } + + var interceptable = AcceptMethodPreScreen(method, true, hook); + if (!interceptable) + { + //we don't need to do anything... + return null; + } + + var accepted = hook.ShouldInterceptMethod(type, method); + + return new MetaMethod(method, method, isStandalone, accepted, hasTarget: true); + } + + protected bool IsGeneratedByTheCompiler(FieldInfo field) + { + // for example fields backing autoproperties + return field.IsDefined(typeof(CompilerGeneratedAttribute)); + } + + protected virtual bool IsOKToBeOnProxy(FieldInfo field) + { + return IsGeneratedByTheCompiler(field); + } + + private void CollectFields(IProxyGenerationHook hook) + { + var fields = type.GetAllFields(); + foreach (var field in fields) + { + if (IsOKToBeOnProxy(field)) + { + continue; + } + + hook.NonProxyableMemberNotification(type, field); + } + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/CustomAttributeInfo.cs b/Castle.Core/DynamicProxy/CustomAttributeInfo.cs new file mode 100644 index 0000000..1277b86 --- /dev/null +++ b/Castle.Core/DynamicProxy/CustomAttributeInfo.cs @@ -0,0 +1,347 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Linq.Expressions; + using System.Reflection; + using System.Reflection.Emit; + using System.Runtime.CompilerServices; + + /// + /// Encapsulates the information needed to build an attribute. + /// + /// + /// Arrays passed to this class as constructor arguments or property or field values become owned by this class. + /// They should not be mutated after creation. + /// + public class CustomAttributeInfo : IEquatable + { + // Cached empty arrays to avoid unnecessary allocations + private static readonly PropertyInfo[] EmptyProperties = new PropertyInfo[0]; + private static readonly FieldInfo[] EmptyFields = new FieldInfo[0]; + private static readonly object[] EmptyValues = new object[0]; + + private static readonly IEqualityComparer ValueComparer = new AttributeArgumentValueEqualityComparer(); + + private readonly CustomAttributeBuilder builder; + private readonly ConstructorInfo constructor; + private readonly object[] constructorArgs; + private readonly IDictionary properties; + private readonly IDictionary fields; + + public CustomAttributeInfo( + ConstructorInfo constructor, + object[] constructorArgs, + PropertyInfo[] namedProperties, + object[] propertyValues, + FieldInfo[] namedFields, + object[] fieldValues) + { + // Will take care of validating the arguments + this.builder = new CustomAttributeBuilder(constructor, constructorArgs, namedProperties, propertyValues, namedFields, fieldValues); + + this.constructor = constructor; + this.constructorArgs = constructorArgs.Length == 0 ? EmptyValues : constructorArgs.ToArray(); + this.properties = MakeNameValueDictionary(namedProperties, propertyValues); + this.fields = MakeNameValueDictionary(namedFields, fieldValues); + } + + public CustomAttributeInfo( + ConstructorInfo constructor, + object[] constructorArgs, + PropertyInfo[] namedProperties, + object[] propertyValues) + : this(constructor, constructorArgs, namedProperties, propertyValues, EmptyFields, EmptyValues) + { + } + + public CustomAttributeInfo( + ConstructorInfo constructor, + object[] constructorArgs, + FieldInfo[] namedFields, + object[] fieldValues) + : this(constructor, constructorArgs, EmptyProperties, EmptyValues, namedFields, fieldValues) + { + } + + public CustomAttributeInfo( + ConstructorInfo constructor, + object[] constructorArgs) + : this(constructor, constructorArgs, EmptyProperties, EmptyValues, EmptyFields, EmptyValues) + { + } + + public static CustomAttributeInfo FromExpression(Expression> expression) + { + var namedProperties = new List(); + var propertyValues = new List(); + var namedFields = new List(); + var fieldValues = new List(); + + var body = UnwrapBody(expression.Body); + + var newExpression = body as NewExpression; + if (newExpression == null) + { + var memberInitExpression = body as MemberInitExpression; + if (memberInitExpression == null) + { + throw new ArgumentException("The expression must be either a simple constructor call or an object initializer expression"); + } + + newExpression = memberInitExpression.NewExpression; + + foreach (var binding in memberInitExpression.Bindings) + { + var assignment = binding as MemberAssignment; + if (assignment == null) + { + throw new ArgumentException("Only assignment bindings are supported"); + } + + object value = GetAttributeArgumentValue(assignment.Expression, allowArray: true); + + var property = assignment.Member as PropertyInfo; + if (property != null) + { + namedProperties.Add(property); + propertyValues.Add(value); + } + else + { + var field = assignment.Member as FieldInfo; + if (field != null) + { + namedFields.Add(field); + fieldValues.Add(value); + } + else + { + throw new ArgumentException("Only property and field assignments are supported"); + } + } + } + } + + var ctorArguments = new List(); + foreach (var arg in newExpression.Arguments) + { + object value = GetAttributeArgumentValue(arg, allowArray: true); + ctorArguments.Add(value); + } + + return new CustomAttributeInfo( + newExpression.Constructor, + ctorArguments.ToArray(), + namedProperties.ToArray(), + propertyValues.ToArray(), + namedFields.ToArray(), + fieldValues.ToArray()); + } + + private static Expression UnwrapBody(Expression body) + { + // In VB.NET, a lambda expression like `Function() New MyAttribute()` introduces + // a conversion to the return type. We need to remove this conversion expression + // to get the actual constructor call. + + var convertExpression = body as UnaryExpression; + if (convertExpression != null && convertExpression.NodeType == ExpressionType.Convert) + { + return convertExpression.Operand; + } + return body; + } + + private static object GetAttributeArgumentValue(Expression arg, bool allowArray) + { + switch (arg.NodeType) + { + case ExpressionType.Constant: + return ((ConstantExpression)arg).Value; + case ExpressionType.MemberAccess: + var memberExpr = (MemberExpression) arg; + if (memberExpr.Member is FieldInfo field) + { + if (memberExpr.Expression is ConstantExpression constant && + IsCompilerGenerated(constant.Type) && + constant.Value != null) + { + return field.GetValue(constant.Value); + } + } + break; + case ExpressionType.NewArrayInit: + if (allowArray) + { + var newArrayExpr = (NewArrayExpression) arg; + var array = Array.CreateInstance(newArrayExpr.Type.GetElementType(), newArrayExpr.Expressions.Count); + int index = 0; + foreach (var expr in newArrayExpr.Expressions) + { + object value = GetAttributeArgumentValue(expr, allowArray: false); + array.SetValue(value, index); + index++; + } + return array; + } + break; + } + + throw new ArgumentException("Only constant, local variables, method parameters and single-dimensional array expressions are supported"); + } + + private static bool IsCompilerGenerated(Type type) + { + return type.IsDefined(typeof(CompilerGeneratedAttribute)); + } + + internal CustomAttributeBuilder Builder + { + get { return builder; } + } + + public bool Equals(CustomAttributeInfo other) + { + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + return constructor.Equals(other.constructor) && + constructorArgs.SequenceEqual(other.constructorArgs, ValueComparer) && + AreMembersEquivalent(properties, other.properties) && + AreMembersEquivalent(fields, other.fields); + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != this.GetType()) return false; + return Equals((CustomAttributeInfo)obj); + } + + public override int GetHashCode() + { + unchecked + { + int hashCode = constructor.GetHashCode(); + hashCode = (hashCode*397) ^ CombineHashCodes(constructorArgs); + hashCode = (hashCode*397) ^ CombineMemberHashCodes(properties); + hashCode = (hashCode*397) ^ CombineMemberHashCodes(fields); + return hashCode; + } + } + + private static bool AreMembersEquivalent(IDictionary x, IDictionary y) + { + if (x.Count != y.Count) + return false; + + foreach (var kvp in x) + { + object value; + if (!y.TryGetValue(kvp.Key, out value)) + return false; + if (!ValueComparer.Equals(kvp.Value, value)) + return false; + } + return true; + } + + private static int CombineHashCodes(IEnumerable values) + { + unchecked + { + int hashCode = 173; + foreach (object value in values) + { + hashCode = (hashCode*397) ^ ValueComparer.GetHashCode(value); + } + return hashCode; + } + } + + private static int CombineMemberHashCodes(IDictionary dict) + { + unchecked + { + // Just sum the hashcodes of all key-value pairs, because + // we don't want to take order into account. + + int hashCode = 0; + foreach (var kvp in dict) + { + int keyHashCode = kvp.Key.GetHashCode(); + int valueHashCode = ValueComparer.GetHashCode(kvp.Value); + hashCode += (keyHashCode*397) ^ valueHashCode; + } + return hashCode; + } + } + + private IDictionary MakeNameValueDictionary(T[] members, object[] values) + where T : MemberInfo + { + var dict = new Dictionary(); + for (int i = 0; i < members.Length; i++) + { + dict.Add(members[i].Name, values[i]); + } + return dict; + } + + private class AttributeArgumentValueEqualityComparer : IEqualityComparer + { + bool IEqualityComparer.Equals(object x, object y) + { + if (ReferenceEquals(x, y)) + return true; + if (x == null || y == null) + return false; + if (x.GetType() != y.GetType()) + return false; + + if (x.GetType().IsArray) + { + return AsObjectEnumerable(x).SequenceEqual(AsObjectEnumerable(y)); + } + + return x.Equals(y); + } + + int IEqualityComparer.GetHashCode(object obj) + { + if (obj == null) + return 0; + if (obj.GetType().IsArray) + { + return CombineHashCodes(AsObjectEnumerable(obj)); + } + return obj.GetHashCode(); + } + + private static IEnumerable AsObjectEnumerable(object array) + { + // Covariance doesn't work for value types + if (array.GetType().GetElementType().IsValueType) + return ((Array)array).Cast(); + + return (IEnumerable)array; + } + } + } +} diff --git a/Castle.Core/DynamicProxy/DefaultProxyBuilder.cs b/Castle.Core/DynamicProxy/DefaultProxyBuilder.cs new file mode 100644 index 0000000..c8454aa --- /dev/null +++ b/Castle.Core/DynamicProxy/DefaultProxyBuilder.cs @@ -0,0 +1,164 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Reflection; + + using Castle.Core.Internal; + using Castle.Core.Logging; + using Castle.DynamicProxy.Generators; + + /// + /// Default implementation of interface producing in-memory proxy assemblies. + /// + public class DefaultProxyBuilder : IProxyBuilder + { + private readonly ModuleScope scope; + private ILogger logger = NullLogger.Instance; + + /// + /// Initializes a new instance of the class with new . + /// + public DefaultProxyBuilder() + : this(new ModuleScope()) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The module scope for generated proxy types. + public DefaultProxyBuilder(ModuleScope scope) + { + this.scope = scope; + } + + public ILogger Logger + { + get { return logger; } + set { logger = value; } + } + + public ModuleScope ModuleScope + { + get { return scope; } + } + + public Type CreateClassProxyType(Type classToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options) + { + AssertValidType(classToProxy, nameof(classToProxy)); + AssertValidTypes(additionalInterfacesToProxy, nameof(additionalInterfacesToProxy)); + AssertValidMixins(options, nameof(options)); + + var generator = new ClassProxyGenerator(scope, classToProxy, additionalInterfacesToProxy, options) { Logger = logger }; + return generator.GetProxyType(); + } + + public Type CreateClassProxyTypeWithTarget(Type classToProxy, Type[] additionalInterfacesToProxy, + ProxyGenerationOptions options) + { + AssertValidType(classToProxy, nameof(classToProxy)); + AssertValidTypes(additionalInterfacesToProxy, nameof(additionalInterfacesToProxy)); + AssertValidMixins(options, nameof(options)); + + var generator = new ClassProxyWithTargetGenerator(scope, classToProxy, additionalInterfacesToProxy, options) + { Logger = logger }; + return generator.GetProxyType(); + } + + public Type CreateInterfaceProxyTypeWithTarget(Type interfaceToProxy, Type[] additionalInterfacesToProxy, + Type targetType, + ProxyGenerationOptions options) + { + AssertValidType(interfaceToProxy, nameof(interfaceToProxy)); + AssertValidTypes(additionalInterfacesToProxy, nameof(additionalInterfacesToProxy)); + AssertValidMixins(options, nameof(options)); + + var generator = new InterfaceProxyWithTargetGenerator(scope, interfaceToProxy, additionalInterfacesToProxy, targetType, options) { Logger = logger }; + return generator.GetProxyType(); + } + + public Type CreateInterfaceProxyTypeWithTargetInterface(Type interfaceToProxy, Type[] additionalInterfacesToProxy, + ProxyGenerationOptions options) + { + AssertValidType(interfaceToProxy, nameof(interfaceToProxy)); + AssertValidTypes(additionalInterfacesToProxy, nameof(additionalInterfacesToProxy)); + AssertValidMixins(options, nameof(options)); + + var generator = new InterfaceProxyWithTargetInterfaceGenerator(scope, interfaceToProxy, additionalInterfacesToProxy, interfaceToProxy, options) { Logger = logger }; + return generator.GetProxyType(); + } + + public Type CreateInterfaceProxyTypeWithoutTarget(Type interfaceToProxy, Type[] additionalInterfacesToProxy, + ProxyGenerationOptions options) + { + AssertValidType(interfaceToProxy, nameof(interfaceToProxy)); + AssertValidTypes(additionalInterfacesToProxy, nameof(additionalInterfacesToProxy)); + AssertValidMixins(options, nameof(options)); + + var generator = new InterfaceProxyWithoutTargetGenerator(scope, interfaceToProxy, additionalInterfacesToProxy, typeof(object), options) { Logger = logger }; + return generator.GetProxyType(); + } + + private void AssertValidMixins(ProxyGenerationOptions options, string paramName) + { + try + { + options.Initialize(); + } + catch (InvalidOperationException ex) + { + throw new ArgumentException(ex.Message, paramName, ex.InnerException); // convert to more suitable exception type + } + } + + private void AssertValidType(Type target, string paramName) + { + AssertValidTypeForTarget(target, target, paramName); + } + + private void AssertValidTypeForTarget(Type type, Type target, string paramName) + { + if (type.IsGenericTypeDefinition) + { + throw new ArgumentException( + $"Can not create proxy for type {target.GetBestName()} because type {type.GetBestName()} is an open generic type.", + paramName); + } + if (ProxyUtil.IsAccessibleType(type) == false) + { + throw new ArgumentException(ExceptionMessageBuilder.CreateMessageForInaccessibleType(type, target), paramName); + } + foreach (var typeArgument in type.GetGenericArguments()) + { + AssertValidTypeForTarget(typeArgument, target, paramName); + } + } + + private void AssertValidTypes(IEnumerable targetTypes, string paramName) + { + if (targetTypes != null) + { + foreach (var t in targetTypes) + { + AssertValidType(t, paramName); + } + } + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/DynProxy.snk b/Castle.Core/DynamicProxy/DynProxy.snk new file mode 100644 index 0000000000000000000000000000000000000000..7fb7fb9c29f935e4f8b665fce0e6b5a5d0dc7abe GIT binary patch literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50098SN6N!`y_v|{B3|*${tK)e-1+wxBo$ELr?HV4TXtu=Ph`Bf z;t~^p{T-b~tu2z$(N+ZsIV8;L_e@A(@AfLcX}KvL(4#=%6TT7Vr_&KWl1NPV1YF1Y zXIl}-&;bA}S z`vR*!S=B0zjS~GWpEY5W8G1XDFWWa~fTN052p8x4d)I|wPWisqz;q)ieM#HB>$T`t zJcdo$Is0;~;HrG?CMPWPsuDx3W~#~A2i#oT02|?OL1w*?kA%H#>q9O0a`yr!R+&!L z+T&VK@cnn3+y`X6!r!mbwc$hcNVCL|gz|(^u4`U%#8yx}OXy)@Lfg9?eCP!r6&~w| zJrCB706)1jDcRzGbu-KpY!S{%2x)2;2O*epnF@Z^7MQFukDVNmfY~qwl=fcTMV#b& zJn0;i`Yh-rpk!e@JLr4zbO1vFZt4K?&)7Z0lve3JLn}JT%>SXy5MpaqWToSW-Sy2U zZ%l_1hL0$Lg4|E|1h{Ik3NOs^nuCd?4)&@!`XGxIzq!uXO+#QuV15H8S^5LLhR5nF zG8g*&$x^Q}fk3~#n?}_ + /// Provides instructions that a user could follow to make a type or method in + /// visible to DynamicProxy. + /// The assembly containing the type or method. + /// Instructions that a user could follow to make a type or method visible to DynamicProxy. + internal static string CreateInstructionsToMakeVisible(Assembly targetAssembly) + { + string strongNamedOrNotIndicator = " not"; // assume not strong-named + string assemblyToBeVisibleTo = "\"DynamicProxyGenAssembly2\""; // appropriate for non-strong-named + + if (targetAssembly.IsAssemblySigned()) + { + strongNamedOrNotIndicator = ""; + assemblyToBeVisibleTo = ReferencesCastleCore(targetAssembly) + ? "InternalsVisible.ToDynamicProxyGenAssembly2" + : '"' + InternalsVisible.ToDynamicProxyGenAssembly2 + '"'; + } + + var instructionsFormat = + "Make it public, or internal and mark your assembly with " + + "[assembly: InternalsVisibleTo({0})] attribute, because assembly {1} " + + "is{2} strong-named."; + + var instructions = string.Format(instructionsFormat, + assemblyToBeVisibleTo, + targetAssembly.GetName().Name, + strongNamedOrNotIndicator); + return instructions; + + bool ReferencesCastleCore(Assembly ia) + { + return ia.GetReferencedAssemblies() + .Any(r => r.FullName == Assembly.GetExecutingAssembly().FullName); + } + } + + /// + /// Creates a message to inform clients that a proxy couldn't be created due to reliance on an + /// inaccessible type (perhaps itself). + /// + /// the inaccessible type that prevents proxy creation + /// the type that couldn't be proxied + public static string CreateMessageForInaccessibleType(Type inaccessibleType, Type typeToProxy) + { + var targetAssembly = typeToProxy.Assembly; + + string inaccessibleTypeDescription = inaccessibleType == typeToProxy + ? "it" + : "type " + inaccessibleType.GetBestName(); + + var messageFormat = "Can not create proxy for type {0} because {1} is not accessible. "; + + var message = string.Format(messageFormat, + typeToProxy.GetBestName(), + inaccessibleTypeDescription); + + var instructions = CreateInstructionsToMakeVisible(targetAssembly); + + return message + instructions; + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/AttributesToAvoidReplicating.cs b/Castle.Core/DynamicProxy/Generators/AttributesToAvoidReplicating.cs new file mode 100644 index 0000000..e045a50 --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/AttributesToAvoidReplicating.cs @@ -0,0 +1,63 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Reflection; + + public static class AttributesToAvoidReplicating + { + private static readonly object lockObject = new object(); + + private static IList attributes; + + static AttributesToAvoidReplicating() + { + attributes = new List() + { + typeof(System.Runtime.InteropServices.ComImportAttribute), + typeof(System.Runtime.InteropServices.MarshalAsAttribute), + typeof(System.Runtime.InteropServices.TypeIdentifierAttribute), + typeof(System.Security.Permissions.SecurityAttribute), + }; + } + + public static void Add(Type attribute) + { + // note: this class is made thread-safe by replacing the backing list rather than adding to it + lock (lockObject) + { + attributes = new List(attributes) { attribute }; + } + } + + public static void Add() + { + Add(typeof(T)); + } + + public static bool Contains(Type attribute) + { + return attributes.Contains(attribute); + } + + internal static bool ShouldAvoid(Type attribute) + { + return attributes.Any(attr => attr.IsAssignableFrom(attribute)); + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/BaseClassProxyGenerator.cs b/Castle.Core/DynamicProxy/Generators/BaseClassProxyGenerator.cs new file mode 100644 index 0000000..02f6012 --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/BaseClassProxyGenerator.cs @@ -0,0 +1,219 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Reflection; + + using Castle.DynamicProxy.Contributors; + using Castle.DynamicProxy.Generators.Emitters.SimpleAST; + using Castle.DynamicProxy.Internal; + + internal abstract class BaseClassProxyGenerator : BaseProxyGenerator + { + protected BaseClassProxyGenerator(ModuleScope scope, Type targetType, Type[] interfaces, ProxyGenerationOptions options) + : base(scope, targetType, interfaces, options) + { + EnsureDoesNotImplementIProxyTargetAccessor(targetType, nameof(targetType)); + } + + protected abstract FieldReference TargetField { get; } + +#if FEATURE_SERIALIZATION + protected abstract SerializableContributor GetSerializableContributor(); +#endif + + protected abstract CompositeTypeContributor GetProxyTargetContributor(INamingScope namingScope); + + protected abstract ProxyTargetAccessorContributor GetProxyTargetAccessorContributor(); + + protected sealed override Type GenerateType(string name, INamingScope namingScope) + { + IEnumerable contributors; + var allInterfaces = GetTypeImplementerMapping(out contributors, namingScope); + + var model = new MetaType(); + // Collect methods + foreach (var contributor in contributors) + { + contributor.CollectElementsToProxy(ProxyGenerationOptions.Hook, model); + } + ProxyGenerationOptions.Hook.MethodsInspected(); + + var emitter = BuildClassEmitter(name, targetType, allInterfaces); + + CreateFields(emitter); + CreateTypeAttributes(emitter); + + // Constructor + var cctor = GenerateStaticConstructor(emitter); + + var constructorArguments = new List(); + + if (TargetField is { } targetField) + { + constructorArguments.Add(targetField); + } + + foreach (var contributor in contributors) + { + contributor.Generate(emitter); + + // TODO: redo it + if (contributor is MixinContributor mixinContributor) + { + constructorArguments.AddRange(mixinContributor.Fields); + } + } + + // constructor arguments + var interceptorsField = emitter.GetField("__interceptors"); + constructorArguments.Add(interceptorsField); + var selector = emitter.GetField("__selector"); + if (selector != null) + { + constructorArguments.Add(selector); + } + + GenerateConstructors(emitter, targetType, constructorArguments.ToArray()); + GenerateParameterlessConstructor(emitter, targetType, interceptorsField); + + // Complete type initializer code body + CompleteInitCacheMethod(cctor.CodeBuilder); + + // non-inheritable attributes from proxied type + var nonInheritableAttributesContributor = new NonInheritableAttributesContributor(targetType); + nonInheritableAttributesContributor.Generate(emitter); + + // Crosses fingers and build type + + var proxyType = emitter.BuildType(); + InitializeStaticFields(proxyType); + return proxyType; + } + + private IEnumerable GetTypeImplementerMapping(out IEnumerable contributors, INamingScope namingScope) + { + var contributorsList = new List(capacity: 5); + var targetInterfaces = targetType.GetAllInterfaces(); + var typeImplementerMapping = new Dictionary(); + + // Order of interface precedence: + + // 1. first target + // target is not an interface so we do nothing + var targetContributor = GetProxyTargetContributor(namingScope); + contributorsList.Add(targetContributor); + + // 2. then mixins + if (ProxyGenerationOptions.HasMixins) + { + var mixinContributor = new MixinContributor(namingScope, false) { Logger = Logger }; + contributorsList.Add(mixinContributor); + + foreach (var mixinInterface in ProxyGenerationOptions.MixinData.MixinInterfaces) + { + if (targetInterfaces.Contains(mixinInterface)) + { + // OK, so the target implements this interface. We now do one of two things: + if (interfaces.Contains(mixinInterface) && + typeImplementerMapping.ContainsKey(mixinInterface) == false) + { + AddMappingNoCheck(mixinInterface, targetContributor, typeImplementerMapping); + targetContributor.AddInterfaceToProxy(mixinInterface); + } + // we do not intercept the interface + mixinContributor.AddEmptyInterface(mixinInterface); + } + else + { + if (!typeImplementerMapping.ContainsKey(mixinInterface)) + { + mixinContributor.AddInterfaceToProxy(mixinInterface); + AddMappingNoCheck(mixinInterface, mixinContributor, typeImplementerMapping); + } + } + } + } + + // 3. then additional interfaces + if (interfaces.Length > 0) + { + var additionalInterfacesContributor = new InterfaceProxyWithoutTargetContributor(namingScope, (c, m) => NullExpression.Instance) { Logger = Logger }; + contributorsList.Add(additionalInterfacesContributor); + + foreach (var @interface in interfaces) + { + if (targetInterfaces.Contains(@interface)) + { + if (typeImplementerMapping.ContainsKey(@interface)) + { + continue; + } + + // we intercept the interface, and forward calls to the target type + AddMappingNoCheck(@interface, targetContributor, typeImplementerMapping); + targetContributor.AddInterfaceToProxy(@interface); + } + else if (ProxyGenerationOptions.MixinData.ContainsMixin(@interface) == false) + { + additionalInterfacesContributor.AddInterfaceToProxy(@interface); + AddMapping(@interface, additionalInterfacesContributor, typeImplementerMapping); + } + } + } + + // 4. plus special interfaces + +#if FEATURE_SERIALIZATION + if (targetType.IsSerializable) + { + var serializableContributor = GetSerializableContributor(); + contributorsList.Add(serializableContributor); + AddMappingForISerializable(typeImplementerMapping, serializableContributor); + } +#endif + + var proxyTargetAccessorContributor = GetProxyTargetAccessorContributor(); + contributorsList.Add(proxyTargetAccessorContributor); + try + { + AddMappingNoCheck(typeof(IProxyTargetAccessor), proxyTargetAccessorContributor, typeImplementerMapping); + } + catch (ArgumentException) + { + HandleExplicitlyPassedProxyTargetAccessor(targetInterfaces); + } + + contributors = contributorsList; + return typeImplementerMapping.Keys; + } + + private void EnsureDoesNotImplementIProxyTargetAccessor(Type type, string name) + { + if (!typeof(IProxyTargetAccessor).IsAssignableFrom(type)) + { + return; + } + var message = + string.Format( + "Target type for the proxy implements {0} which is a DynamicProxy infrastructure interface and you should never implement it yourself. Are you trying to proxy an existing proxy?", + typeof(IProxyTargetAccessor)); + throw new ArgumentException(message, name); + } + } +} diff --git a/Castle.Core/DynamicProxy/Generators/BaseInterfaceProxyGenerator.cs b/Castle.Core/DynamicProxy/Generators/BaseInterfaceProxyGenerator.cs new file mode 100644 index 0000000..84e6b11 --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/BaseInterfaceProxyGenerator.cs @@ -0,0 +1,296 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Reflection; +#if FEATURE_SERIALIZATION + using System.Xml.Serialization; +#endif + + using Castle.DynamicProxy.Contributors; + using Castle.DynamicProxy.Generators.Emitters; + using Castle.DynamicProxy.Generators.Emitters.SimpleAST; + using Castle.DynamicProxy.Internal; + + internal abstract class BaseInterfaceProxyGenerator : BaseProxyGenerator + { + protected readonly Type proxyTargetType; + + protected FieldReference targetField; + + protected BaseInterfaceProxyGenerator(ModuleScope scope, Type targetType, Type[] interfaces, + Type proxyTargetType, ProxyGenerationOptions options) + : base(scope, targetType, interfaces, options) + { + CheckNotGenericTypeDefinition(proxyTargetType, nameof(proxyTargetType)); + EnsureValidBaseType(ProxyGenerationOptions.BaseTypeForInterfaceProxy); + + this.proxyTargetType = proxyTargetType; + } + + protected abstract bool AllowChangeTarget { get; } + + protected abstract string GeneratorType { get; } + + protected abstract CompositeTypeContributor GetProxyTargetContributor(Type proxyTargetType, INamingScope namingScope); + + protected abstract ProxyTargetAccessorContributor GetProxyTargetAccessorContributor(); + + protected abstract void AddMappingForAdditionalInterfaces(CompositeTypeContributor contributor, Type[] proxiedInterfaces, + IDictionary typeImplementerMapping, + ICollection targetInterfaces); + + protected virtual ITypeContributor AddMappingForTargetType(IDictionary typeImplementerMapping, + Type proxyTargetType, ICollection targetInterfaces, + INamingScope namingScope) + { + var contributor = GetProxyTargetContributor(proxyTargetType, namingScope); + var proxiedInterfaces = targetType.GetAllInterfaces(); + foreach (var @interface in proxiedInterfaces) + { + contributor.AddInterfaceToProxy(@interface); + AddMappingNoCheck(@interface, contributor, typeImplementerMapping); + } + + AddMappingForAdditionalInterfaces(contributor, proxiedInterfaces, typeImplementerMapping, targetInterfaces); + return contributor; + } + +#if FEATURE_SERIALIZATION + protected override void CreateTypeAttributes(ClassEmitter emitter) + { + base.CreateTypeAttributes(emitter); + emitter.DefineCustomAttribute(); + } +#endif + + protected override CacheKey GetCacheKey() + { + return new CacheKey(proxyTargetType, targetType, interfaces, ProxyGenerationOptions); + } + + protected override Type GenerateType(string typeName, INamingScope namingScope) + { + IEnumerable contributors; + var allInterfaces = GetTypeImplementerMapping(proxyTargetType, out contributors, namingScope); + + var model = new MetaType(); + // Collect methods + foreach (var contributor in contributors) + { + contributor.CollectElementsToProxy(ProxyGenerationOptions.Hook, model); + } + + ProxyGenerationOptions.Hook.MethodsInspected(); + + ClassEmitter emitter; + FieldReference interceptorsField; + var baseType = Init(typeName, out emitter, proxyTargetType, out interceptorsField, allInterfaces); + + // Constructor + + var cctor = GenerateStaticConstructor(emitter); + var ctorArguments = new List(); + + foreach (var contributor in contributors) + { + contributor.Generate(emitter); + + // TODO: redo it + if (contributor is MixinContributor) + { + ctorArguments.AddRange((contributor as MixinContributor).Fields); + } + } + + ctorArguments.Add(interceptorsField); + ctorArguments.Add(targetField); + var selector = emitter.GetField("__selector"); + if (selector != null) + { + ctorArguments.Add(selector); + } + + GenerateConstructors(emitter, baseType, ctorArguments.ToArray()); + + // Complete type initializer code body + CompleteInitCacheMethod(cctor.CodeBuilder); + + // non-inheritable attributes from proxied type + var nonInheritableAttributesContributor = new NonInheritableAttributesContributor(targetType); + nonInheritableAttributesContributor.Generate(emitter); + + // Crosses fingers and build type + var generatedType = emitter.BuildType(); + + InitializeStaticFields(generatedType); + return generatedType; + } + + protected virtual InterfaceProxyWithoutTargetContributor GetContributorForAdditionalInterfaces( + INamingScope namingScope) + { + return new InterfaceProxyWithoutTargetContributor(namingScope, (c, m) => NullExpression.Instance) { Logger = Logger }; + } + + protected virtual IEnumerable GetTypeImplementerMapping(Type proxyTargetType, + out IEnumerable contributors, + INamingScope namingScope) + { + var contributorsList = new List(capacity: 5); + var targetInterfaces = proxyTargetType.GetAllInterfaces(); + var typeImplementerMapping = new Dictionary(); + + // Order of interface precedence: + // 1. first target + var targetContributor = AddMappingForTargetType(typeImplementerMapping, proxyTargetType, targetInterfaces, namingScope); + contributorsList.Add(targetContributor); + + // 2. then mixins + if (ProxyGenerationOptions.HasMixins) + { + var mixinContributor = new MixinContributor(namingScope, AllowChangeTarget) { Logger = Logger }; + contributorsList.Add(mixinContributor); + + foreach (var mixinInterface in ProxyGenerationOptions.MixinData.MixinInterfaces) + { + if (targetInterfaces.Contains(mixinInterface)) + { + // OK, so the target implements this interface. We now do one of two things: + if (interfaces.Contains(mixinInterface)) + { + // we intercept the interface, and forward calls to the target type + AddMapping(mixinInterface, targetContributor, typeImplementerMapping); + } + // we do not intercept the interface + mixinContributor.AddEmptyInterface(mixinInterface); + } + else + { + if (!typeImplementerMapping.ContainsKey(mixinInterface)) + { + mixinContributor.AddInterfaceToProxy(mixinInterface); + typeImplementerMapping.Add(mixinInterface, mixinContributor); + } + } + } + } + + // 3. then additional interfaces + if (interfaces.Length > 0) + { + var additionalInterfacesContributor = GetContributorForAdditionalInterfaces(namingScope); + contributorsList.Add(additionalInterfacesContributor); + + foreach (var @interface in interfaces) + { + if (typeImplementerMapping.ContainsKey(@interface)) + { + continue; + } + if (ProxyGenerationOptions.MixinData.ContainsMixin(@interface)) + { + continue; + } + + additionalInterfacesContributor.AddInterfaceToProxy(@interface); + AddMappingNoCheck(@interface, additionalInterfacesContributor, typeImplementerMapping); + } + } + + // 4. plus special interfaces + +#if FEATURE_SERIALIZATION + var serializableContributor = new InterfaceProxySerializableContributor(targetType, GeneratorType, interfaces); + contributorsList.Add(serializableContributor); + AddMappingForISerializable(typeImplementerMapping, serializableContributor); +#endif + + var proxyTargetAccessorContributor = GetProxyTargetAccessorContributor(); + contributorsList.Add(proxyTargetAccessorContributor); + try + { + AddMappingNoCheck(typeof(IProxyTargetAccessor), proxyTargetAccessorContributor, typeImplementerMapping); + } + catch (ArgumentException) + { + HandleExplicitlyPassedProxyTargetAccessor(targetInterfaces); + } + + contributors = contributorsList; + return typeImplementerMapping.Keys; + } + + protected virtual Type Init(string typeName, out ClassEmitter emitter, Type proxyTargetType, + out FieldReference interceptorsField, IEnumerable allInterfaces) + { + var baseType = ProxyGenerationOptions.BaseTypeForInterfaceProxy; + + emitter = BuildClassEmitter(typeName, baseType, allInterfaces); + + CreateFields(emitter, proxyTargetType); + CreateTypeAttributes(emitter); + + interceptorsField = emitter.GetField("__interceptors"); + return baseType; + } + + private void CreateFields(ClassEmitter emitter, Type proxyTargetType) + { + base.CreateFields(emitter); + targetField = emitter.CreateField("__target", proxyTargetType); +#if FEATURE_SERIALIZATION + emitter.DefineCustomAttributeFor(targetField); +#endif + } + + private void EnsureValidBaseType(Type type) + { + if (type == null) + { + throw new ArgumentException( + "Base type for proxy is null reference. Please set it to System.Object or some other valid type."); + } + + if (!type.IsClass) + { + ThrowInvalidBaseType(type, "it is not a class type"); + } + + if (type.IsSealed) + { + ThrowInvalidBaseType(type, "it is sealed"); + } + + var constructor = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, + null, Type.EmptyTypes, null); + + if (constructor == null || constructor.IsPrivate) + { + ThrowInvalidBaseType(type, "it does not have accessible parameterless constructor"); + } + } + + private void ThrowInvalidBaseType(Type type, string doesNotHaveAccessibleParameterlessConstructor) + { + var format = + "Type {0} is not valid base type for interface proxy, because {1}. Only a non-sealed class with non-private default constructor can be used as base type for interface proxy. Please use some other valid type."; + throw new ArgumentException(string.Format(format, type, doesNotHaveAccessibleParameterlessConstructor)); + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/BaseProxyGenerator.cs b/Castle.Core/DynamicProxy/Generators/BaseProxyGenerator.cs new file mode 100644 index 0000000..2d79040 --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/BaseProxyGenerator.cs @@ -0,0 +1,409 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators +{ + using System; + using System.Collections.Generic; + using System.Diagnostics; + using System.Linq; + using System.Reflection; +#if FEATURE_SERIALIZATION + using System.Runtime.Serialization; + using System.Xml.Serialization; +#endif + + using Castle.Core.Logging; + using Castle.DynamicProxy.Contributors; + using Castle.DynamicProxy.Generators.Emitters; + using Castle.DynamicProxy.Generators.Emitters.SimpleAST; + using Castle.DynamicProxy.Internal; + + /// + /// Base class that exposes the common functionalities + /// to proxy generation. + /// + internal abstract class BaseProxyGenerator + { + protected readonly Type targetType; + protected readonly Type[] interfaces; + private readonly ModuleScope scope; + private ILogger logger = NullLogger.Instance; + private ProxyGenerationOptions proxyGenerationOptions; + + protected BaseProxyGenerator(ModuleScope scope, Type targetType, Type[] interfaces, ProxyGenerationOptions proxyGenerationOptions) + { + CheckNotGenericTypeDefinition(targetType, nameof(targetType)); + CheckNotGenericTypeDefinitions(interfaces, nameof(interfaces)); + + this.scope = scope; + this.targetType = targetType; + this.interfaces = TypeUtil.GetAllInterfaces(interfaces); + this.proxyGenerationOptions = proxyGenerationOptions; + this.proxyGenerationOptions.Initialize(); + } + + public ILogger Logger + { + get { return logger; } + set { logger = value; } + } + + protected ProxyGenerationOptions ProxyGenerationOptions + { + get { return proxyGenerationOptions; } + } + + protected ModuleScope Scope + { + get { return scope; } + } + + public Type GetProxyType() + { + bool notFoundInTypeCache = false; + + var proxyType = Scope.TypeCache.GetOrAdd(GetCacheKey(), cacheKey => + { + notFoundInTypeCache = true; + Logger.DebugFormat("No cached proxy type was found for target type {0}.", targetType.FullName); + + EnsureOptionsOverrideEqualsAndGetHashCode(); + + var name = Scope.NamingScope.GetUniqueName("Castle.Proxies." + targetType.Name + "Proxy"); + return GenerateType(name, Scope.NamingScope.SafeSubScope()); + }); + + if (!notFoundInTypeCache) + { + Logger.DebugFormat("Found cached proxy type {0} for target type {1}.", proxyType.FullName, targetType.FullName); + } + + return proxyType; + } + + protected abstract CacheKey GetCacheKey(); + + protected abstract Type GenerateType(string name, INamingScope namingScope); + + protected void AddMapping(Type @interface, ITypeContributor implementer, IDictionary mapping) + { + Debug.Assert(implementer != null, "implementer != null"); + Debug.Assert(@interface != null, "@interface != null"); + Debug.Assert(@interface.IsInterface, "@interface.IsInterface"); + + if (!mapping.ContainsKey(@interface)) + { + AddMappingNoCheck(@interface, implementer, mapping); + } + } + +#if FEATURE_SERIALIZATION + protected void AddMappingForISerializable(IDictionary typeImplementerMapping, + ITypeContributor instance) + { + AddMapping(typeof(ISerializable), instance, typeImplementerMapping); + } +#endif + + /// + /// It is safe to add mapping (no mapping for the interface exists) + /// + protected void AddMappingNoCheck(Type @interface, ITypeContributor implementer, + IDictionary mapping) + { + mapping.Add(@interface, implementer); + } + + protected virtual ClassEmitter BuildClassEmitter(string typeName, Type parentType, IEnumerable interfaces) + { + CheckNotGenericTypeDefinition(parentType, nameof(parentType)); + CheckNotGenericTypeDefinitions(interfaces, nameof(interfaces)); + + return new ClassEmitter(Scope, typeName, parentType, interfaces); + } + + protected void CheckNotGenericTypeDefinition(Type type, string argumentName) + { + if (type != null && type.IsGenericTypeDefinition) + { + throw new ArgumentException("Type cannot be a generic type definition. Type: " + type.FullName, argumentName); + } + } + + protected void CheckNotGenericTypeDefinitions(IEnumerable types, string argumentName) + { + if (types == null) + { + return; + } + foreach (var t in types) + { + CheckNotGenericTypeDefinition(t, argumentName); + } + } + + protected void CompleteInitCacheMethod(CodeBuilder constCodeBuilder) + { + constCodeBuilder.AddStatement(new ReturnStatement()); + } + + protected virtual void CreateFields(ClassEmitter emitter) + { + CreateOptionsField(emitter); + CreateSelectorField(emitter); + CreateInterceptorsField(emitter); + } + + protected void CreateInterceptorsField(ClassEmitter emitter) + { + var interceptorsField = emitter.CreateField("__interceptors", typeof(IInterceptor[])); + +#if FEATURE_SERIALIZATION + emitter.DefineCustomAttributeFor(interceptorsField); +#endif + } + + protected FieldReference CreateOptionsField(ClassEmitter emitter) + { + return emitter.CreateStaticField("proxyGenerationOptions", typeof(ProxyGenerationOptions)); + } + + protected void CreateSelectorField(ClassEmitter emitter) + { + if (ProxyGenerationOptions.Selector == null) + { + return; + } + + emitter.CreateField("__selector", typeof(IInterceptorSelector)); + } + + protected virtual void CreateTypeAttributes(ClassEmitter emitter) + { + emitter.AddCustomAttributes(ProxyGenerationOptions.AdditionalAttributes); +#if FEATURE_SERIALIZATION + emitter.DefineCustomAttribute(new object[] { targetType }); +#endif + } + + protected void EnsureOptionsOverrideEqualsAndGetHashCode() + { + if (Logger.IsWarnEnabled) + { + // Check the proxy generation hook + if (!OverridesEqualsAndGetHashCode(ProxyGenerationOptions.Hook.GetType())) + { + Logger.WarnFormat("The IProxyGenerationHook type {0} does not override both Equals and GetHashCode. " + + "If these are not correctly overridden caching will fail to work causing performance problems.", + ProxyGenerationOptions.Hook.GetType().FullName); + } + + // Interceptor selectors no longer need to override Equals and GetHashCode + } + } + + protected void GenerateConstructor(ClassEmitter emitter, ConstructorInfo baseConstructor, + params FieldReference[] fields) + { + ArgumentReference[] args; + ParameterInfo[] baseConstructorParams = null; + + if (baseConstructor != null) + { + baseConstructorParams = baseConstructor.GetParameters(); + } + + if (baseConstructorParams != null && baseConstructorParams.Length != 0) + { + args = new ArgumentReference[fields.Length + baseConstructorParams.Length]; + + var offset = fields.Length; + for (var i = offset; i < offset + baseConstructorParams.Length; i++) + { + var paramInfo = baseConstructorParams[i - offset]; + args[i] = new ArgumentReference(paramInfo.ParameterType); + } + } + else + { + args = new ArgumentReference[fields.Length]; + } + + for (var i = 0; i < fields.Length; i++) + { + args[i] = new ArgumentReference(fields[i].Reference.FieldType); + } + + var constructor = emitter.CreateConstructor(args); + if (baseConstructorParams != null && baseConstructorParams.Length != 0) + { + var offset = 1 + fields.Length; + for (int i = 0, n = baseConstructorParams.Length; i < n; ++i) + { + var parameterBuilder = constructor.ConstructorBuilder.DefineParameter(offset + i, baseConstructorParams[i].Attributes, baseConstructorParams[i].Name); + foreach (var attribute in baseConstructorParams[i].GetNonInheritableAttributes()) + { + parameterBuilder.SetCustomAttribute(attribute.Builder); + } + } + } + + for (var i = 0; i < fields.Length; i++) + { + constructor.CodeBuilder.AddStatement(new AssignStatement(fields[i], args[i])); + } + + // Invoke base constructor + + if (baseConstructor != null) + { + Debug.Assert(baseConstructorParams != null); + + var slice = new ArgumentReference[baseConstructorParams.Length]; + Array.Copy(args, fields.Length, slice, 0, baseConstructorParams.Length); + + constructor.CodeBuilder.AddStatement(new ConstructorInvocationStatement(baseConstructor, slice)); + } + else + { + constructor.CodeBuilder.AddStatement(new ConstructorInvocationStatement(emitter.BaseType)); + } + + constructor.CodeBuilder.AddStatement(new ReturnStatement()); + } + + protected void GenerateConstructors(ClassEmitter emitter, Type baseType, params FieldReference[] fields) + { + var constructors = + baseType.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + + foreach (var constructor in constructors) + { + if (!ProxyUtil.IsAccessibleMethod(constructor)) + { + continue; + } + + GenerateConstructor(emitter, constructor, fields); + } + } + + /// + /// Generates a parameters constructor that initializes the proxy + /// state with just to make it non-null. + /// + /// This constructor is important to allow proxies to be XML serializable + /// + /// + protected void GenerateParameterlessConstructor(ClassEmitter emitter, Type baseClass, FieldReference interceptorField) + { + // Check if the type actually has a default constructor + var defaultConstructor = baseClass.GetConstructor(BindingFlags.Public | BindingFlags.Instance, null, Type.EmptyTypes, + null); + + if (defaultConstructor == null) + { + defaultConstructor = baseClass.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, Type.EmptyTypes, + null); + + if (defaultConstructor == null || defaultConstructor.IsPrivate) + { + return; + } + } + + var constructor = emitter.CreateConstructor(); + + // initialize fields with an empty interceptor + + constructor.CodeBuilder.AddStatement(new AssignStatement(interceptorField, + new NewArrayExpression(1, typeof(IInterceptor)))); + constructor.CodeBuilder.AddStatement( + new AssignArrayStatement(interceptorField, 0, new NewInstanceExpression(typeof(StandardInterceptor)))); + + // Invoke base constructor + + constructor.CodeBuilder.AddStatement(new ConstructorInvocationStatement(defaultConstructor)); + + constructor.CodeBuilder.AddStatement(new ReturnStatement()); + } + + protected ConstructorEmitter GenerateStaticConstructor(ClassEmitter emitter) + { + return emitter.CreateTypeConstructor(); + } + + protected void HandleExplicitlyPassedProxyTargetAccessor(ICollection targetInterfaces) + { + var interfaceName = typeof(IProxyTargetAccessor).ToString(); + //ok, let's determine who tried to sneak the IProxyTargetAccessor in... + string message; + if (targetInterfaces.Contains(typeof(IProxyTargetAccessor))) + { + message = + string.Format( + "Target type for the proxy implements {0} which is a DynamicProxy infrastructure interface and you should never implement it yourself. Are you trying to proxy an existing proxy?", + interfaceName); + throw new InvalidOperationException("This is a DynamicProxy2 error: " + message); + } + else if (ProxyGenerationOptions.MixinData.ContainsMixin(typeof(IProxyTargetAccessor))) + { + var mixinType = ProxyGenerationOptions.MixinData.GetMixinInstance(typeof(IProxyTargetAccessor)).GetType(); + message = + string.Format( + "Mixin type {0} implements {1} which is a DynamicProxy infrastructure interface and you should never implement it yourself. Are you trying to mix in an existing proxy?", + mixinType.Name, interfaceName); + throw new InvalidOperationException("This is a DynamicProxy2 error: " + message); + } + else if (interfaces.Contains(typeof(IProxyTargetAccessor))) + { + message = + string.Format( + "You passed {0} as one of additional interfaces to proxy which is a DynamicProxy infrastructure interface and is implemented by every proxy anyway. Please remove it from the list of additional interfaces to proxy.", + interfaceName); + throw new InvalidOperationException("This is a DynamicProxy2 error: " + message); + } + else + { + // this can technically never happen + message = string.Format("It looks like we have a bug with regards to how we handle {0}. Please report it.", + interfaceName); + throw new DynamicProxyException(message); + } + } + + protected void InitializeStaticFields(Type builtType) + { + builtType.SetStaticField("proxyGenerationOptions", BindingFlags.NonPublic, ProxyGenerationOptions); + } + + private bool OverridesEqualsAndGetHashCode(Type type) + { + var equalsMethod = type.GetMethod("Equals", BindingFlags.Public | BindingFlags.Instance); + if (equalsMethod == null || equalsMethod.DeclaringType == typeof(object) || equalsMethod.IsAbstract) + { + return false; + } + + var getHashCodeMethod = type.GetMethod("GetHashCode", BindingFlags.Public | BindingFlags.Instance); + if (getHashCodeMethod == null || getHashCodeMethod.DeclaringType == typeof(object) || getHashCodeMethod.IsAbstract) + { + return false; + } + + return true; + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/CacheKey.cs b/Castle.Core/DynamicProxy/Generators/CacheKey.cs new file mode 100644 index 0000000..d0a98b8 --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/CacheKey.cs @@ -0,0 +1,113 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators +{ + using System; + using System.Reflection; + +#if FEATURE_SERIALIZATION + [Serializable] +#endif + internal class CacheKey + { + private readonly MemberInfo target; + private readonly Type[] interfaces; + private readonly ProxyGenerationOptions options; + private readonly Type type; + + /// + /// Initializes a new instance of the class. + /// + /// Target element. This is either target type or target method for invocation types. + /// The type of the proxy. This is base type for invocation types. + /// The interfaces. + /// The options. + public CacheKey(MemberInfo target, Type type, Type[] interfaces, ProxyGenerationOptions options) + { + this.target = target; + this.type = type; + this.interfaces = interfaces ?? Type.EmptyTypes; + this.options = options; + } + + /// + /// Initializes a new instance of the class. + /// + /// Type of the target. + /// The interfaces. + /// The options. + public CacheKey(Type target, Type[] interfaces, ProxyGenerationOptions options) + : this(target, null, interfaces, options) + { + } + + public override int GetHashCode() + { + var result = target.GetHashCode(); + foreach (var inter in interfaces) + { + result = 29*result + inter.GetHashCode(); + } + if (options != null) + { + result = 29*result + options.GetHashCode(); + } + if (type != null) + { + result = 29*result + type.GetHashCode(); + } + return result; + } + + public override bool Equals(object obj) + { + if (this == obj) + { + return true; + } + + var cacheKey = obj as CacheKey; + if (cacheKey == null) + { + return false; + } + + if (!Equals(type, cacheKey.type)) + { + return false; + } + if (!Equals(target, cacheKey.target)) + { + return false; + } + if (interfaces.Length != cacheKey.interfaces.Length) + { + return false; + } + for (var i = 0; i < interfaces.Length; i++) + { + if (!Equals(interfaces[i], cacheKey.interfaces[i])) + { + return false; + } + } + if (!Equals(options, cacheKey.options)) + { + return false; + } + return true; + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/ClassProxyGenerator.cs b/Castle.Core/DynamicProxy/Generators/ClassProxyGenerator.cs new file mode 100644 index 0000000..7d713f1 --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/ClassProxyGenerator.cs @@ -0,0 +1,58 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators +{ + using System; + using System.Collections.Generic; + using System.Reflection; + + using Castle.DynamicProxy.Contributors; + using Castle.DynamicProxy.Generators.Emitters.SimpleAST; + using Castle.DynamicProxy.Serialization; + + internal sealed class ClassProxyGenerator : BaseClassProxyGenerator + { + public ClassProxyGenerator(ModuleScope scope, Type targetType, Type[] interfaces, ProxyGenerationOptions options) + : base(scope, targetType, interfaces, options) + { + } + + protected override FieldReference TargetField => null; + + protected override CacheKey GetCacheKey() + { + return new CacheKey(targetType, interfaces, ProxyGenerationOptions); + } + +#if FEATURE_SERIALIZATION + protected override SerializableContributor GetSerializableContributor() + { + return new ClassProxySerializableContributor(targetType, interfaces, ProxyTypeConstants.Class); + } +#endif + + protected override CompositeTypeContributor GetProxyTargetContributor(INamingScope namingScope) + { + return new ClassProxyTargetContributor(targetType, namingScope) { Logger = Logger }; + } + + protected override ProxyTargetAccessorContributor GetProxyTargetAccessorContributor() + { + return new ProxyTargetAccessorContributor( + getTargetReference: () => SelfReference.Self, + targetType); + } + } +} diff --git a/Castle.Core/DynamicProxy/Generators/ClassProxyWithTargetGenerator.cs b/Castle.Core/DynamicProxy/Generators/ClassProxyWithTargetGenerator.cs new file mode 100644 index 0000000..c7f6fe6 --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/ClassProxyWithTargetGenerator.cs @@ -0,0 +1,80 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators +{ + using System; + using System.Collections.Generic; + using System.Reflection; + +#if FEATURE_SERIALIZATION + using System.Xml.Serialization; +#endif + + using Castle.DynamicProxy.Contributors; + using Castle.DynamicProxy.Generators.Emitters; + using Castle.DynamicProxy.Generators.Emitters.SimpleAST; + using Castle.DynamicProxy.Serialization; + + internal sealed class ClassProxyWithTargetGenerator : BaseClassProxyGenerator + { + private FieldReference targetField; + + public ClassProxyWithTargetGenerator(ModuleScope scope, Type targetType, Type[] interfaces, + ProxyGenerationOptions options) + : base(scope, targetType, interfaces, options) + { + } + + protected override FieldReference TargetField => targetField; + + protected override CacheKey GetCacheKey() + { + return new CacheKey(targetType, targetType, interfaces, ProxyGenerationOptions); + } + + protected override void CreateFields(ClassEmitter emitter) + { + base.CreateFields(emitter); + CreateTargetField(emitter); + } + +#if FEATURE_SERIALIZATION + protected override SerializableContributor GetSerializableContributor() + { + return new ClassProxySerializableContributor(targetType, interfaces, ProxyTypeConstants.ClassWithTarget); + } +#endif + + protected override CompositeTypeContributor GetProxyTargetContributor(INamingScope namingScope) + { + return new ClassProxyWithTargetTargetContributor(targetType, namingScope) { Logger = Logger }; + } + + protected override ProxyTargetAccessorContributor GetProxyTargetAccessorContributor() + { + return new ProxyTargetAccessorContributor( + getTargetReference: () => targetField, + targetType); + } + + private void CreateTargetField(ClassEmitter emitter) + { + targetField = emitter.CreateField("__target", targetType); +#if FEATURE_SERIALIZATION + emitter.DefineCustomAttributeFor(targetField); +#endif + } + } +} diff --git a/Castle.Core/DynamicProxy/Generators/CompositionInvocationTypeGenerator.cs b/Castle.Core/DynamicProxy/Generators/CompositionInvocationTypeGenerator.cs new file mode 100644 index 0000000..7222725 --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/CompositionInvocationTypeGenerator.cs @@ -0,0 +1,71 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators +{ + using System; + using System.Reflection; + + using Castle.DynamicProxy.Contributors; + using Castle.DynamicProxy.Generators.Emitters; + using Castle.DynamicProxy.Generators.Emitters.SimpleAST; + using Castle.DynamicProxy.Internal; + using Castle.DynamicProxy.Tokens; + + internal class CompositionInvocationTypeGenerator : InvocationTypeGenerator + { + public static readonly Type BaseType = typeof(CompositionInvocation); + + public CompositionInvocationTypeGenerator(Type target, MetaMethod method, MethodInfo callback, bool canChangeTarget, + IInvocationCreationContributor contributor) + : base(target, method, callback, canChangeTarget, contributor) + { + } + + protected override ArgumentReference[] GetBaseCtorArguments(Type targetFieldType, + out ConstructorInfo baseConstructor) + { + baseConstructor = InvocationMethods.CompositionInvocationConstructor; + return new[] + { + new ArgumentReference(targetFieldType), + new ArgumentReference(typeof(object)), + new ArgumentReference(typeof(IInterceptor[])), + new ArgumentReference(typeof(MethodInfo)), + new ArgumentReference(typeof(object[])), + }; + } + + protected override Type GetBaseType() + { + return BaseType; + } + + protected override FieldReference GetTargetReference() + { + return new FieldReference(InvocationMethods.CompositionInvocationTarget); + } + + protected override void ImplementInvokeMethodOnTarget(AbstractTypeEmitter invocation, ParameterInfo[] parameters, + MethodEmitter invokeMethodOnTarget, Reference targetField) + { + invokeMethodOnTarget.CodeBuilder.AddStatement( + new MethodInvocationExpression( + SelfReference.Self, + InvocationMethods.CompositionInvocationEnsureValidTarget)); + + base.ImplementInvokeMethodOnTarget(invocation, parameters, invokeMethodOnTarget, targetField); + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/DelegateTypeGenerator.cs b/Castle.Core/DynamicProxy/Generators/DelegateTypeGenerator.cs new file mode 100644 index 0000000..8efd6d4 --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/DelegateTypeGenerator.cs @@ -0,0 +1,109 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators +{ + using System; + using System.Reflection; + + using Castle.DynamicProxy.Generators.Emitters; + using Castle.DynamicProxy.Generators.Emitters.SimpleAST; + using Castle.DynamicProxy.Internal; + + internal class DelegateTypeGenerator : IGenerator + { + private const TypeAttributes DelegateFlags = TypeAttributes.Class | + TypeAttributes.Public | + TypeAttributes.Sealed | + TypeAttributes.AnsiClass | + TypeAttributes.AutoClass; + + private readonly MetaMethod method; + private readonly Type targetType; + + public DelegateTypeGenerator(MetaMethod method, Type targetType) + { + this.method = method; + this.targetType = targetType; + } + + public AbstractTypeEmitter Generate(ClassEmitter @class, INamingScope namingScope) + { + var emitter = GetEmitter(@class, namingScope); + BuildConstructor(emitter); + BuildInvokeMethod(emitter); + return emitter; + } + + private void BuildConstructor(AbstractTypeEmitter emitter) + { + var constructor = emitter.CreateConstructor(new ArgumentReference(typeof(object)), + new ArgumentReference(typeof(IntPtr))); + constructor.ConstructorBuilder.SetImplementationFlags(MethodImplAttributes.Runtime | MethodImplAttributes.Managed); + } + + private void BuildInvokeMethod(AbstractTypeEmitter @delegate) + { + var paramTypes = GetParamTypes(@delegate); + var invoke = @delegate.CreateMethod("Invoke", + MethodAttributes.Public | + MethodAttributes.HideBySig | + MethodAttributes.NewSlot | + MethodAttributes.Virtual, + @delegate.GetClosedParameterType(method.MethodOnTarget.ReturnType), + paramTypes); + invoke.MethodBuilder.SetImplementationFlags(MethodImplAttributes.Runtime | MethodImplAttributes.Managed); + } + + private AbstractTypeEmitter GetEmitter(ClassEmitter @class, INamingScope namingScope) + { + var methodInfo = method.MethodOnTarget; + var suggestedName = string.Format("Castle.Proxies.Delegates.{0}_{1}", + methodInfo.DeclaringType.Name, + method.Method.Name); + var uniqueName = namingScope.ParentScope.GetUniqueName(suggestedName); + + var @delegate = new ClassEmitter(@class.ModuleScope, + uniqueName, + typeof(MulticastDelegate), + Type.EmptyTypes, + DelegateFlags, + forceUnsigned: @class.InStrongNamedModule == false); + @delegate.CopyGenericParametersFromMethod(method.Method); + return @delegate; + } + + private Type[] GetParamTypes(AbstractTypeEmitter @delegate) + { + var parameters = method.MethodOnTarget.GetParameters(); + if (@delegate.TypeBuilder.IsGenericType) + { + var types = new Type[parameters.Length]; + + for (var i = 0; i < parameters.Length; i++) + { + types[i] = @delegate.GetClosedParameterType(parameters[i].ParameterType); + } + return types; + } + var paramTypes = new Type[parameters.Length + 1]; + paramTypes[0] = targetType; + for (var i = 0; i < parameters.Length; i++) + { + paramTypes[i + 1] = @delegate.GetClosedParameterType(parameters[i].ParameterType); + } + return paramTypes; + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/AbstractTypeEmitter.cs b/Castle.Core/DynamicProxy/Generators/Emitters/AbstractTypeEmitter.cs new file mode 100644 index 0000000..43b7958 --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/Emitters/AbstractTypeEmitter.cs @@ -0,0 +1,374 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators.Emitters +{ + using System; + using System.Collections.Generic; + using System.Diagnostics; + using System.Reflection; + using System.Reflection.Emit; + + using Castle.DynamicProxy.Generators.Emitters.SimpleAST; + using Castle.DynamicProxy.Internal; + + internal abstract class AbstractTypeEmitter + { + private const MethodAttributes defaultAttributes = + MethodAttributes.HideBySig | MethodAttributes.Virtual | MethodAttributes.Public; + + private readonly List constructors; + private readonly List events; + + private readonly IDictionary fields = + new Dictionary(StringComparer.OrdinalIgnoreCase); + + private readonly List methods; + + private readonly List nested; + private readonly List properties; + private readonly TypeBuilder typebuilder; + + private GenericTypeParameterBuilder[] genericTypeParams; + + protected AbstractTypeEmitter(TypeBuilder typeBuilder) + { + typebuilder = typeBuilder; + nested = new List(); + methods = new List(); + constructors = new List(); + properties = new List(); + events = new List(); + } + + public Type BaseType + { + get + { + if (TypeBuilder.IsInterface) + { + throw new InvalidOperationException("This emitter represents an interface; interfaces have no base types."); + } + return TypeBuilder.BaseType; + } + } + + public TypeConstructorEmitter ClassConstructor { get; private set; } + + public GenericTypeParameterBuilder[] GenericTypeParams + { + get { return genericTypeParams; } + } + + public TypeBuilder TypeBuilder + { + get { return typebuilder; } + } + + public void AddCustomAttributes(IEnumerable additionalAttributes) + { + foreach (var attribute in additionalAttributes) + { + typebuilder.SetCustomAttribute(attribute.Builder); + } + } + + public void AddNestedClass(NestedClassEmitter nestedClass) + { + nested.Add(nestedClass); + } + + public virtual Type BuildType() + { + EnsureBuildersAreInAValidState(); + + var type = CreateType(typebuilder); + + foreach (var builder in nested) + { + builder.BuildType(); + } + + return type; + } + + public void CopyGenericParametersFromMethod(MethodInfo methodToCopyGenericsFrom) + { + // big sanity check + if (genericTypeParams != null) + { + throw new InvalidOperationException("Cannot invoke me twice"); + } + + SetGenericTypeParameters(GenericUtil.CopyGenericArguments(methodToCopyGenericsFrom, typebuilder)); + } + + public ConstructorEmitter CreateConstructor(params ArgumentReference[] arguments) + { + if (TypeBuilder.IsInterface) + { + throw new InvalidOperationException("Interfaces cannot have constructors."); + } + + var member = new ConstructorEmitter(this, arguments); + constructors.Add(member); + return member; + } + + public void CreateDefaultConstructor() + { + if (TypeBuilder.IsInterface) + { + throw new InvalidOperationException("Interfaces cannot have constructors."); + } + + constructors.Add(new ConstructorEmitter(this)); + } + + public EventEmitter CreateEvent(string name, EventAttributes atts, Type type) + { + var eventEmitter = new EventEmitter(this, name, atts, type); + events.Add(eventEmitter); + return eventEmitter; + } + + public FieldReference CreateField(string name, Type fieldType) + { + return CreateField(name, fieldType, true); + } + + public FieldReference CreateField(string name, Type fieldType, bool serializable) + { + var atts = FieldAttributes.Private; + + if (!serializable) + { + atts |= FieldAttributes.NotSerialized; + } + + return CreateField(name, fieldType, atts); + } + + public FieldReference CreateField(string name, Type fieldType, FieldAttributes atts) + { + var fieldBuilder = typebuilder.DefineField(name, fieldType, atts); + var reference = new FieldReference(fieldBuilder); + fields[name] = reference; + return reference; + } + + public MethodEmitter CreateMethod(string name, MethodAttributes attrs, Type returnType, params Type[] argumentTypes) + { + var member = new MethodEmitter(this, name, attrs, returnType, argumentTypes ?? Type.EmptyTypes); + methods.Add(member); + return member; + } + + public MethodEmitter CreateMethod(string name, Type returnType, params Type[] parameterTypes) + { + return CreateMethod(name, defaultAttributes, returnType, parameterTypes); + } + + public MethodEmitter CreateMethod(string name, MethodInfo methodToUseAsATemplate) + { + return CreateMethod(name, defaultAttributes, methodToUseAsATemplate); + } + + public MethodEmitter CreateMethod(string name, MethodAttributes attributes, MethodInfo methodToUseAsATemplate) + { + var method = new MethodEmitter(this, name, attributes, methodToUseAsATemplate); + methods.Add(method); + return method; + } + + public PropertyEmitter CreateProperty(string name, PropertyAttributes attributes, Type propertyType, Type[] arguments) + { + var propEmitter = new PropertyEmitter(this, name, attributes, propertyType, arguments); + properties.Add(propEmitter); + return propEmitter; + } + + public FieldReference CreateStaticField(string name, Type fieldType) + { + return CreateStaticField(name, fieldType, FieldAttributes.Private); + } + + public FieldReference CreateStaticField(string name, Type fieldType, FieldAttributes atts) + { + atts |= FieldAttributes.Static; + return CreateField(name, fieldType, atts); + } + + public ConstructorEmitter CreateTypeConstructor() + { + var member = new TypeConstructorEmitter(this); + constructors.Add(member); + ClassConstructor = member; + return member; + } + + public void DefineCustomAttribute(CustomAttributeBuilder attribute) + { + typebuilder.SetCustomAttribute(attribute); + } + + public void DefineCustomAttribute(object[] constructorArguments) where TAttribute : Attribute + { + var customAttributeInfo = AttributeUtil.CreateInfo(typeof(TAttribute), constructorArguments); + typebuilder.SetCustomAttribute(customAttributeInfo.Builder); + } + + public void DefineCustomAttribute() where TAttribute : Attribute, new() + { + var customAttributeInfo = AttributeUtil.CreateInfo(); + typebuilder.SetCustomAttribute(customAttributeInfo.Builder); + } + + public void DefineCustomAttributeFor(FieldReference field) where TAttribute : Attribute, new() + { + var customAttributeInfo = AttributeUtil.CreateInfo(); + var fieldbuilder = field.Fieldbuilder; + if (fieldbuilder == null) + { + throw new ArgumentException( + "Invalid field reference.This reference does not point to field on type being generated", nameof(field)); + } + fieldbuilder.SetCustomAttribute(customAttributeInfo.Builder); + } + + public IEnumerable GetAllFields() + { + return fields.Values; + } + + public FieldReference GetField(string name) + { + if (string.IsNullOrEmpty(name)) + { + return null; + } + + FieldReference value; + fields.TryGetValue(name, out value); + return value; + } + + public Type GetClosedParameterType(Type parameter) + { + if (parameter.IsGenericType) + { + // ECMA-335 section II.9.4: "The CLI does not support partial instantiation + // of generic types. And generic types shall not appear uninstantiated any- + // where in metadata signature blobs." (And parameters are defined there!) + Debug.Assert(parameter.IsGenericTypeDefinition == false); + + var arguments = parameter.GetGenericArguments(); + if (CloseGenericParametersIfAny(arguments)) + { + return parameter.GetGenericTypeDefinition().MakeGenericType(arguments); + } + } + + if (parameter.IsGenericParameter) + { + return GetGenericArgument(parameter.GenericParameterPosition); + } + + if (parameter.IsArray) + { + var elementType = GetClosedParameterType(parameter.GetElementType()); + int rank = parameter.GetArrayRank(); + return rank == 1 + ? elementType.MakeArrayType() + : elementType.MakeArrayType(rank); + } + + if (parameter.IsByRef) + { + var elementType = GetClosedParameterType(parameter.GetElementType()); + return elementType.MakeByRefType(); + } + + return parameter; + + bool CloseGenericParametersIfAny(Type[] arguments) + { + var hasAnyGenericParameters = false; + for (var i = 0; i < arguments.Length; i++) + { + var newType = GetClosedParameterType(arguments[i]); + if (newType != null && !ReferenceEquals(newType, arguments[i])) + { + arguments[i] = newType; + hasAnyGenericParameters = true; + } + } + return hasAnyGenericParameters; + } + } + + public Type GetGenericArgument(int position) + { + Debug.Assert(0 <= position && position < genericTypeParams.Length); + + return genericTypeParams[position]; + } + + public Type[] GetGenericArgumentsFor(MethodInfo genericMethod) + { + Debug.Assert(genericMethod.GetGenericArguments().Length == genericTypeParams.Length); + + return genericTypeParams; + } + + public void SetGenericTypeParameters(GenericTypeParameterBuilder[] genericTypeParameterBuilders) + { + genericTypeParams = genericTypeParameterBuilders; + } + + protected Type CreateType(TypeBuilder type) + { + return type.CreateTypeInfo(); + } + + protected virtual void EnsureBuildersAreInAValidState() + { + if (!typebuilder.IsInterface && constructors.Count == 0) + { + CreateDefaultConstructor(); + } + + foreach (IMemberEmitter builder in properties) + { + builder.EnsureValidCodeBlock(); + builder.Generate(); + } + foreach (IMemberEmitter builder in events) + { + builder.EnsureValidCodeBlock(); + builder.Generate(); + } + foreach (IMemberEmitter builder in constructors) + { + builder.EnsureValidCodeBlock(); + builder.Generate(); + } + foreach (IMemberEmitter builder in methods) + { + builder.EnsureValidCodeBlock(); + builder.Generate(); + } + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/ArgumentsUtil.cs b/Castle.Core/DynamicProxy/Generators/Emitters/ArgumentsUtil.cs new file mode 100644 index 0000000..2e0396d --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/Emitters/ArgumentsUtil.cs @@ -0,0 +1,105 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators.Emitters +{ + using System; + using System.Reflection; + using System.Reflection.Emit; + + using Castle.DynamicProxy.Generators.Emitters.SimpleAST; + + internal abstract class ArgumentsUtil + { + public static ArgumentReference[] ConvertToArgumentReference(Type[] args) + { + var arguments = new ArgumentReference[args.Length]; + + for (var i = 0; i < args.Length; ++i) + { + arguments[i] = new ArgumentReference(args[i]); + } + + return arguments; + } + + public static ArgumentReference[] ConvertToArgumentReference(ParameterInfo[] args) + { + var arguments = new ArgumentReference[args.Length]; + + for (var i = 0; i < args.Length; ++i) + { + arguments[i] = new ArgumentReference(args[i].ParameterType); + } + + return arguments; + } + + public static IExpression[] ConvertToArgumentReferenceExpression(ParameterInfo[] args) + { + var arguments = new IExpression[args.Length]; + + for (var i = 0; i < args.Length; ++i) + { + arguments[i] = new ArgumentReference(args[i].ParameterType, i + 1); + } + + return arguments; + } + + public static void EmitLoadOwnerAndReference(Reference reference, ILGenerator il) + { + if (reference == null) + { + return; + } + + EmitLoadOwnerAndReference(reference.OwnerReference, il); + + reference.LoadReference(il); + } + + public static Type[] GetTypes(ParameterInfo[] parameters) + { + var types = new Type[parameters.Length]; + for (var i = 0; i < parameters.Length; i++) + { + types[i] = parameters[i].ParameterType; + } + return types; + } + + public static Type[] InitializeAndConvert(ArgumentReference[] args) + { + var types = new Type[args.Length]; + + for (var i = 0; i < args.Length; ++i) + { + args[i].Position = i + 1; + types[i] = args[i].Type; + } + + return types; + } + + public static void InitializeArgumentsByPosition(ArgumentReference[] args, bool isStatic) + { + var offset = isStatic ? 0 : 1; + for (var i = 0; i < args.Length; ++i) + { + args[i].Position = i + offset; + } + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/ClassEmitter.cs b/Castle.Core/DynamicProxy/Generators/Emitters/ClassEmitter.cs new file mode 100644 index 0000000..cb2023b --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/Emitters/ClassEmitter.cs @@ -0,0 +1,109 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators.Emitters +{ + using System; + using System.Collections.Generic; + using System.Diagnostics; + using System.Reflection; + using System.Reflection.Emit; + + using Castle.DynamicProxy.Internal; + + internal class ClassEmitter : AbstractTypeEmitter + { + internal const TypeAttributes DefaultAttributes = + TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.Serializable; + + private readonly ModuleScope moduleScope; + + public ClassEmitter(ModuleScope modulescope, string name, Type baseType, IEnumerable interfaces) + : this(modulescope, name, baseType, interfaces, DefaultAttributes, forceUnsigned: false) + { + } + + public ClassEmitter(ModuleScope modulescope, string name, Type baseType, IEnumerable interfaces, + TypeAttributes flags, + bool forceUnsigned) + : this(CreateTypeBuilder(modulescope, name, baseType, interfaces, flags, forceUnsigned)) + { + interfaces = InitializeGenericArgumentsFromBases(ref baseType, interfaces); + + if (interfaces != null) + { + foreach (var inter in interfaces) + { + if (inter.IsInterface) + { + TypeBuilder.AddInterfaceImplementation(inter); + } + else + { + Debug.Assert(inter.IsDelegateType()); + } + } + } + + TypeBuilder.SetParent(baseType); + moduleScope = modulescope; + } + + public ClassEmitter(TypeBuilder typeBuilder) + : base(typeBuilder) + { + } + + public ModuleScope ModuleScope + { + get { return moduleScope; } + } + + internal bool InStrongNamedModule + { + get { return StrongNameUtil.IsAssemblySigned(TypeBuilder.Assembly); } + } + + protected virtual IEnumerable InitializeGenericArgumentsFromBases(ref Type baseType, + IEnumerable interfaces) + { + if (baseType != null && baseType.IsGenericTypeDefinition) + { + throw new NotSupportedException("ClassEmitter does not support open generic base types. Type: " + baseType.FullName); + } + + if (interfaces == null) + { + return interfaces; + } + + foreach (var inter in interfaces) + { + if (inter.IsGenericTypeDefinition) + { + throw new NotSupportedException("ClassEmitter does not support open generic interfaces. Type: " + inter.FullName); + } + } + return interfaces; + } + + private static TypeBuilder CreateTypeBuilder(ModuleScope modulescope, string name, Type baseType, + IEnumerable interfaces, + TypeAttributes flags, bool forceUnsigned) + { + var isAssemblySigned = !forceUnsigned && !StrongNameUtil.IsAnyTypeFromUnsignedAssembly(baseType, interfaces); + return modulescope.DefineType(isAssemblySigned, name, flags); + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/CodeBuilder.cs b/Castle.Core/DynamicProxy/Generators/Emitters/CodeBuilder.cs new file mode 100644 index 0000000..606e975 --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/Emitters/CodeBuilder.cs @@ -0,0 +1,68 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators.Emitters +{ + using System; + using System.Collections.Generic; + using System.Reflection.Emit; + + using Castle.DynamicProxy.Generators.Emitters.SimpleAST; + + internal sealed class CodeBuilder + { + private readonly List locals; + private readonly List statements; + private bool isEmpty; + + public CodeBuilder() + { + statements = new List(); + locals = new List(); + isEmpty = true; + } + + internal bool IsEmpty + { + get { return isEmpty; } + } + + public CodeBuilder AddStatement(IStatement statement) + { + isEmpty = false; + statements.Add(statement); + return this; + } + + public LocalReference DeclareLocal(Type type) + { + var local = new LocalReference(type); + locals.Add(local); + return local; + } + + internal void Generate(ILGenerator il) + { + foreach (var local in locals) + { + local.Generate(il); + } + + foreach (var statement in statements) + { + statement.Emit(il); + } + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/ConstructorEmitter.cs b/Castle.Core/DynamicProxy/Generators/Emitters/ConstructorEmitter.cs new file mode 100644 index 0000000..37ab582 --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/Emitters/ConstructorEmitter.cs @@ -0,0 +1,94 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators.Emitters +{ + using System; + using System.Reflection; + using System.Reflection.Emit; + + using Castle.DynamicProxy.Generators.Emitters.SimpleAST; + + internal class ConstructorEmitter : IMemberEmitter + { + private readonly ConstructorBuilder builder; + private readonly CodeBuilder codeBuilder; + private readonly AbstractTypeEmitter maintype; + + protected internal ConstructorEmitter(AbstractTypeEmitter maintype, ConstructorBuilder builder) + { + this.maintype = maintype; + this.builder = builder; + codeBuilder = new CodeBuilder(); + } + + internal ConstructorEmitter(AbstractTypeEmitter maintype, params ArgumentReference[] arguments) + { + this.maintype = maintype; + + var args = ArgumentsUtil.InitializeAndConvert(arguments); + + builder = maintype.TypeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, args); + codeBuilder = new CodeBuilder(); + } + + public CodeBuilder CodeBuilder + { + get { return codeBuilder; } + } + + public ConstructorBuilder ConstructorBuilder + { + get { return builder; } + } + + public MemberInfo Member + { + get { return builder; } + } + + public Type ReturnType + { + get { return typeof(void); } + } + + private bool ImplementedByRuntime + { + get + { + var attributes = builder.MethodImplementationFlags; + return (attributes & MethodImplAttributes.Runtime) != 0; + } + } + + public virtual void EnsureValidCodeBlock() + { + if (ImplementedByRuntime == false && CodeBuilder.IsEmpty) + { + CodeBuilder.AddStatement(new ConstructorInvocationStatement(maintype.BaseType)); + CodeBuilder.AddStatement(new ReturnStatement()); + } + } + + public virtual void Generate() + { + if (ImplementedByRuntime) + { + return; + } + + CodeBuilder.Generate(builder.GetILGenerator()); + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/EventEmitter.cs b/Castle.Core/DynamicProxy/Generators/Emitters/EventEmitter.cs new file mode 100644 index 0000000..08ad72e --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/Emitters/EventEmitter.cs @@ -0,0 +1,99 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators.Emitters +{ + using System; + using System.Reflection; + using System.Reflection.Emit; + + internal class EventEmitter : IMemberEmitter + { + private readonly EventBuilder eventBuilder; + private readonly Type type; + private readonly AbstractTypeEmitter typeEmitter; + private MethodEmitter addMethod; + private MethodEmitter removeMethod; + + public EventEmitter(AbstractTypeEmitter typeEmitter, string name, EventAttributes attributes, Type type) + { + if (name == null) + { + throw new ArgumentNullException(nameof(name)); + } + if (type == null) + { + throw new ArgumentNullException(nameof(type)); + } + this.typeEmitter = typeEmitter; + this.type = type; + eventBuilder = typeEmitter.TypeBuilder.DefineEvent(name, attributes, type); + } + + public MemberInfo Member + { + get { return null; } + } + + public Type ReturnType + { + get { return type; } + } + + public MethodEmitter CreateAddMethod(string addMethodName, MethodAttributes attributes, MethodInfo methodToOverride) + { + if (addMethod != null) + { + throw new InvalidOperationException("An add method exists"); + } + + addMethod = new MethodEmitter(typeEmitter, addMethodName, attributes, methodToOverride); + return addMethod; + } + + public MethodEmitter CreateRemoveMethod(string removeMethodName, MethodAttributes attributes, + MethodInfo methodToOverride) + { + if (removeMethod != null) + { + throw new InvalidOperationException("A remove method exists"); + } + removeMethod = new MethodEmitter(typeEmitter, removeMethodName, attributes, methodToOverride); + return removeMethod; + } + + public void EnsureValidCodeBlock() + { + addMethod.EnsureValidCodeBlock(); + removeMethod.EnsureValidCodeBlock(); + } + + public void Generate() + { + if (addMethod == null) + { + throw new InvalidOperationException("Event add method was not created"); + } + if (removeMethod == null) + { + throw new InvalidOperationException("Event remove method was not created"); + } + addMethod.Generate(); + eventBuilder.SetAddOnMethod(addMethod.MethodBuilder); + + removeMethod.Generate(); + eventBuilder.SetRemoveOnMethod(removeMethod.MethodBuilder); + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/GenericUtil.cs b/Castle.Core/DynamicProxy/Generators/Emitters/GenericUtil.cs new file mode 100644 index 0000000..458ce77 --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/Emitters/GenericUtil.cs @@ -0,0 +1,160 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators.Emitters +{ + using System; + using System.Diagnostics; + using System.Reflection; + using System.Reflection.Emit; + + using Castle.Core.Internal; + using Castle.DynamicProxy.Internal; + + internal delegate GenericTypeParameterBuilder[] ApplyGenArgs(string[] argumentNames); + + internal class GenericUtil + { + public static GenericTypeParameterBuilder[] CopyGenericArguments( + MethodInfo methodToCopyGenericsFrom, + TypeBuilder builder) + { + return CopyGenericArguments(methodToCopyGenericsFrom, builder.DefineGenericParameters); + } + + public static GenericTypeParameterBuilder[] CopyGenericArguments( + MethodInfo methodToCopyGenericsFrom, + MethodBuilder builder) + { + return CopyGenericArguments(methodToCopyGenericsFrom, builder.DefineGenericParameters); + } + + private static Type AdjustConstraintToNewGenericParameters( + Type constraint, MethodInfo methodToCopyGenericsFrom, Type[] originalGenericParameters, + GenericTypeParameterBuilder[] newGenericParameters) + { + if (constraint.IsGenericType) + { + var genericArgumentsOfConstraint = constraint.GetGenericArguments(); + + for (var i = 0; i < genericArgumentsOfConstraint.Length; ++i) + { + genericArgumentsOfConstraint[i] = + AdjustConstraintToNewGenericParameters(genericArgumentsOfConstraint[i], methodToCopyGenericsFrom, + originalGenericParameters, newGenericParameters); + } + return constraint.GetGenericTypeDefinition().MakeGenericType(genericArgumentsOfConstraint); + } + else if (constraint.IsGenericParameter) + { + // Determine the source of the parameter + if (constraint.DeclaringMethod != null) + { + // constraint comes from the method + var index = Array.IndexOf(originalGenericParameters, constraint); + Trace.Assert(index != -1, + "When a generic method parameter has a constraint on another method parameter, both parameters must be declared on the same method."); + return newGenericParameters[index]; + } + else // parameter from surrounding type + { + Trace.Assert(constraint.DeclaringType.IsGenericTypeDefinition); + Trace.Assert(methodToCopyGenericsFrom.DeclaringType.IsGenericType + && constraint.DeclaringType == methodToCopyGenericsFrom.DeclaringType.GetGenericTypeDefinition(), + "When a generic method parameter has a constraint on a generic type parameter, the generic type must be the declaring typer of the method."); + + var index = Array.IndexOf(constraint.DeclaringType.GetGenericArguments(), constraint); + Trace.Assert(index != -1, "The generic parameter comes from the given type."); + return methodToCopyGenericsFrom.DeclaringType.GetGenericArguments()[index]; // these are the actual, concrete types + } + } + else + { + return constraint; + } + } + + private static Type[] AdjustGenericConstraints(MethodInfo methodToCopyGenericsFrom, + GenericTypeParameterBuilder[] newGenericParameters, + Type[] originalGenericArguments, + Type[] constraints) + { + // HACK: the mono runtime has a strange bug where assigning to the constraints + // parameter and returning it throws, so we'll create a new array. + // System.ArrayTypeMismatchException : Source array type cannot be assigned to destination array type. + Type[] adjustedConstraints = new Type[constraints.Length]; + for (var i = 0; i < constraints.Length; i++) + { + adjustedConstraints[i] = AdjustConstraintToNewGenericParameters(constraints[i], + methodToCopyGenericsFrom, originalGenericArguments, newGenericParameters); + } + return adjustedConstraints; + } + + private static GenericTypeParameterBuilder[] CopyGenericArguments( + MethodInfo methodToCopyGenericsFrom, + ApplyGenArgs genericParameterGenerator) + { + var originalGenericArguments = methodToCopyGenericsFrom.GetGenericArguments(); + if (originalGenericArguments.Length == 0) + { + return null; + } + + var argumentNames = GetArgumentNames(originalGenericArguments); + var newGenericParameters = genericParameterGenerator(argumentNames); + + for (var i = 0; i < newGenericParameters.Length; i++) + { + try + { + var attributes = originalGenericArguments[i].GenericParameterAttributes; + newGenericParameters[i].SetGenericParameterAttributes(attributes); + var constraints = AdjustGenericConstraints(methodToCopyGenericsFrom, newGenericParameters, originalGenericArguments, originalGenericArguments[i].GetGenericParameterConstraints()); + + newGenericParameters[i].SetInterfaceConstraints(constraints); + CopyNonInheritableAttributes(newGenericParameters[i], originalGenericArguments[i]); + } + catch (NotSupportedException) + { + // Doesn't matter + + newGenericParameters[i].SetGenericParameterAttributes(GenericParameterAttributes.None); + } + } + + return newGenericParameters; + } + + private static void CopyNonInheritableAttributes(GenericTypeParameterBuilder newGenericParameter, + Type originalGenericArgument) + { + foreach (var attribute in originalGenericArgument.GetNonInheritableAttributes()) + { + newGenericParameter.SetCustomAttribute(attribute.Builder); + } + } + + private static string[] GetArgumentNames(Type[] originalGenericArguments) + { + var argumentNames = new string[originalGenericArguments.Length]; + + for (var i = 0; i < argumentNames.Length; i++) + { + argumentNames[i] = originalGenericArguments[i].Name; + } + return argumentNames; + } + } +} diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/IMemberEmitter.cs b/Castle.Core/DynamicProxy/Generators/Emitters/IMemberEmitter.cs new file mode 100644 index 0000000..9f6676a --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/Emitters/IMemberEmitter.cs @@ -0,0 +1,30 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators.Emitters +{ + using System; + using System.Reflection; + + internal interface IMemberEmitter + { + MemberInfo Member { get; } + + Type ReturnType { get; } + + void EnsureValidCodeBlock(); + + void Generate(); + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/LdcOpCodesDictionary.cs b/Castle.Core/DynamicProxy/Generators/Emitters/LdcOpCodesDictionary.cs new file mode 100644 index 0000000..c461e73 --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/Emitters/LdcOpCodesDictionary.cs @@ -0,0 +1,69 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators.Emitters +{ + using System; + using System.Collections.Generic; + using System.Reflection.Emit; + + /// + /// Provides appropriate Ldc.X opcode for the type of primitive value to be loaded. + /// + internal sealed class LdcOpCodesDictionary : Dictionary + { + private static readonly LdcOpCodesDictionary dict = new LdcOpCodesDictionary(); + + // has to be assigned explicitly to suppress compiler warning + private static readonly OpCode emptyOpCode = new OpCode(); + + private LdcOpCodesDictionary() + { + Add(typeof(bool), OpCodes.Ldc_I4); + Add(typeof(char), OpCodes.Ldc_I4); + Add(typeof(SByte), OpCodes.Ldc_I4); + Add(typeof(Int16), OpCodes.Ldc_I4); + Add(typeof(Int32), OpCodes.Ldc_I4); + Add(typeof(Int64), OpCodes.Ldc_I8); + Add(typeof(float), OpCodes.Ldc_R4); + Add(typeof(double), OpCodes.Ldc_R8); + Add(typeof(byte), OpCodes.Ldc_I4_0); + Add(typeof(UInt16), OpCodes.Ldc_I4_0); + Add(typeof(UInt32), OpCodes.Ldc_I4_0); + Add(typeof(UInt64), OpCodes.Ldc_I4_0); + } + + public new OpCode this[Type type] + { + get + { + if (TryGetValue(type, out var opCode)) + { + return opCode; + } + return EmptyOpCode; + } + } + + public static OpCode EmptyOpCode + { + get { return emptyOpCode; } + } + + public static LdcOpCodesDictionary Instance + { + get { return dict; } + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/LdindOpCodesDictionary.cs b/Castle.Core/DynamicProxy/Generators/Emitters/LdindOpCodesDictionary.cs new file mode 100644 index 0000000..a605fd7 --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/Emitters/LdindOpCodesDictionary.cs @@ -0,0 +1,70 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators.Emitters +{ + using System; + using System.Collections.Generic; + using System.Reflection.Emit; + + /// + /// Provides appropriate Ldind.X opcode for + /// the type of primitive value to be loaded indirectly. + /// + internal sealed class LdindOpCodesDictionary : Dictionary + { + private static readonly LdindOpCodesDictionary dict = new LdindOpCodesDictionary(); + + // has to be assigned explicitly to suppress compiler warning + private static readonly OpCode emptyOpCode = new OpCode(); + + private LdindOpCodesDictionary() + { + Add(typeof(bool), OpCodes.Ldind_I1); + Add(typeof(char), OpCodes.Ldind_I2); + Add(typeof(SByte), OpCodes.Ldind_I1); + Add(typeof(Int16), OpCodes.Ldind_I2); + Add(typeof(Int32), OpCodes.Ldind_I4); + Add(typeof(Int64), OpCodes.Ldind_I8); + Add(typeof(float), OpCodes.Ldind_R4); + Add(typeof(double), OpCodes.Ldind_R8); + Add(typeof(byte), OpCodes.Ldind_U1); + Add(typeof(UInt16), OpCodes.Ldind_U2); + Add(typeof(UInt32), OpCodes.Ldind_U4); + Add(typeof(UInt64), OpCodes.Ldind_I8); + } + + public new OpCode this[Type type] + { + get + { + if (TryGetValue(type, out var opCode)) + { + return opCode; + } + return EmptyOpCode; + } + } + + public static OpCode EmptyOpCode + { + get { return emptyOpCode; } + } + + public static LdindOpCodesDictionary Instance + { + get { return dict; } + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/MethodEmitter.cs b/Castle.Core/DynamicProxy/Generators/Emitters/MethodEmitter.cs new file mode 100644 index 0000000..7d2579f --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/Emitters/MethodEmitter.cs @@ -0,0 +1,350 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators.Emitters +{ + using System; + using System.Collections.Generic; + using System.Diagnostics; + using System.Globalization; + using System.Linq; + using System.Reflection; + using System.Reflection.Emit; + + using Castle.DynamicProxy.Generators.Emitters.SimpleAST; + using Castle.DynamicProxy.Internal; + + [DebuggerDisplay("{builder.Name}")] + internal class MethodEmitter : IMemberEmitter + { + private readonly MethodBuilder builder; + private readonly CodeBuilder codeBuilder; + private readonly GenericTypeParameterBuilder[] genericTypeParams; + + private ArgumentReference[] arguments; + + protected internal MethodEmitter(MethodBuilder builder) + { + this.builder = builder; + codeBuilder = new CodeBuilder(); + } + + internal MethodEmitter(AbstractTypeEmitter owner, string name, MethodAttributes attributes) + : this(owner.TypeBuilder.DefineMethod(name, attributes)) + { + } + + internal MethodEmitter(AbstractTypeEmitter owner, string name, + MethodAttributes attributes, Type returnType, + params Type[] argumentTypes) + : this(owner, name, attributes) + { + SetParameters(argumentTypes); + SetReturnType(returnType); + } + + internal MethodEmitter(AbstractTypeEmitter owner, string name, + MethodAttributes attributes, MethodInfo methodToUseAsATemplate) + : this(owner, name, attributes) + { + // All code paths leading up to this constructor can be traced back to + // proxy type generation code. At present, proxy types are never generic. + Debug.Assert(owner.GenericTypeParams == null || owner.GenericTypeParams.Length == 0); + + var returnType = methodToUseAsATemplate.ReturnType; + var baseMethodParameters = methodToUseAsATemplate.GetParameters(); + var parameters = ArgumentsUtil.GetTypes(baseMethodParameters); + + genericTypeParams = GenericUtil.CopyGenericArguments(methodToUseAsATemplate, builder); + SetParameters(parameters); + SetReturnType(returnType); + SetSignature(returnType, methodToUseAsATemplate.ReturnParameter, parameters, baseMethodParameters); + DefineParameters(baseMethodParameters); + } + + public ArgumentReference[] Arguments + { + get { return arguments; } + } + + public CodeBuilder CodeBuilder + { + get { return codeBuilder; } + } + + public GenericTypeParameterBuilder[] GenericTypeParams + { + get { return genericTypeParams; } + } + + public MethodBuilder MethodBuilder + { + get { return builder; } + } + + public MemberInfo Member + { + get { return builder; } + } + + public Type ReturnType + { + get { return builder.ReturnType; } + } + + private bool ImplementedByRuntime + { + get + { + var attributes = builder.MethodImplementationFlags; + return (attributes & MethodImplAttributes.Runtime) != 0; + } + } + + public void DefineCustomAttribute(CustomAttributeBuilder attribute) + { + builder.SetCustomAttribute(attribute); + } + + public void SetParameters(Type[] paramTypes) + { + builder.SetParameters(paramTypes); + arguments = ArgumentsUtil.ConvertToArgumentReference(paramTypes); + ArgumentsUtil.InitializeArgumentsByPosition(arguments, MethodBuilder.IsStatic); + } + + public virtual void EnsureValidCodeBlock() + { + if (ImplementedByRuntime == false && CodeBuilder.IsEmpty) + { + if (ReturnType == typeof(void)) + { + CodeBuilder.AddStatement(new ReturnStatement()); + } + else + { + CodeBuilder.AddStatement(new ReturnStatement(new DefaultValueExpression(ReturnType))); + } + } + } + + public virtual void Generate() + { + if (ImplementedByRuntime) + { + return; + } + + codeBuilder.Generate(builder.GetILGenerator()); + } + + private void DefineParameters(ParameterInfo[] parameters) + { + foreach (var parameter in parameters) + { + var parameterBuilder = builder.DefineParameter(parameter.Position + 1, parameter.Attributes, parameter.Name); + foreach (var attribute in parameter.GetNonInheritableAttributes()) + { + parameterBuilder.SetCustomAttribute(attribute.Builder); + } + + // If a parameter has a default value, that default value needs to be replicated. + // Default values as reported by `ParameterInfo.[Raw]DefaultValue` have two possible origins: + // + // 1. A `[DecimalConstant]` or `[DateTimeConstant]` custom attribute attached to the parameter. + // Attribute-based default values have already been copied above. + // (Note that another attribute type, `[DefaultParameterValue]`, only appears in source + // code. The compiler replaces it with another metadata construct:) + // + // 2. A `Constant` metadata table entry whose parent is the parameter. + // Constant-based default values need more work. We can detect this case by checking + // whether the `ParameterAttributes.HasDefault` flag is set. (NB: This is not the same + // as querying `ParameterInfo.HasDefault`, which would also return true for case (1)!) + if ((parameter.Attributes & ParameterAttributes.HasDefault) != 0) + { + try + { + CopyDefaultValueConstant(from: parameter, to: parameterBuilder); + } + catch + { + // Default value replication is a nice-to-have feature but not essential, + // so if it goes wrong for one parameter, just continue. + } + } + } + } + + private void CopyDefaultValueConstant(ParameterInfo from, ParameterBuilder to) + { + Debug.Assert(from != null); + Debug.Assert(to != null); + Debug.Assert((from.Attributes & ParameterAttributes.HasDefault) != 0); + + object defaultValue; + try + { + defaultValue = from.DefaultValue; + } + catch (FormatException) when (from.ParameterType == typeof(DateTime)) + { + // This catch clause guards against a CLR bug that makes it impossible to query + // the default value of an optional DateTime parameter. For the CoreCLR, see + // https://github.com/dotnet/corefx/issues/26164. + + // If this bug is present, it is caused by a `null` default value: + defaultValue = null; + } + catch (FormatException) when (from.ParameterType.IsEnum) + { + // This catch clause guards against a CLR bug that makes it impossible to query + // the default value of a (closed generic) enum parameter. For the CoreCLR, see + // https://github.com/dotnet/corefx/issues/29570. + + // If this bug is present, it is caused by a `null` default value: + defaultValue = null; + } + + if (defaultValue is Missing) + { + // It is likely that we are reflecting over invalid metadata if we end up here. + // At this point, `to.Attributes` will have the `HasDefault` flag set. If we do + // not call `to.SetConstant`, that flag will be reset when creating the dynamic + // type, so `to` will at least end up having valid metadata. It is quite likely + // that the `Missing.Value` will still be reproduced because the `Parameter- + // Builder`'s `ParameterAttributes.Optional` is likely set. (If it isn't set, + // we'll be causing a default value of `DBNull.Value`, but there's nothing that + // can be done about that, short of recreating a new `ParameterBuilder`.) + return; + } + + try + { + to.SetConstant(defaultValue); + } + catch (ArgumentException) + { + var parameterType = from.ParameterType; + var parameterNonNullableType = parameterType; + + if (defaultValue == null) + { + if (parameterType.IsNullableType()) + { + // This guards against a Mono bug that prohibits setting default value `null` + // for a `Nullable` parameter. See https://github.com/mono/mono/issues/8504. + // + // If this bug is present, luckily we still get `null` as the default value if + // we do nothing more (which is probably itself yet another bug, as the CLR + // would "produce" a default value of `Missing.Value` in this situation). + return; + } + else if (parameterType.IsValueType) + { + // This guards against a CLR bug that prohibits replicating `null` default + // values for non-nullable value types (which, despite the apparent type + // mismatch, is perfectly legal and something that the Roslyn compilers do). + // For the CoreCLR, see https://github.com/dotnet/corefx/issues/26184. + + // If this bug is present, the best we can do is to not set the default value. + // This will cause a default value of `Missing.Value` (if `ParameterAttributes- + // .Optional` is set) or `DBNull.Value` (otherwise, unlikely). + return; + } + } + else if (parameterType.IsNullableType()) + { + parameterNonNullableType = from.ParameterType.GetGenericArguments()[0]; + if (parameterNonNullableType.IsEnum || parameterNonNullableType.IsAssignableFrom(defaultValue.GetType())) + { + // This guards against two bugs: + // + // * On the CLR and CoreCLR, a bug that makes it impossible to use `ParameterBuilder- + // .SetConstant` on parameters of a nullable enum type. For CoreCLR, see + // https://github.com/dotnet/coreclr/issues/17893. + // + // If this bug is present, there is no way to faithfully reproduce the default + // value. This will most likely cause a default value of `Missing.Value` or + // `DBNull.Value`. (To better understand which of these, see comment above). + // + // * On Mono, a bug that performs a too-strict type check for nullable types. The + // value passed to `ParameterBuilder.SetConstant` must have a type matching that + // of the parameter precisely. See https://github.com/mono/mono/issues/8597. + // + // If this bug is present, there's no way to reproduce the default value because + // we cannot actually create a value of type `Nullable<>`. + return; + } + } + + // Finally, we might have got here because the metadata constant simply doesn't match + // the parameter type exactly. Some code generators other than the .NET compilers + // might produce such metadata. Make a final attempt to coerce it to the required type: + try + { + var coercedDefaultValue = Convert.ChangeType(defaultValue, parameterNonNullableType, CultureInfo.InvariantCulture); + to.SetConstant(coercedDefaultValue); + + return; + } + catch + { + // We don't care about the error thrown by an unsuccessful type coercion. + } + + throw; + } + } + + private void SetReturnType(Type returnType) + { + builder.SetReturnType(returnType); + } + + private void SetSignature(Type returnType, ParameterInfo returnParameter, Type[] parameters, + ParameterInfo[] baseMethodParameters) + { + Type[] returnRequiredCustomModifiers; + Type[] returnOptionalCustomModifiers; + Type[][] parametersRequiredCustomModifiers; + Type[][] parametersOptionalCustomModifiers; + + returnRequiredCustomModifiers = returnParameter.GetRequiredCustomModifiers(); + Array.Reverse(returnRequiredCustomModifiers); + + returnOptionalCustomModifiers = returnParameter.GetOptionalCustomModifiers(); + Array.Reverse(returnOptionalCustomModifiers); + + int parameterCount = baseMethodParameters.Length; + parametersRequiredCustomModifiers = new Type[parameterCount][]; + parametersOptionalCustomModifiers = new Type[parameterCount][]; + for (int i = 0; i < parameterCount; ++i) + { + parametersRequiredCustomModifiers[i] = baseMethodParameters[i].GetRequiredCustomModifiers(); + Array.Reverse(parametersRequiredCustomModifiers[i]); + + parametersOptionalCustomModifiers[i] = baseMethodParameters[i].GetOptionalCustomModifiers(); + Array.Reverse(parametersOptionalCustomModifiers[i]); + } + + builder.SetSignature( + returnType, + returnRequiredCustomModifiers, + returnOptionalCustomModifiers, + parameters, + parametersRequiredCustomModifiers, + parametersOptionalCustomModifiers); + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/NestedClassEmitter.cs b/Castle.Core/DynamicProxy/Generators/Emitters/NestedClassEmitter.cs new file mode 100644 index 0000000..53809e4 --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/Emitters/NestedClassEmitter.cs @@ -0,0 +1,52 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators.Emitters +{ + using System; + using System.Reflection; + using System.Reflection.Emit; + + internal class NestedClassEmitter : AbstractTypeEmitter + { + public NestedClassEmitter(AbstractTypeEmitter maintype, string name, Type baseType, Type[] interfaces) + : this( + maintype, + CreateTypeBuilder(maintype, name, TypeAttributes.Sealed | TypeAttributes.NestedPublic | TypeAttributes.Class, + baseType, interfaces)) + { + } + + public NestedClassEmitter(AbstractTypeEmitter maintype, string name, TypeAttributes attributes, Type baseType, + Type[] interfaces) + : this(maintype, CreateTypeBuilder(maintype, name, attributes, baseType, interfaces)) + { + } + + public NestedClassEmitter(AbstractTypeEmitter maintype, TypeBuilder typeBuilder) + : base(typeBuilder) + { + maintype.AddNestedClass(this); + } + + private static TypeBuilder CreateTypeBuilder(AbstractTypeEmitter maintype, string name, TypeAttributes attributes, + Type baseType, Type[] interfaces) + { + return maintype.TypeBuilder.DefineNestedType( + name, + attributes, + baseType, interfaces); + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/OpCodeUtil.cs b/Castle.Core/DynamicProxy/Generators/Emitters/OpCodeUtil.cs new file mode 100644 index 0000000..4b1ac75 --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/Emitters/OpCodeUtil.cs @@ -0,0 +1,178 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators.Emitters +{ + using System; + using System.Reflection; + using System.Reflection.Emit; + + internal abstract class OpCodeUtil + { + /// + /// Emits a load indirect opcode of the appropriate type for a value or object reference. + /// Pops a pointer off the evaluation stack, dereferences it and loads + /// a value of the specified type. + /// + public static void EmitLoadIndirectOpCodeForType(ILGenerator gen, Type type) + { + if (type.IsEnum) + { + EmitLoadIndirectOpCodeForType(gen, GetUnderlyingTypeOfEnum(type)); + return; + } + + if (type.IsByRef) + { + throw new NotSupportedException("Cannot load ByRef values"); + } + else if (type.IsPrimitive && type != typeof(IntPtr) && type != typeof(UIntPtr)) + { + var opCode = LdindOpCodesDictionary.Instance[type]; + + if (opCode == LdindOpCodesDictionary.EmptyOpCode) + { + throw new ArgumentException("Type " + type + " could not be converted to a OpCode"); + } + + gen.Emit(opCode); + } + else if (type.IsValueType) + { + gen.Emit(OpCodes.Ldobj, type); + } + else if (type.IsGenericParameter) + { + gen.Emit(OpCodes.Ldobj, type); + } + else + { + gen.Emit(OpCodes.Ldind_Ref); + } + } + + /// + /// Emits a load opcode of the appropriate kind for the constant default value of a + /// type, such as 0 for value types and null for reference types. + /// + public static void EmitLoadOpCodeForDefaultValueOfType(ILGenerator gen, Type type) + { + if (type.IsPrimitive) + { + var opCode = LdcOpCodesDictionary.Instance[type]; + switch (opCode.StackBehaviourPush) + { + case StackBehaviour.Pushi: + gen.Emit(opCode, 0); + if (Is64BitTypeLoadedAsInt32(type)) + { + // we load Int32, and have to convert it to 64bit type + gen.Emit(OpCodes.Conv_I8); + } + break; + case StackBehaviour.Pushr8: + gen.Emit(opCode, 0D); + break; + case StackBehaviour.Pushi8: + gen.Emit(opCode, 0L); + break; + case StackBehaviour.Pushr4: + gen.Emit(opCode, 0F); + break; + default: + throw new NotSupportedException(); + } + } + else + { + gen.Emit(OpCodes.Ldnull); + } + } + + /// + /// Emits a store indirectopcode of the appropriate type for a value or object reference. + /// Pops a value of the specified type and a pointer off the evaluation stack, and + /// stores the value. + /// + public static void EmitStoreIndirectOpCodeForType(ILGenerator gen, Type type) + { + if (type.IsEnum) + { + EmitStoreIndirectOpCodeForType(gen, GetUnderlyingTypeOfEnum(type)); + return; + } + + if (type.IsByRef) + { + throw new NotSupportedException("Cannot store ByRef values"); + } + else if (type.IsPrimitive && type != typeof(IntPtr) && type != typeof(UIntPtr)) + { + var opCode = StindOpCodesDictionary.Instance[type]; + + if (Equals(opCode, StindOpCodesDictionary.EmptyOpCode)) + { + throw new ArgumentException("Type " + type + " could not be converted to a OpCode"); + } + + gen.Emit(opCode); + } + else if (type.IsValueType) + { + gen.Emit(OpCodes.Stobj, type); + } + else if (type.IsGenericParameter) + { + gen.Emit(OpCodes.Stobj, type); + } + else + { + gen.Emit(OpCodes.Stind_Ref); + } + } + + private static Type GetUnderlyingTypeOfEnum(Type enumType) + { + var baseType = (IConvertible)Activator.CreateInstance(enumType); + var code = baseType.GetTypeCode(); + + switch (code) + { + case TypeCode.SByte: + return typeof(SByte); + case TypeCode.Byte: + return typeof(Byte); + case TypeCode.Int16: + return typeof(Int16); + case TypeCode.Int32: + return typeof(Int32); + case TypeCode.Int64: + return typeof(Int64); + case TypeCode.UInt16: + return typeof(UInt16); + case TypeCode.UInt32: + return typeof(UInt32); + case TypeCode.UInt64: + return typeof(UInt64); + default: + throw new NotSupportedException(); + } + } + + private static bool Is64BitTypeLoadedAsInt32(Type type) + { + return type == typeof(long) || type == typeof(ulong); + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/PropertyEmitter.cs b/Castle.Core/DynamicProxy/Generators/Emitters/PropertyEmitter.cs new file mode 100644 index 0000000..c2674b3 --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/Emitters/PropertyEmitter.cs @@ -0,0 +1,116 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators.Emitters +{ + using System; + using System.Reflection; + using System.Reflection.Emit; + + internal class PropertyEmitter : IMemberEmitter + { + private readonly PropertyBuilder builder; + private readonly AbstractTypeEmitter parentTypeEmitter; + private MethodEmitter getMethod; + private MethodEmitter setMethod; + + public PropertyEmitter(AbstractTypeEmitter parentTypeEmitter, string name, PropertyAttributes attributes, + Type propertyType, Type[] arguments) + { + this.parentTypeEmitter = parentTypeEmitter; + + builder = parentTypeEmitter.TypeBuilder.DefineProperty( + name, attributes, CallingConventions.HasThis, propertyType, + null, null, arguments, null, null); + } + + public MemberInfo Member + { + get { return null; } + } + + public Type ReturnType + { + get { return builder.PropertyType; } + } + + public MethodEmitter CreateGetMethod(string name, MethodAttributes attrs, MethodInfo methodToOverride, + params Type[] parameters) + { + if (getMethod != null) + { + throw new InvalidOperationException("A get method exists"); + } + + getMethod = new MethodEmitter(parentTypeEmitter, name, attrs, methodToOverride); + return getMethod; + } + + public MethodEmitter CreateGetMethod(string name, MethodAttributes attributes, MethodInfo methodToOverride) + { + return CreateGetMethod(name, attributes, methodToOverride, Type.EmptyTypes); + } + + public MethodEmitter CreateSetMethod(string name, MethodAttributes attrs, MethodInfo methodToOverride, + params Type[] parameters) + { + if (setMethod != null) + { + throw new InvalidOperationException("A set method exists"); + } + + setMethod = new MethodEmitter(parentTypeEmitter, name, attrs, methodToOverride); + return setMethod; + } + + public MethodEmitter CreateSetMethod(string name, MethodAttributes attributes, MethodInfo methodToOverride) + { + var method = CreateSetMethod(name, attributes, methodToOverride, Type.EmptyTypes); + return method; + } + + public void DefineCustomAttribute(CustomAttributeBuilder attribute) + { + builder.SetCustomAttribute(attribute); + } + + public void EnsureValidCodeBlock() + { + if (setMethod != null) + { + setMethod.EnsureValidCodeBlock(); + } + + if (getMethod != null) + { + getMethod.EnsureValidCodeBlock(); + } + } + + public void Generate() + { + if (setMethod != null) + { + setMethod.Generate(); + builder.SetSetMethod(setMethod.MethodBuilder); + } + + if (getMethod != null) + { + getMethod.Generate(); + builder.SetGetMethod(getMethod.MethodBuilder); + } + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ArgumentReference.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ArgumentReference.cs new file mode 100644 index 0000000..19be72d --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ArgumentReference.cs @@ -0,0 +1,78 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST +{ + using System; + using System.Diagnostics; + using System.Reflection.Emit; + + [DebuggerDisplay("argument {Type}")] + internal class ArgumentReference : TypeReference + { + public ArgumentReference(Type argumentType) + : base(argumentType) + { + Position = -1; + } + + public ArgumentReference(Type argumentType, int position) + : base(argumentType) + { + Position = position; + } + + internal int Position { get; set; } + + public override void LoadAddressOfReference(ILGenerator gen) + { + throw new NotSupportedException(); + } + + public override void LoadReference(ILGenerator gen) + { + if (Position == -1) + { + throw new InvalidOperationException("ArgumentReference uninitialized"); + } + switch (Position) + { + case 0: + gen.Emit(OpCodes.Ldarg_0); + break; + case 1: + gen.Emit(OpCodes.Ldarg_1); + break; + case 2: + gen.Emit(OpCodes.Ldarg_2); + break; + case 3: + gen.Emit(OpCodes.Ldarg_3); + break; + default: + gen.Emit(OpCodes.Ldarg_S, Position); + break; + } + } + + public override void StoreReference(ILGenerator gen) + { + if (Position == -1) + { + throw new InvalidOperationException("ArgumentReference uninitialized"); + } + gen.Emit(OpCodes.Starg, Position); + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/AsTypeReference.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/AsTypeReference.cs new file mode 100644 index 0000000..6f0ce6c --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/AsTypeReference.cs @@ -0,0 +1,63 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST +{ + using System; + using System.Diagnostics; + using System.Reflection.Emit; + + [DebuggerDisplay("{reference} as {type}")] + internal class AsTypeReference : Reference + { + private readonly Reference reference; + private readonly Type type; + + public AsTypeReference(Reference reference, Type type) + { + if (reference == null) + { + throw new ArgumentNullException(nameof(reference)); + } + if (type == null) + { + throw new ArgumentNullException(nameof(type)); + } + this.reference = reference; + this.type = type; + if (reference == OwnerReference) + { + OwnerReference = null; + } + } + + public override void LoadAddressOfReference(ILGenerator gen) + { + // NOTE: Or maybe throw new NotSupportedException() ? + reference.LoadAddressOfReference(gen); + } + + public override void LoadReference(ILGenerator gen) + { + reference.LoadReference(gen); + gen.Emit(OpCodes.Isinst, type); + } + + public override void StoreReference(ILGenerator gen) + { + // NOTE: Or maybe throw new NotSupportedException() ? + reference.StoreReference(gen); + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/AssignArgumentStatement.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/AssignArgumentStatement.cs new file mode 100644 index 0000000..5c4b2a7 --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/AssignArgumentStatement.cs @@ -0,0 +1,36 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST +{ + using System.Reflection.Emit; + + internal class AssignArgumentStatement : IStatement + { + private readonly ArgumentReference argument; + private readonly IExpression expression; + + public AssignArgumentStatement(ArgumentReference argument, IExpression expression) + { + this.argument = argument; + this.expression = expression; + } + + public void Emit(ILGenerator gen) + { + ArgumentsUtil.EmitLoadOwnerAndReference(argument, gen); + expression.Emit(gen); + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/AssignArrayStatement.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/AssignArrayStatement.cs new file mode 100644 index 0000000..b8ea4d5 --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/AssignArrayStatement.cs @@ -0,0 +1,43 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST +{ + using System.Reflection.Emit; + + internal class AssignArrayStatement : IStatement + { + private readonly Reference targetArray; + private readonly int targetPosition; + private readonly IExpression value; + + public AssignArrayStatement(Reference targetArray, int targetPosition, IExpression value) + { + this.targetArray = targetArray; + this.targetPosition = targetPosition; + this.value = value; + } + + public void Emit(ILGenerator il) + { + ArgumentsUtil.EmitLoadOwnerAndReference(targetArray, il); + + il.Emit(OpCodes.Ldc_I4, targetPosition); + + value.Emit(il); + + il.Emit(OpCodes.Stelem_Ref); + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/AssignStatement.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/AssignStatement.cs new file mode 100644 index 0000000..4d33b78 --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/AssignStatement.cs @@ -0,0 +1,37 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST +{ + using System.Reflection.Emit; + + internal class AssignStatement : IStatement + { + private readonly IExpression expression; + private readonly Reference target; + + public AssignStatement(Reference target, IExpression expression) + { + this.target = target; + this.expression = expression; + } + + public void Emit(ILGenerator gen) + { + ArgumentsUtil.EmitLoadOwnerAndReference(target.OwnerReference, gen); + expression.Emit(gen); + target.StoreReference(gen); + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/BlockStatement.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/BlockStatement.cs new file mode 100644 index 0000000..c3526ed --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/BlockStatement.cs @@ -0,0 +1,37 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST +{ + using System.Collections.Generic; + using System.Reflection.Emit; + + internal class BlockStatement : IStatement + { + private readonly List statements = new List(); + + public void AddStatement(IStatement statement) + { + statements.Add(statement); + } + + public void Emit(ILGenerator gen) + { + foreach (var s in statements) + { + s.Emit(gen); + } + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ByRefReference.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ByRefReference.cs new file mode 100644 index 0000000..f6fc69a --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ByRefReference.cs @@ -0,0 +1,48 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST +{ + using System; + using System.Diagnostics; + using System.Reflection.Emit; + + + [DebuggerDisplay("&{localReference}")] + internal class ByRefReference : TypeReference + { + private readonly LocalReference localReference; + + public ByRefReference(LocalReference localReference) + : base(localReference.Type) + { + this.localReference = localReference; + } + + public override void LoadAddressOfReference(ILGenerator gen) + { + localReference.LoadAddressOfReference(gen); + } + + public override void LoadReference(ILGenerator gen) + { + localReference.LoadAddressOfReference(gen); + } + + public override void StoreReference(ILGenerator gen) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ConstructorInvocationStatement.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ConstructorInvocationStatement.cs new file mode 100644 index 0000000..be9cfe6 --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ConstructorInvocationStatement.cs @@ -0,0 +1,71 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST +{ + using System; + using System.Reflection; + using System.Reflection.Emit; + + internal class ConstructorInvocationStatement : IStatement + { + private readonly IExpression[] args; + private readonly ConstructorInfo cmethod; + + public ConstructorInvocationStatement(Type baseType) + : this(GetDefaultConstructor(baseType)) + { + } + + public ConstructorInvocationStatement(ConstructorInfo method, params IExpression[] args) + { + if (method == null) + { + throw new ArgumentNullException(nameof(method)); + } + if (args == null) + { + throw new ArgumentNullException(nameof(args)); + } + + cmethod = method; + this.args = args; + } + + public void Emit(ILGenerator gen) + { + gen.Emit(OpCodes.Ldarg_0); + + foreach (var exp in args) + { + exp.Emit(gen); + } + + gen.Emit(OpCodes.Call, cmethod); + } + + private static ConstructorInfo GetDefaultConstructor(Type baseType) + { + var type = baseType; + if (type.ContainsGenericParameters) + { + type = type.GetGenericTypeDefinition(); + // need to get generic type definition, otherwise the GetConstructor method might throw NotSupportedException + } + + var flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; + return type.GetConstructor(flags, null, Type.EmptyTypes, null); + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ConvertExpression.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ConvertExpression.cs new file mode 100644 index 0000000..5e90d39 --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ConvertExpression.cs @@ -0,0 +1,116 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST +{ + using System; + using System.Reflection; + using System.Reflection.Emit; + + internal class ConvertExpression : IExpression + { + private readonly IExpression right; + private Type fromType; + private Type target; + + public ConvertExpression(Type targetType, IExpression right) + : this(targetType, typeof(object), right) + { + } + + public ConvertExpression(Type targetType, Type fromType, IExpression right) + { + target = targetType; + this.fromType = fromType; + this.right = right; + } + + public void Emit(ILGenerator gen) + { + right.Emit(gen); + + if (fromType == target) + { + return; + } + + if (fromType.IsByRef) + { + fromType = fromType.GetElementType(); + } + + if (target.IsByRef) + { + target = target.GetElementType(); + } + + if (target.IsValueType) + { + if (fromType.IsValueType) + { + throw new NotImplementedException("Cannot convert between distinct value types"); + } + else + { + // Unbox conversion + // Assumes fromType is a boxed value + // if we can, we emit a box and ldind, otherwise, we will use unbox.any + if (LdindOpCodesDictionary.Instance[target] != LdindOpCodesDictionary.EmptyOpCode) + { + gen.Emit(OpCodes.Unbox, target); + OpCodeUtil.EmitLoadIndirectOpCodeForType(gen, target); + } + else + { + gen.Emit(OpCodes.Unbox_Any, target); + } + } + } + else + { + if (fromType.IsValueType) + { + // Box conversion + gen.Emit(OpCodes.Box, fromType); + EmitCastIfNeeded(typeof(object), target, gen); + } + else + { + // Possible down-cast + EmitCastIfNeeded(fromType, target, gen); + } + } + } + + private static void EmitCastIfNeeded(Type from, Type target, ILGenerator gen) + { + if (target.IsGenericParameter) + { + gen.Emit(OpCodes.Unbox_Any, target); + } + else if (from.IsGenericParameter) + { + gen.Emit(OpCodes.Box, from); + } + else if (target.IsGenericType && target != from) + { + gen.Emit(OpCodes.Castclass, target); + } + else if (target.IsSubclassOf(from)) + { + gen.Emit(OpCodes.Castclass, target); + } + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/DefaultValueExpression.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/DefaultValueExpression.cs new file mode 100644 index 0000000..c4668cf --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/DefaultValueExpression.cs @@ -0,0 +1,84 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST +{ + using System; + using System.Reflection; + using System.Reflection.Emit; + + internal class DefaultValueExpression : IExpression + { + private readonly Type type; + + public DefaultValueExpression(Type type) + { + this.type = type; + } + + public void Emit(ILGenerator gen) + { + // TODO: check if this can be simplified by using more of OpCodeUtil and other existing types + if (IsPrimitiveOrClass(type)) + { + OpCodeUtil.EmitLoadOpCodeForDefaultValueOfType(gen, type); + } + else if (type.IsValueType || type.IsGenericParameter) + { + // TODO: handle decimal explicitly + var local = gen.DeclareLocal(type); + gen.Emit(OpCodes.Ldloca_S, local); + gen.Emit(OpCodes.Initobj, type); + gen.Emit(OpCodes.Ldloc, local); + } + else if (type.IsByRef) + { + EmitByRef(gen); + } + else + { + throw new NotImplementedException("Can't emit default value for type " + type); + } + } + + private void EmitByRef(ILGenerator gen) + { + var elementType = type.GetElementType(); + if (IsPrimitiveOrClass(elementType)) + { + OpCodeUtil.EmitLoadOpCodeForDefaultValueOfType(gen, elementType); + OpCodeUtil.EmitStoreIndirectOpCodeForType(gen, elementType); + } + else if (elementType.IsGenericParameter || elementType.IsValueType) + { + gen.Emit(OpCodes.Initobj, elementType); + } + else + { + throw new NotImplementedException("Can't emit default value for reference of type " + elementType); + } + } + + private bool IsPrimitiveOrClass(Type type) + { + if (type.IsPrimitive && type != typeof(IntPtr) && type != typeof(UIntPtr)) + { + return true; + } + return ((type.IsClass || type.IsInterface) && + type.IsGenericParameter == false && + type.IsByRef == false); + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/EndExceptionBlockStatement.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/EndExceptionBlockStatement.cs new file mode 100644 index 0000000..f8b9339 --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/EndExceptionBlockStatement.cs @@ -0,0 +1,26 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST +{ + using System.Reflection.Emit; + + internal class EndExceptionBlockStatement : IStatement + { + public void Emit(ILGenerator gen) + { + gen.EndExceptionBlock(); + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/FieldReference.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/FieldReference.cs new file mode 100644 index 0000000..bdc39e6 --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/FieldReference.cs @@ -0,0 +1,95 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST +{ + using System.Diagnostics; + using System.Reflection; + using System.Reflection.Emit; + + [DebuggerDisplay("{fieldbuilder.Name} ({fieldbuilder.FieldType})")] + internal class FieldReference : Reference + { + private readonly FieldInfo field; + private readonly FieldBuilder fieldbuilder; + private readonly bool isStatic; + + public FieldReference(FieldInfo field) + { + this.field = field; + if ((field.Attributes & FieldAttributes.Static) != 0) + { + isStatic = true; + owner = null; + } + } + + public FieldReference(FieldBuilder fieldbuilder) + { + this.fieldbuilder = fieldbuilder; + field = fieldbuilder; + if ((fieldbuilder.Attributes & FieldAttributes.Static) != 0) + { + isStatic = true; + owner = null; + } + } + + public FieldBuilder Fieldbuilder + { + get { return fieldbuilder; } + } + + public FieldInfo Reference + { + get { return field; } + } + + public override void LoadAddressOfReference(ILGenerator gen) + { + if (isStatic) + { + gen.Emit(OpCodes.Ldsflda, Reference); + } + else + { + gen.Emit(OpCodes.Ldflda, Reference); + } + } + + public override void LoadReference(ILGenerator gen) + { + if (isStatic) + { + gen.Emit(OpCodes.Ldsfld, Reference); + } + else + { + gen.Emit(OpCodes.Ldfld, Reference); + } + } + + public override void StoreReference(ILGenerator gen) + { + if (isStatic) + { + gen.Emit(OpCodes.Stsfld, Reference); + } + else + { + gen.Emit(OpCodes.Stfld, Reference); + } + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/FinallyStatement.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/FinallyStatement.cs new file mode 100644 index 0000000..ff2ba63 --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/FinallyStatement.cs @@ -0,0 +1,26 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST +{ + using System.Reflection.Emit; + + internal class FinallyStatement : IStatement + { + public void Emit(ILGenerator gen) + { + gen.BeginFinallyBlock(); + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/IExpression.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/IExpression.cs new file mode 100644 index 0000000..8c06a69 --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/IExpression.cs @@ -0,0 +1,20 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST +{ + internal interface IExpression : IExpressionOrStatement + { + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/IExpressionOrStatement.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/IExpressionOrStatement.cs new file mode 100644 index 0000000..fb58101 --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/IExpressionOrStatement.cs @@ -0,0 +1,23 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST +{ + using System.Reflection.Emit; + + internal interface IExpressionOrStatement + { + void Emit(ILGenerator gen); + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/IStatement.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/IStatement.cs new file mode 100644 index 0000000..78d3bbd --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/IStatement.cs @@ -0,0 +1,20 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST +{ + internal interface IStatement : IExpressionOrStatement + { + } +} diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/IfNullExpression.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/IfNullExpression.cs new file mode 100644 index 0000000..333a732 --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/IfNullExpression.cs @@ -0,0 +1,62 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST +{ + using System; + using System.Reflection.Emit; + + internal class IfNullExpression : IExpression, IStatement + { + private readonly IExpressionOrStatement ifNotNull; + private readonly IExpressionOrStatement ifNull; + private readonly Reference reference; + private readonly IExpression expression; + + public IfNullExpression(Reference reference, IExpressionOrStatement ifNull, IExpressionOrStatement ifNotNull = null) + { + this.reference = reference ?? throw new ArgumentNullException(nameof(reference)); + this.ifNull = ifNull; + this.ifNotNull = ifNotNull; + } + + public IfNullExpression(IExpression expression, IExpressionOrStatement ifNull, IExpressionOrStatement ifNotNull = null) + { + this.expression = expression ?? throw new ArgumentNullException(nameof(expression)); + this.ifNull = ifNull; + this.ifNotNull = ifNotNull; + } + + public void Emit(ILGenerator gen) + { + if (reference != null) + { + ArgumentsUtil.EmitLoadOwnerAndReference(reference, gen); + } + else if (expression != null) + { + expression.Emit(gen); + } + + var notNull = gen.DefineLabel(); + gen.Emit(OpCodes.Brtrue_S, notNull); + ifNull.Emit(gen); + gen.MarkLabel(notNull); + if (ifNotNull != null) // yeah, I know that reads funny :) + { + ifNotNull.Emit(gen); + } + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/IndirectReference.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/IndirectReference.cs new file mode 100644 index 0000000..321d439 --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/IndirectReference.cs @@ -0,0 +1,73 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST +{ + using System; + using System.Diagnostics; + using System.Reflection; + using System.Reflection.Emit; + + /// + /// Wraps a reference that is passed + /// ByRef and provides indirect load/store support. + /// + [DebuggerDisplay("&{OwnerReference}")] + internal class IndirectReference : TypeReference + { + public IndirectReference(TypeReference byRefReference) : + base(byRefReference, byRefReference.Type.GetElementType()) + { + if (!byRefReference.Type.IsByRef) + { + throw new ArgumentException("Expected an IsByRef reference", nameof(byRefReference)); + } + } + + public override void LoadAddressOfReference(ILGenerator gen) + { + // Load of owner reference takes care of this. + } + + // TODO: Better name + + public override void LoadReference(ILGenerator gen) + { + OpCodeUtil.EmitLoadIndirectOpCodeForType(gen, Type); + } + + public override void StoreReference(ILGenerator gen) + { + OpCodeUtil.EmitStoreIndirectOpCodeForType(gen, Type); + } + + public static TypeReference WrapIfByRef(TypeReference reference) + { + return reference.Type.IsByRef ? new IndirectReference(reference) : reference; + } + + // TODO: Better name + public static TypeReference[] WrapIfByRef(TypeReference[] references) + { + var result = new TypeReference[references.Length]; + + for (var i = 0; i < references.Length; i++) + { + result[i] = WrapIfByRef(references[i]); + } + + return result; + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/LiteralBoolExpression.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/LiteralBoolExpression.cs new file mode 100644 index 0000000..2fb5050 --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/LiteralBoolExpression.cs @@ -0,0 +1,33 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST +{ + using System.Reflection.Emit; + + internal class LiteralBoolExpression : IExpression + { + private readonly bool value; + + public LiteralBoolExpression(bool value) + { + this.value = value; + } + + public void Emit(ILGenerator gen) + { + gen.Emit(value ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0); + } + } +} diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/LiteralIntExpression.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/LiteralIntExpression.cs new file mode 100644 index 0000000..3e07dd4 --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/LiteralIntExpression.cs @@ -0,0 +1,68 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST +{ + using System.Reflection.Emit; + + internal class LiteralIntExpression : IExpression + { + private readonly int value; + + public LiteralIntExpression(int value) + { + this.value = value; + } + + public void Emit(ILGenerator gen) + { + switch (value) + { + case -1: + gen.Emit(OpCodes.Ldc_I4_M1); + break; + case 0: + gen.Emit(OpCodes.Ldc_I4_0); + break; + case 1: + gen.Emit(OpCodes.Ldc_I4_1); + break; + case 2: + gen.Emit(OpCodes.Ldc_I4_2); + break; + case 3: + gen.Emit(OpCodes.Ldc_I4_3); + break; + case 4: + gen.Emit(OpCodes.Ldc_I4_4); + break; + case 5: + gen.Emit(OpCodes.Ldc_I4_5); + break; + case 6: + gen.Emit(OpCodes.Ldc_I4_6); + break; + case 7: + gen.Emit(OpCodes.Ldc_I4_7); + break; + case 8: + gen.Emit(OpCodes.Ldc_I4_8); + break; + default: + gen.Emit(OpCodes.Ldc_I4, value); + break; + } + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/LiteralStringExpression.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/LiteralStringExpression.cs new file mode 100644 index 0000000..f8a842d --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/LiteralStringExpression.cs @@ -0,0 +1,33 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST +{ + using System.Reflection.Emit; + + internal class LiteralStringExpression : IExpression + { + private readonly string value; + + public LiteralStringExpression(string value) + { + this.value = value; + } + + public void Emit(ILGenerator gen) + { + gen.Emit(OpCodes.Ldstr, value); + } + } +} diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/LoadRefArrayElementExpression.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/LoadRefArrayElementExpression.cs new file mode 100644 index 0000000..311a46c --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/LoadRefArrayElementExpression.cs @@ -0,0 +1,37 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST +{ + using System.Reflection.Emit; + + internal class LoadRefArrayElementExpression : IExpression + { + private readonly Reference arrayReference; + private readonly LiteralIntExpression index; + + public LoadRefArrayElementExpression(int index, Reference arrayReference) + { + this.index = new LiteralIntExpression(index); + this.arrayReference = arrayReference; + } + + public void Emit(ILGenerator gen) + { + ArgumentsUtil.EmitLoadOwnerAndReference(arrayReference, gen); + index.Emit(gen); + gen.Emit(OpCodes.Ldelem_Ref); + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/LocalReference.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/LocalReference.cs new file mode 100644 index 0000000..cc051a5 --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/LocalReference.cs @@ -0,0 +1,50 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST +{ + using System; + using System.Diagnostics; + using System.Reflection.Emit; + + [DebuggerDisplay("local {Type}")] + internal class LocalReference : TypeReference + { + private LocalBuilder localbuilder; + + public LocalReference(Type type) : base(type) + { + } + + public override void Generate(ILGenerator gen) + { + localbuilder = gen.DeclareLocal(base.Type); + } + + public override void LoadAddressOfReference(ILGenerator gen) + { + gen.Emit(OpCodes.Ldloca, localbuilder); + } + + public override void LoadReference(ILGenerator gen) + { + gen.Emit(OpCodes.Ldloc, localbuilder); + } + + public override void StoreReference(ILGenerator gen) + { + gen.Emit(OpCodes.Stloc, localbuilder); + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/MethodInvocationExpression.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/MethodInvocationExpression.cs new file mode 100644 index 0000000..4261758 --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/MethodInvocationExpression.cs @@ -0,0 +1,69 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST +{ + using System.Reflection; + using System.Reflection.Emit; + + internal class MethodInvocationExpression : IExpression, IStatement + { + protected readonly IExpression[] args; + protected readonly MethodInfo method; + protected readonly Reference owner; + + public MethodInvocationExpression(MethodInfo method, params IExpression[] args) : + this(SelfReference.Self, method, args) + { + } + + public MethodInvocationExpression(MethodEmitter method, params IExpression[] args) : + this(SelfReference.Self, method.MethodBuilder, args) + { + } + + public MethodInvocationExpression(Reference owner, MethodEmitter method, params IExpression[] args) : + this(owner, method.MethodBuilder, args) + { + } + + public MethodInvocationExpression(Reference owner, MethodInfo method, params IExpression[] args) + { + this.owner = owner; + this.method = method; + this.args = args; + } + + public bool VirtualCall { get; set; } + + public void Emit(ILGenerator gen) + { + ArgumentsUtil.EmitLoadOwnerAndReference(owner, gen); + + foreach (var exp in args) + { + exp.Emit(gen); + } + + if (VirtualCall) + { + gen.Emit(OpCodes.Callvirt, method); + } + else + { + gen.Emit(OpCodes.Call, method); + } + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/MethodTokenExpression.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/MethodTokenExpression.cs new file mode 100644 index 0000000..cc70b09 --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/MethodTokenExpression.cs @@ -0,0 +1,43 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST +{ + using System.Diagnostics; + using System.Reflection; + using System.Reflection.Emit; + + using Castle.DynamicProxy.Tokens; + + internal class MethodTokenExpression : IExpression + { + private readonly MethodInfo method; + + public MethodTokenExpression(MethodInfo method) + { + this.method = method; + Debug.Assert(method.DeclaringType != null); // DynamicProxy isn't using global methods nor `DynamicMethod` + } + + public void Emit(ILGenerator gen) + { + gen.Emit(OpCodes.Ldtoken, method); + gen.Emit(OpCodes.Ldtoken, method.DeclaringType); + + var minfo = MethodBaseMethods.GetMethodFromHandle; + gen.Emit(OpCodes.Call, minfo); + gen.Emit(OpCodes.Castclass, typeof(MethodInfo)); + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/NewArrayExpression.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/NewArrayExpression.cs new file mode 100644 index 0000000..e6a2524 --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/NewArrayExpression.cs @@ -0,0 +1,37 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST +{ + using System; + using System.Reflection.Emit; + + internal class NewArrayExpression : IExpression + { + private readonly Type arrayType; + private readonly int size; + + public NewArrayExpression(int size, Type arrayType) + { + this.size = size; + this.arrayType = arrayType; + } + + public void Emit(ILGenerator gen) + { + gen.Emit(OpCodes.Ldc_I4, size); + gen.Emit(OpCodes.Newarr, arrayType); + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/NewInstanceExpression.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/NewInstanceExpression.cs new file mode 100644 index 0000000..d5abeff --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/NewInstanceExpression.cs @@ -0,0 +1,51 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST +{ + using System; + using System.Reflection; + using System.Reflection.Emit; + + internal class NewInstanceExpression : IExpression + { + private readonly IExpression[] arguments; + private ConstructorInfo constructor; + + public NewInstanceExpression(ConstructorInfo constructor, params IExpression[] args) + { + this.constructor = constructor ?? throw new ArgumentNullException(nameof(constructor)); + arguments = args; + } + + public NewInstanceExpression(Type target) + { + constructor = target.GetConstructor(Type.EmptyTypes) ?? throw new MissingMethodException("Could not find default constructor."); + arguments = null; + } + + public void Emit(ILGenerator gen) + { + if (arguments != null) + { + foreach (var exp in arguments) + { + exp.Emit(gen); + } + } + + gen.Emit(OpCodes.Newobj, constructor); + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/NullCoalescingOperatorExpression.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/NullCoalescingOperatorExpression.cs new file mode 100644 index 0000000..7c492a6 --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/NullCoalescingOperatorExpression.cs @@ -0,0 +1,52 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST +{ + using System; + using System.Reflection.Emit; + + internal class NullCoalescingOperatorExpression : IExpression + { + private readonly IExpression @default; + private readonly IExpression expression; + + public NullCoalescingOperatorExpression(IExpression expression, IExpression @default) + { + if (expression == null) + { + throw new ArgumentNullException(nameof(expression)); + } + + if (@default == null) + { + throw new ArgumentNullException(nameof(@default)); + } + + this.expression = expression; + this.@default = @default; + } + + public void Emit(ILGenerator gen) + { + expression.Emit(gen); + gen.Emit(OpCodes.Dup); + var label = gen.DefineLabel(); + gen.Emit(OpCodes.Brtrue_S, label); + gen.Emit(OpCodes.Pop); + @default.Emit(gen); + gen.MarkLabel(label); + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/NullExpression.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/NullExpression.cs new file mode 100644 index 0000000..cdf0495 --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/NullExpression.cs @@ -0,0 +1,32 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST +{ + using System.Reflection.Emit; + + internal class NullExpression : IExpression + { + public static readonly NullExpression Instance = new NullExpression(); + + protected NullExpression() + { + } + + public void Emit(ILGenerator gen) + { + gen.Emit(OpCodes.Ldnull); + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/Reference.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/Reference.cs new file mode 100644 index 0000000..6064317 --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/Reference.cs @@ -0,0 +1,53 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST +{ + using System.Reflection.Emit; + + internal abstract class Reference : IExpression + { + protected Reference owner = SelfReference.Self; + + protected Reference() + { + } + + protected Reference(Reference owner) + { + this.owner = owner; + } + + public Reference OwnerReference + { + get { return owner; } + set { owner = value; } + } + + public abstract void LoadAddressOfReference(ILGenerator gen); + + public abstract void LoadReference(ILGenerator gen); + + public abstract void StoreReference(ILGenerator gen); + + public virtual void Generate(ILGenerator gen) + { + } + + public void Emit(ILGenerator gen) + { + ArgumentsUtil.EmitLoadOwnerAndReference(this, gen); + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ReferencesToObjectArrayExpression.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ReferencesToObjectArrayExpression.cs new file mode 100644 index 0000000..dea87ef --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ReferencesToObjectArrayExpression.cs @@ -0,0 +1,67 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST +{ + using System; + using System.Reflection; + using System.Reflection.Emit; + + internal class ReferencesToObjectArrayExpression : IExpression + { + private readonly TypeReference[] args; + + public ReferencesToObjectArrayExpression(params TypeReference[] args) + { + this.args = args; + } + + public void Emit(ILGenerator gen) + { + var local = gen.DeclareLocal(typeof(object[])); + + gen.Emit(OpCodes.Ldc_I4, args.Length); + gen.Emit(OpCodes.Newarr, typeof(object)); + gen.Emit(OpCodes.Stloc, local); + + for (var i = 0; i < args.Length; i++) + { + gen.Emit(OpCodes.Ldloc, local); + gen.Emit(OpCodes.Ldc_I4, i); + + var reference = args[i]; + + ArgumentsUtil.EmitLoadOwnerAndReference(reference, gen); + + if (reference.Type.IsByRef) + { + throw new NotSupportedException(); + } + + if (reference.Type.IsValueType) + { + gen.Emit(OpCodes.Box, reference.Type); + } + else if (reference.Type.IsGenericParameter) + { + gen.Emit(OpCodes.Box, reference.Type); + } + + gen.Emit(OpCodes.Stelem_Ref); + } + + gen.Emit(OpCodes.Ldloc, local); + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ReturnStatement.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ReturnStatement.cs new file mode 100644 index 0000000..35bd01d --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ReturnStatement.cs @@ -0,0 +1,52 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST +{ + using System.Reflection.Emit; + + internal class ReturnStatement : IStatement + { + private readonly IExpression expression; + private readonly Reference reference; + + public ReturnStatement() + { + } + + public ReturnStatement(Reference reference) + { + this.reference = reference; + } + + public ReturnStatement(IExpression expression) + { + this.expression = expression; + } + + public void Emit(ILGenerator gen) + { + if (reference != null) + { + ArgumentsUtil.EmitLoadOwnerAndReference(reference, gen); + } + else if (expression != null) + { + expression.Emit(gen); + } + + gen.Emit(OpCodes.Ret); + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/SelfReference.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/SelfReference.cs new file mode 100644 index 0000000..085d964 --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/SelfReference.cs @@ -0,0 +1,45 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST +{ + using System; + using System.Diagnostics; + using System.Reflection.Emit; + + [DebuggerDisplay("this")] + internal class SelfReference : Reference + { + public static readonly SelfReference Self = new SelfReference(); + + protected SelfReference() : base(null) + { + } + + public override void LoadAddressOfReference(ILGenerator gen) + { + throw new NotSupportedException(); + } + + public override void LoadReference(ILGenerator gen) + { + gen.Emit(OpCodes.Ldarg_0); + } + + public override void StoreReference(ILGenerator gen) + { + gen.Emit(OpCodes.Ldarg_0); + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ThrowStatement.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ThrowStatement.cs new file mode 100644 index 0000000..f34a3c5 --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ThrowStatement.cs @@ -0,0 +1,44 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST +{ + using System; + using System.Reflection; + using System.Reflection.Emit; + + internal class ThrowStatement : IStatement + { + private readonly string errorMessage; + private readonly Type exceptionType; + + public ThrowStatement(Type exceptionType, string errorMessage) + { + this.exceptionType = exceptionType; + this.errorMessage = errorMessage; + } + + public void Emit(ILGenerator gen) + { + var ci = exceptionType.GetConstructor(new[] { typeof(string) }); + var message = new LiteralStringExpression(errorMessage); + + var creationStmt = new NewInstanceExpression(ci, message); + + creationStmt.Emit(gen); + + gen.Emit(OpCodes.Throw); + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/TryStatement.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/TryStatement.cs new file mode 100644 index 0000000..69eb9bd --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/TryStatement.cs @@ -0,0 +1,26 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST +{ + using System.Reflection.Emit; + + internal class TryStatement : IStatement + { + public void Emit(ILGenerator gen) + { + gen.BeginExceptionBlock(); + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/TypeReference.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/TypeReference.cs new file mode 100644 index 0000000..fa551e6 --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/TypeReference.cs @@ -0,0 +1,37 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST +{ + using System; + + internal abstract class TypeReference : Reference + { + private readonly Type type; + + protected TypeReference(Type argumentType) : this(null, argumentType) + { + } + + protected TypeReference(Reference owner, Type type) : base(owner) + { + this.type = type; + } + + public Type Type + { + get { return type; } + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/TypeTokenExpression.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/TypeTokenExpression.cs new file mode 100644 index 0000000..2a390c2 --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/TypeTokenExpression.cs @@ -0,0 +1,37 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST +{ + using System; + using System.Reflection.Emit; + + using Castle.DynamicProxy.Tokens; + + internal class TypeTokenExpression : IExpression + { + private readonly Type type; + + public TypeTokenExpression(Type type) + { + this.type = type; + } + + public void Emit(ILGenerator gen) + { + gen.Emit(OpCodes.Ldtoken, type); + gen.Emit(OpCodes.Call, TypeMethods.GetTypeFromHandle); + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/StindOpCodesDictionary.cs b/Castle.Core/DynamicProxy/Generators/Emitters/StindOpCodesDictionary.cs new file mode 100644 index 0000000..87b1240 --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/Emitters/StindOpCodesDictionary.cs @@ -0,0 +1,70 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators.Emitters +{ + using System; + using System.Collections.Generic; + using System.Reflection.Emit; + + /// + /// Provides appropriate Stind.X opcode + /// for the type of primitive value to be stored indirectly. + /// + internal sealed class StindOpCodesDictionary : Dictionary + { + private static readonly StindOpCodesDictionary dict = new StindOpCodesDictionary(); + + // has to be assigned explicitly to suppress compiler warning + private static readonly OpCode emptyOpCode = new OpCode(); + + private StindOpCodesDictionary() + { + Add(typeof(bool), OpCodes.Stind_I1); + Add(typeof(char), OpCodes.Stind_I2); + Add(typeof(SByte), OpCodes.Stind_I1); + Add(typeof(Int16), OpCodes.Stind_I2); + Add(typeof(Int32), OpCodes.Stind_I4); + Add(typeof(Int64), OpCodes.Stind_I8); + Add(typeof(float), OpCodes.Stind_R4); + Add(typeof(double), OpCodes.Stind_R8); + Add(typeof(byte), OpCodes.Stind_I1); + Add(typeof(UInt16), OpCodes.Stind_I2); + Add(typeof(UInt32), OpCodes.Stind_I4); + Add(typeof(UInt64), OpCodes.Stind_I8); + } + + public new OpCode this[Type type] + { + get + { + if (TryGetValue(type, out var opCode)) + { + return opCode; + } + return EmptyOpCode; + } + } + + public static OpCode EmptyOpCode + { + get { return emptyOpCode; } + } + + public static StindOpCodesDictionary Instance + { + get { return dict; } + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/StrongNameUtil.cs b/Castle.Core/DynamicProxy/Generators/Emitters/StrongNameUtil.cs new file mode 100644 index 0000000..43cec00 --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/Emitters/StrongNameUtil.cs @@ -0,0 +1,61 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators.Emitters +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Reflection; + + internal static class StrongNameUtil + { + private static readonly IDictionary signedAssemblyCache = new Dictionary(); + private static readonly object lockObject = new object(); + + public static bool IsAssemblySigned(this Assembly assembly) + { + lock (lockObject) + { + if (signedAssemblyCache.TryGetValue(assembly, out var isSigned) == false) + { + isSigned = assembly.ContainsPublicKey(); + signedAssemblyCache.Add(assembly, isSigned); + } + return isSigned; + } + } + + private static bool ContainsPublicKey(this Assembly assembly) + { + // Pulled from a comment on http://www.flawlesscode.com/post/2008/08/Mocking-and-IOC-in-Silverlight-2-Castle-Project-and-Moq-ports.aspx + return assembly.FullName != null && !assembly.FullName.Contains("PublicKeyToken=null"); + } + + public static bool IsAnyTypeFromUnsignedAssembly(IEnumerable types) + { + return types.Any(t => t.Assembly.IsAssemblySigned() == false); + } + + public static bool IsAnyTypeFromUnsignedAssembly(Type baseType, IEnumerable interfaces) + { + if (baseType != null && baseType.Assembly.IsAssemblySigned() == false) + { + return true; + } + + return IsAnyTypeFromUnsignedAssembly(interfaces); + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/TypeConstructorEmitter.cs b/Castle.Core/DynamicProxy/Generators/Emitters/TypeConstructorEmitter.cs new file mode 100644 index 0000000..ce0b9a0 --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/Emitters/TypeConstructorEmitter.cs @@ -0,0 +1,34 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators.Emitters +{ + using Castle.DynamicProxy.Generators.Emitters.SimpleAST; + + internal class TypeConstructorEmitter : ConstructorEmitter + { + internal TypeConstructorEmitter(AbstractTypeEmitter maintype) + : base(maintype, maintype.TypeBuilder.DefineTypeInitializer()) + { + } + + public override void EnsureValidCodeBlock() + { + if (CodeBuilder.IsEmpty) + { + CodeBuilder.AddStatement(new ReturnStatement()); + } + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/ForwardingMethodGenerator.cs b/Castle.Core/DynamicProxy/Generators/ForwardingMethodGenerator.cs new file mode 100644 index 0000000..6b7364f --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/ForwardingMethodGenerator.cs @@ -0,0 +1,46 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators +{ + using Castle.DynamicProxy.Contributors; + using Castle.DynamicProxy.Generators.Emitters; + using Castle.DynamicProxy.Generators.Emitters.SimpleAST; + + internal class ForwardingMethodGenerator : MethodGenerator + { + private readonly GetTargetReferenceDelegate getTargetReference; + + public ForwardingMethodGenerator(MetaMethod method, OverrideMethodDelegate overrideMethod, + GetTargetReferenceDelegate getTargetReference) + : base(method, overrideMethod) + { + this.getTargetReference = getTargetReference; + } + + protected override MethodEmitter BuildProxiedMethodBody(MethodEmitter emitter, ClassEmitter @class, + INamingScope namingScope) + { + var targetReference = getTargetReference(@class, MethodToOverride); + var arguments = ArgumentsUtil.ConvertToArgumentReferenceExpression(MethodToOverride.GetParameters()); + + emitter.CodeBuilder.AddStatement(new ReturnStatement( + new MethodInvocationExpression( + targetReference, + MethodToOverride, + arguments) { VirtualCall = true })); + return emitter; + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/GeneratorUtil.cs b/Castle.Core/DynamicProxy/Generators/GeneratorUtil.cs new file mode 100644 index 0000000..eb9ff84 --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/GeneratorUtil.cs @@ -0,0 +1,131 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators +{ + using System.Linq; + using System.Reflection; + using System.Runtime.InteropServices; + + using Castle.DynamicProxy.Generators.Emitters; + using Castle.DynamicProxy.Generators.Emitters.SimpleAST; + using Castle.DynamicProxy.Tokens; + + internal static class GeneratorUtil + { + public static void CopyOutAndRefParameters(TypeReference[] dereferencedArguments, LocalReference invocation, + MethodInfo method, MethodEmitter emitter) + { + var parameters = method.GetParameters(); + + // Create it only if there are byref writable arguments. + LocalReference arguments = null; + + for (var i = 0; i < parameters.Length; i++) + { + if (IsByRef(parameters[i]) && !IsReadOnly(parameters[i])) + { + if (arguments == null) + { + arguments = StoreInvocationArgumentsInLocal(emitter, invocation); + } + + emitter.CodeBuilder.AddStatement(AssignArgument(dereferencedArguments, i, arguments)); + } + } + + bool IsByRef(ParameterInfo parameter) + { + return parameter.ParameterType.IsByRef; + } + + bool IsReadOnly(ParameterInfo parameter) + { + // C# `in` parameters are also by-ref, but meant to be read-only. + // The section "Metadata representation of in parameters" on the following page + // defines how such parameters are marked: + // + // https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.2/readonly-ref.md + // + // This poses three problems for detecting them: + // + // * The C# Roslyn compiler marks `in` parameters with an `[in]` IL modifier, + // but this isn't specified, nor is it used uniquely for `in` params. + // + // * `System.Runtime.CompilerServices.IsReadOnlyAttribute` is not defined on all + // .NET platforms, so the compiler sometimes recreates that type in the same + // assembly that contains the method having an `in` parameter. In other words, + // it's an attribute one must check for by name (which is slow, as it implies + // use of a `GetCustomAttributes` enumeration instead of a faster `IsDefined`). + // + // * A required custom modifier `System.Runtime.InteropServices.InAttribute` + // is always present in those cases relevant for DynamicProxy (proxyable methods), + // but not all targeted platforms support reading custom modifiers. Also, + // support for cmods is generally flaky (at this time of writing, mid-2018). + // + // The above points inform the following detection logic: First, we rely on an IL + // `[in]` modifier being present. This is a "fast guard" against non-`in` parameters: + if ((parameter.Attributes & (ParameterAttributes.In | ParameterAttributes.Out)) != ParameterAttributes.In) + { + return false; + } + + // This check allows to make the detection logic more robust on the platforms which support custom modifiers. + // The robustness is achieved by the fact, that usually the `IsReadOnlyAttribute` emitted by the compiler is internal to the assembly. + // Therefore, if clients use Reflection.Emit to create "a copy" of the methods with read-only members, they cannot re-use the existing attribute. + // Instead, they are forced to emit their own `IsReadOnlyAttribute` to mark some argument as immutable. + // The `InAttribute` type OTOH was always available in BCL. Therefore, it's much easier to copy the modreq and be recognized by Castle. + // + // If check fails, resort to the IsReadOnlyAttribute check. + // Check for the required modifiers first, as it's faster. + if (parameter.GetRequiredCustomModifiers().Any(x => x == typeof(InAttribute))) + { + return true; + } + + // The comparison by name is intentional; any assembly could define that attribute. + // See explanation in comment above. + if (parameter.GetCustomAttributes(false).Any(x => x.GetType().FullName == "System.Runtime.CompilerServices.IsReadOnlyAttribute")) + { + return true; + } + + return false; + } + } + + private static ConvertExpression Argument(int i, LocalReference invocationArgs, TypeReference[] arguments) + { + return new ConvertExpression(arguments[i].Type, new LoadRefArrayElementExpression(i, invocationArgs)); + } + + private static AssignStatement AssignArgument(TypeReference[] dereferencedArguments, int i, + LocalReference invocationArgs) + { + return new AssignStatement(dereferencedArguments[i], Argument(i, invocationArgs, dereferencedArguments)); + } + + private static AssignStatement GetArguments(LocalReference invocationArgs, LocalReference invocation) + { + return new AssignStatement(invocationArgs, new MethodInvocationExpression(invocation, InvocationMethods.GetArguments)); + } + + private static LocalReference StoreInvocationArgumentsInLocal(MethodEmitter emitter, LocalReference invocation) + { + var invocationArgs = emitter.CodeBuilder.DeclareLocal(typeof(object[])); + emitter.CodeBuilder.AddStatement(GetArguments(invocationArgs, invocation)); + return invocationArgs; + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/IGenerator.cs b/Castle.Core/DynamicProxy/Generators/IGenerator.cs new file mode 100644 index 0000000..619f8af --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/IGenerator.cs @@ -0,0 +1,23 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators +{ + using Castle.DynamicProxy.Generators.Emitters; + + internal interface IGenerator + { + T Generate(ClassEmitter @class, INamingScope namingScope); + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/INamingScope.cs b/Castle.Core/DynamicProxy/Generators/INamingScope.cs new file mode 100644 index 0000000..57cd4c0 --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/INamingScope.cs @@ -0,0 +1,45 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators +{ + /// + /// Represents the scope of uniqueness of names for types and their members + /// + internal interface INamingScope + { + INamingScope ParentScope { get; } + + /// + /// Gets a unique name based on + /// + /// Name suggested by the caller + /// Unique name based on . + /// + /// Implementers should provide name as closely resembling as possible. + /// Generally if no collision occurs it is suggested to return suggested name, otherwise append sequential suffix. + /// Implementers must return deterministic names, that is when is called twice + /// with the same suggested name, the same returned name should be provided each time. Non-deterministic return + /// values, like appending random suffices will break serialization of proxies. + /// + string GetUniqueName(string suggestedName); + + /// + /// Returns new, disposable naming scope. It is responsibility of the caller to make sure that no naming collision + /// with enclosing scope, or other subscopes is possible. + /// + /// New naming scope. + INamingScope SafeSubScope(); + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/InheritanceInvocationTypeGenerator.cs b/Castle.Core/DynamicProxy/Generators/InheritanceInvocationTypeGenerator.cs new file mode 100644 index 0000000..b02d587 --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/InheritanceInvocationTypeGenerator.cs @@ -0,0 +1,59 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators +{ + using System; + using System.Reflection; + + using Castle.DynamicProxy.Contributors; + using Castle.DynamicProxy.Generators.Emitters.SimpleAST; + using Castle.DynamicProxy.Internal; + using Castle.DynamicProxy.Tokens; + + internal class InheritanceInvocationTypeGenerator : InvocationTypeGenerator + { + public static readonly Type BaseType = typeof(InheritanceInvocation); + + public InheritanceInvocationTypeGenerator(Type targetType, MetaMethod method, MethodInfo callback, + IInvocationCreationContributor contributor) + : base(targetType, method, callback, false, contributor) + { + } + + protected override ArgumentReference[] GetBaseCtorArguments(Type targetFieldType, + out ConstructorInfo baseConstructor) + { + baseConstructor = InvocationMethods.InheritanceInvocationConstructor; + return new[] + { + new ArgumentReference(typeof(Type)), + new ArgumentReference(typeof(object)), + new ArgumentReference(typeof(IInterceptor[])), + new ArgumentReference(typeof(MethodInfo)), + new ArgumentReference(typeof(object[])) + }; + } + + protected override Type GetBaseType() + { + return BaseType; + } + + protected override FieldReference GetTargetReference() + { + return new FieldReference(InvocationMethods.ProxyObject); + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/InterfaceProxyWithTargetGenerator.cs b/Castle.Core/DynamicProxy/Generators/InterfaceProxyWithTargetGenerator.cs new file mode 100644 index 0000000..dc4ac91 --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/InterfaceProxyWithTargetGenerator.cs @@ -0,0 +1,68 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators +{ + using System; + using System.Collections.Generic; + using System.Linq; + + using Castle.DynamicProxy.Contributors; + using Castle.DynamicProxy.Serialization; + + internal sealed class InterfaceProxyWithTargetGenerator : BaseInterfaceProxyGenerator + { + public InterfaceProxyWithTargetGenerator(ModuleScope scope, Type targetType, Type[] interfaces, + Type proxyTargetType, ProxyGenerationOptions options) + : base(scope, targetType, interfaces, proxyTargetType, options) + { } + + protected override bool AllowChangeTarget => false; + + protected override string GeneratorType => ProxyTypeConstants.InterfaceWithTarget; + + protected override CompositeTypeContributor GetProxyTargetContributor(Type proxyTargetType, INamingScope namingScope) + { + return new InterfaceProxyTargetContributor(proxyTargetType, AllowChangeTarget, namingScope) { Logger = Logger }; + } + + protected override ProxyTargetAccessorContributor GetProxyTargetAccessorContributor() + { + return new ProxyTargetAccessorContributor( + getTargetReference: () => targetField, + proxyTargetType); + } + + protected override void AddMappingForAdditionalInterfaces(CompositeTypeContributor contributor, Type[] proxiedInterfaces, + IDictionary typeImplementerMapping, + ICollection targetInterfaces) + { + foreach (var @interface in interfaces) + { + if (!ImplementedByTarget(targetInterfaces, @interface) || proxiedInterfaces.Contains(@interface)) + { + continue; + } + + contributor.AddInterfaceToProxy(@interface); + AddMappingNoCheck(@interface, contributor, typeImplementerMapping); + } + } + + private bool ImplementedByTarget(ICollection targetInterfaces, Type @interface) + { + return targetInterfaces.Contains(@interface); + } + } +} diff --git a/Castle.Core/DynamicProxy/Generators/InterfaceProxyWithTargetInterfaceGenerator.cs b/Castle.Core/DynamicProxy/Generators/InterfaceProxyWithTargetInterfaceGenerator.cs new file mode 100644 index 0000000..9ae7b10 --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/InterfaceProxyWithTargetInterfaceGenerator.cs @@ -0,0 +1,74 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators +{ + using System; + using System.Collections.Generic; + using System.Reflection; + + using Castle.DynamicProxy.Contributors; + using Castle.DynamicProxy.Generators.Emitters; + using Castle.DynamicProxy.Generators.Emitters.SimpleAST; + using Castle.DynamicProxy.Internal; + using Castle.DynamicProxy.Serialization; + + internal sealed class InterfaceProxyWithTargetInterfaceGenerator : BaseInterfaceProxyGenerator + { + public InterfaceProxyWithTargetInterfaceGenerator(ModuleScope scope, Type targetType, Type[] interfaces, + Type proxyTargetType, ProxyGenerationOptions options) + : base(scope, targetType, interfaces, proxyTargetType, options) + { + } + + protected override bool AllowChangeTarget => true; + + protected override string GeneratorType => ProxyTypeConstants.InterfaceWithTargetInterface; + + protected override CompositeTypeContributor GetProxyTargetContributor(Type proxyTargetType, INamingScope namingScope) + { + return new InterfaceProxyWithTargetInterfaceTargetContributor(proxyTargetType, AllowChangeTarget, namingScope) { Logger = Logger }; + } + + protected override ProxyTargetAccessorContributor GetProxyTargetAccessorContributor() + { + return new ProxyTargetAccessorContributor( + getTargetReference: () => targetField, + proxyTargetType); + } + + protected override void AddMappingForAdditionalInterfaces(CompositeTypeContributor contributor, Type[] proxiedInterfaces, + IDictionary typeImplementerMapping, + ICollection targetInterfaces) + { + } + + protected override InterfaceProxyWithoutTargetContributor GetContributorForAdditionalInterfaces( + INamingScope namingScope) + { + return new InterfaceProxyWithOptionalTargetContributor(namingScope, GetTargetExpression, GetTarget) + { Logger = Logger }; + } + + private Reference GetTarget(ClassEmitter @class, MethodInfo method) + { + return new AsTypeReference(@class.GetField("__target"), method.DeclaringType); + } + + private IExpression GetTargetExpression(ClassEmitter @class, MethodInfo method) + { + return GetTarget(@class, method); + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/InterfaceProxyWithoutTargetGenerator.cs b/Castle.Core/DynamicProxy/Generators/InterfaceProxyWithoutTargetGenerator.cs new file mode 100644 index 0000000..d916e4d --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/InterfaceProxyWithoutTargetGenerator.cs @@ -0,0 +1,59 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators +{ + using System; + using System.Collections.Generic; + + using Castle.DynamicProxy.Contributors; + using Castle.DynamicProxy.Generators.Emitters.SimpleAST; + using Castle.DynamicProxy.Serialization; + + internal sealed class InterfaceProxyWithoutTargetGenerator : BaseInterfaceProxyGenerator + { + public InterfaceProxyWithoutTargetGenerator(ModuleScope scope, Type targetType, Type[] interfaces, + Type proxyTargetType, ProxyGenerationOptions options) + : base(scope, targetType, interfaces, proxyTargetType, options) + { + } + + protected override bool AllowChangeTarget => false; + + protected override string GeneratorType => ProxyTypeConstants.InterfaceWithoutTarget; + + protected override CompositeTypeContributor GetProxyTargetContributor(Type proxyTargetType, INamingScope namingScope) + { + return new InterfaceProxyWithoutTargetContributor(namingScope, (c, m) => NullExpression.Instance) { Logger = Logger }; + } + + protected override ProxyTargetAccessorContributor GetProxyTargetAccessorContributor() + { + return new ProxyTargetAccessorContributor( + getTargetReference: () => targetField, + proxyTargetType); + } + + protected override void AddMappingForAdditionalInterfaces(CompositeTypeContributor contributor, Type[] proxiedInterfaces, + IDictionary typeImplementerMapping, + ICollection targetInterfaces) + { + } + + protected override IEnumerable GetTypeImplementerMapping(Type _, out IEnumerable contributors, INamingScope namingScope) + { + return base.GetTypeImplementerMapping(proxyTargetType: targetType, out contributors, namingScope); + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/InvocationTypeGenerator.cs b/Castle.Core/DynamicProxy/Generators/InvocationTypeGenerator.cs new file mode 100644 index 0000000..133d9d7 --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/InvocationTypeGenerator.cs @@ -0,0 +1,311 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators +{ + using System; + using System.Collections.Generic; + using System.Reflection; + + using Castle.DynamicProxy.Contributors; + using Castle.DynamicProxy.Generators.Emitters; + using Castle.DynamicProxy.Generators.Emitters.SimpleAST; + using Castle.DynamicProxy.Internal; + using Castle.DynamicProxy.Tokens; + + internal abstract class InvocationTypeGenerator : IGenerator + { + protected readonly MetaMethod method; + protected readonly Type targetType; + private readonly MethodInfo callback; + private readonly bool canChangeTarget; + private readonly IInvocationCreationContributor contributor; + + protected InvocationTypeGenerator(Type targetType, MetaMethod method, MethodInfo callback, bool canChangeTarget, + IInvocationCreationContributor contributor) + { + this.targetType = targetType; + this.method = method; + this.callback = callback; + this.canChangeTarget = canChangeTarget; + this.contributor = contributor; + } + + /// + /// Generates the constructor for the class that extends + /// + /// + protected abstract ArgumentReference[] GetBaseCtorArguments(Type targetFieldType, + out ConstructorInfo baseConstructor); + + protected abstract Type GetBaseType(); + + protected abstract FieldReference GetTargetReference(); + + public AbstractTypeEmitter Generate(ClassEmitter @class, INamingScope namingScope) + { + var methodInfo = method.Method; + + var interfaces = new Type[0]; + + if (canChangeTarget) + { + interfaces = new[] { typeof(IChangeProxyTarget) }; + } + var invocation = GetEmitter(@class, interfaces, namingScope, methodInfo); + + // invocation only needs to mirror the generic parameters of the MethodInfo + // targetType cannot be a generic type definition (YET!) + invocation.CopyGenericParametersFromMethod(methodInfo); + + CreateConstructor(invocation); + + var targetField = GetTargetReference(); + if (canChangeTarget) + { + ImplementChangeProxyTargetInterface(@class, invocation, targetField); + } + + ImplemementInvokeMethodOnTarget(invocation, methodInfo.GetParameters(), targetField, callback); + +#if FEATURE_SERIALIZATION + invocation.DefineCustomAttribute(); +#endif + + return invocation; + } + + protected virtual MethodInvocationExpression GetCallbackMethodInvocation(AbstractTypeEmitter invocation, + IExpression[] args, MethodInfo callbackMethod, + Reference targetField, + MethodEmitter invokeMethodOnTarget) + { + if (contributor != null) + { + return contributor.GetCallbackMethodInvocation(invocation, args, targetField, invokeMethodOnTarget); + } + var methodOnTargetInvocationExpression = new MethodInvocationExpression( + new AsTypeReference(targetField, callbackMethod.DeclaringType), + callbackMethod, + args) { VirtualCall = true }; + return methodOnTargetInvocationExpression; + } + + protected virtual void ImplementInvokeMethodOnTarget(AbstractTypeEmitter invocation, ParameterInfo[] parameters, + MethodEmitter invokeMethodOnTarget, + Reference targetField) + { + var callbackMethod = GetCallbackMethod(invocation); + if (callbackMethod == null) + { + EmitCallThrowOnNoTarget(invokeMethodOnTarget); + return; + } + + var args = new IExpression[parameters.Length]; + + // Idea: instead of grab parameters one by one + // we should grab an array + var byRefArguments = new Dictionary(); + + for (var i = 0; i < parameters.Length; i++) + { + var param = parameters[i]; + + var paramType = invocation.GetClosedParameterType(param.ParameterType); + if (paramType.IsByRef) + { + var localReference = invokeMethodOnTarget.CodeBuilder.DeclareLocal(paramType.GetElementType()); + invokeMethodOnTarget.CodeBuilder + .AddStatement( + new AssignStatement(localReference, + new ConvertExpression(paramType.GetElementType(), + new MethodInvocationExpression(SelfReference.Self, + InvocationMethods.GetArgumentValue, + new LiteralIntExpression(i))))); + var byRefReference = new ByRefReference(localReference); + args[i] = byRefReference; + byRefArguments[i] = localReference; + } + else + { + args[i] = + new ConvertExpression(paramType, + new MethodInvocationExpression(SelfReference.Self, + InvocationMethods.GetArgumentValue, + new LiteralIntExpression(i))); + } + } + + if (byRefArguments.Count > 0) + { + invokeMethodOnTarget.CodeBuilder.AddStatement(new TryStatement()); + } + + var methodOnTargetInvocationExpression = GetCallbackMethodInvocation(invocation, args, callbackMethod, targetField, invokeMethodOnTarget); + + LocalReference returnValue = null; + if (callbackMethod.ReturnType != typeof(void)) + { + var returnType = invocation.GetClosedParameterType(callbackMethod.ReturnType); + returnValue = invokeMethodOnTarget.CodeBuilder.DeclareLocal(returnType); + invokeMethodOnTarget.CodeBuilder.AddStatement(new AssignStatement(returnValue, methodOnTargetInvocationExpression)); + } + else + { + invokeMethodOnTarget.CodeBuilder.AddStatement(methodOnTargetInvocationExpression); + } + + AssignBackByRefArguments(invokeMethodOnTarget, byRefArguments); + + if (callbackMethod.ReturnType != typeof(void)) + { + var setRetVal = + new MethodInvocationExpression(SelfReference.Self, + InvocationMethods.SetReturnValue, + new ConvertExpression(typeof(object), returnValue.Type, returnValue)); + + invokeMethodOnTarget.CodeBuilder.AddStatement(setRetVal); + } + + invokeMethodOnTarget.CodeBuilder.AddStatement(new ReturnStatement()); + } + + private void AssignBackByRefArguments(MethodEmitter invokeMethodOnTarget, Dictionary byRefArguments) + { + if (byRefArguments.Count == 0) + { + return; + } + + invokeMethodOnTarget.CodeBuilder.AddStatement(new FinallyStatement()); + foreach (var byRefArgument in byRefArguments) + { + var index = byRefArgument.Key; + var localReference = byRefArgument.Value; + invokeMethodOnTarget.CodeBuilder.AddStatement( + new MethodInvocationExpression( + SelfReference.Self, + InvocationMethods.SetArgumentValue, + new LiteralIntExpression(index), + new ConvertExpression( + typeof(object), + localReference.Type, + localReference))); + } + invokeMethodOnTarget.CodeBuilder.AddStatement(new EndExceptionBlockStatement()); + } + + private void CreateConstructor(AbstractTypeEmitter invocation) + { + ConstructorInfo baseConstructor; + var baseCtorArguments = GetBaseCtorArguments(targetType, out baseConstructor); + + var constructor = CreateConstructor(invocation, baseCtorArguments); + constructor.CodeBuilder.AddStatement(new ConstructorInvocationStatement(baseConstructor, baseCtorArguments)); + constructor.CodeBuilder.AddStatement(new ReturnStatement()); + } + + private ConstructorEmitter CreateConstructor(AbstractTypeEmitter invocation, ArgumentReference[] baseCtorArguments) + { + if (contributor == null) + { + return invocation.CreateConstructor(baseCtorArguments); + } + return contributor.CreateConstructor(baseCtorArguments, invocation); + } + + private void EmitCallThrowOnNoTarget(MethodEmitter invokeMethodOnTarget) + { + var throwOnNoTarget = new MethodInvocationExpression(InvocationMethods.ThrowOnNoTarget); + + invokeMethodOnTarget.CodeBuilder.AddStatement(throwOnNoTarget); + invokeMethodOnTarget.CodeBuilder.AddStatement(new ReturnStatement()); + } + + private MethodInfo GetCallbackMethod(AbstractTypeEmitter invocation) + { + if (contributor != null) + { + return contributor.GetCallbackMethod(); + } + var callbackMethod = callback; + if (callbackMethod == null) + { + return null; + } + + if (!callbackMethod.IsGenericMethod) + { + return callbackMethod; + } + + return callbackMethod.MakeGenericMethod(invocation.GetGenericArgumentsFor(callbackMethod)); + } + + private AbstractTypeEmitter GetEmitter(ClassEmitter @class, Type[] interfaces, INamingScope namingScope, + MethodInfo methodInfo) + { + var suggestedName = string.Format("Castle.Proxies.Invocations.{0}_{1}", methodInfo.DeclaringType.Name, + methodInfo.Name); + var uniqueName = namingScope.ParentScope.GetUniqueName(suggestedName); + return new ClassEmitter(@class.ModuleScope, uniqueName, GetBaseType(), interfaces, ClassEmitter.DefaultAttributes, forceUnsigned: @class.InStrongNamedModule == false); + } + + private void ImplemementInvokeMethodOnTarget(AbstractTypeEmitter invocation, ParameterInfo[] parameters, + FieldReference targetField, MethodInfo callbackMethod) + { + var invokeMethodOnTarget = invocation.CreateMethod("InvokeMethodOnTarget", typeof(void)); + ImplementInvokeMethodOnTarget(invocation, parameters, invokeMethodOnTarget, targetField); + } + + private void ImplementChangeInvocationTarget(AbstractTypeEmitter invocation, FieldReference targetField) + { + var changeInvocationTarget = invocation.CreateMethod("ChangeInvocationTarget", typeof(void), new[] { typeof(object) }); + changeInvocationTarget.CodeBuilder.AddStatement( + new AssignStatement(targetField, + new ConvertExpression(targetType, changeInvocationTarget.Arguments[0]))); + changeInvocationTarget.CodeBuilder.AddStatement(new ReturnStatement()); + } + + private void ImplementChangeProxyTarget(AbstractTypeEmitter invocation, ClassEmitter @class) + { + var changeProxyTarget = invocation.CreateMethod("ChangeProxyTarget", typeof(void), new[] { typeof(object) }); + + var proxyObject = new FieldReference(InvocationMethods.ProxyObject); + var localProxy = changeProxyTarget.CodeBuilder.DeclareLocal(typeof(IProxyTargetAccessor)); + changeProxyTarget.CodeBuilder.AddStatement( + new AssignStatement(localProxy, + new ConvertExpression(localProxy.Type, proxyObject))); + + var dynSetProxy = typeof(IProxyTargetAccessor).GetMethod(nameof(IProxyTargetAccessor.DynProxySetTarget)); + + changeProxyTarget.CodeBuilder.AddStatement( + new MethodInvocationExpression(localProxy, dynSetProxy, changeProxyTarget.Arguments[0]) + { + VirtualCall = true + }); + + changeProxyTarget.CodeBuilder.AddStatement(new ReturnStatement()); + } + + private void ImplementChangeProxyTargetInterface(ClassEmitter @class, AbstractTypeEmitter invocation, + FieldReference targetField) + { + ImplementChangeInvocationTarget(invocation, targetField); + + ImplementChangeProxyTarget(invocation, @class); + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/MetaEvent.cs b/Castle.Core/DynamicProxy/Generators/MetaEvent.cs new file mode 100644 index 0000000..ea2e479 --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/MetaEvent.cs @@ -0,0 +1,151 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators +{ + using System; + using System.Reflection; + + using Castle.DynamicProxy.Generators.Emitters; + + internal class MetaEvent : MetaTypeElement, IEquatable + { + private readonly MetaMethod adder; + private readonly MetaMethod remover; + private EventEmitter emitter; + + /// + /// Initializes a new instance of the class. + /// + /// The event. + /// The add method. + /// The remove method. + /// The attributes. + public MetaEvent(EventInfo @event, MetaMethod adder, MetaMethod remover, EventAttributes attributes) + : base(@event) + { + if (adder == null) + { + throw new ArgumentNullException(nameof(adder)); + } + if (remover == null) + { + throw new ArgumentNullException(nameof(remover)); + } + this.adder = adder; + this.remover = remover; + Attributes = attributes; + } + + public MetaMethod Adder + { + get { return adder; } + } + + public EventAttributes Attributes { get; private set; } + + public EventEmitter Emitter + { + get + { + if (emitter != null) + { + return emitter; + } + + throw new InvalidOperationException( + "Emitter is not initialized. You have to initialize it first using 'BuildEventEmitter' method"); + } + } + + public MetaMethod Remover + { + get { return remover; } + } + + private Type Type + { + get { return ((EventInfo)Member).EventHandlerType; } + } + + public void BuildEventEmitter(ClassEmitter classEmitter) + { + if (emitter != null) + { + throw new InvalidOperationException(); + } + emitter = classEmitter.CreateEvent(Name, Attributes, Type); + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) + { + return false; + } + if (ReferenceEquals(this, obj)) + { + return true; + } + if (obj.GetType() != typeof(MetaEvent)) + { + return false; + } + return Equals((MetaEvent)obj); + } + + public override int GetHashCode() + { + unchecked + { + var result = (adder.Method != null ? adder.Method.GetHashCode() : 0); + result = (result*397) ^ (remover.Method != null ? remover.Method.GetHashCode() : 0); + result = (result*397) ^ Attributes.GetHashCode(); + return result; + } + } + + public bool Equals(MetaEvent other) + { + if (ReferenceEquals(null, other)) + { + return false; + } + + if (ReferenceEquals(this, other)) + { + return true; + } + + if (!Type.Equals(other.Type)) + { + return false; + } + + if (!StringComparer.OrdinalIgnoreCase.Equals(Name, other.Name)) + { + return false; + } + + return true; + } + + public override void SwitchToExplicitImplementation() + { + SwitchToExplicitImplementationName(); + adder.SwitchToExplicitImplementation(); + remover.SwitchToExplicitImplementation(); + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/MetaMethod.cs b/Castle.Core/DynamicProxy/Generators/MetaMethod.cs new file mode 100644 index 0000000..bffa8bd --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/MetaMethod.cs @@ -0,0 +1,143 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators +{ + using System; + using System.Diagnostics; + using System.Reflection; + + [DebuggerDisplay("{Method}")] + internal class MetaMethod : MetaTypeElement, IEquatable + { + private const MethodAttributes ExplicitImplementationAttributes = MethodAttributes.Virtual | + MethodAttributes.Public | + MethodAttributes.HideBySig | + MethodAttributes.NewSlot | + MethodAttributes.Final; + + public MetaMethod(MethodInfo method, MethodInfo methodOnTarget, bool standalone, bool proxyable, bool hasTarget) + : base(method) + { + Method = method; + MethodOnTarget = methodOnTarget; + Standalone = standalone; + Proxyable = proxyable; + HasTarget = hasTarget; + Attributes = ObtainAttributes(); + } + + public MethodAttributes Attributes { get; private set; } + public bool HasTarget { get; private set; } + public MethodInfo Method { get; private set; } + + public MethodInfo MethodOnTarget { get; private set; } + + public bool Ignore { get; internal set; } + + public bool Proxyable { get; private set; } + + public bool Standalone { get; private set; } + + public bool Equals(MetaMethod other) + { + if (ReferenceEquals(null, other)) + { + return false; + } + if (ReferenceEquals(this, other)) + { + return true; + } + + if (!StringComparer.OrdinalIgnoreCase.Equals(Name, other.Name)) + { + return false; + } + + var comparer = MethodSignatureComparer.Instance; + if (!comparer.EqualSignatureTypes(Method.ReturnType, other.Method.ReturnType)) + { + return false; + } + + if (!comparer.EqualGenericParameters(Method, other.Method)) + { + return false; + } + + if (!comparer.EqualParameters(Method, other.Method)) + { + return false; + } + + return true; + } + + public override void SwitchToExplicitImplementation() + { + Attributes = ExplicitImplementationAttributes; + if (Standalone == false) + { + Attributes |= MethodAttributes.SpecialName; + } + + SwitchToExplicitImplementationName(); + } + + private MethodAttributes ObtainAttributes() + { + var methodInfo = Method; + var attributes = MethodAttributes.Virtual; + + if (methodInfo.IsFinal || Method.DeclaringType.IsInterface) + { + attributes |= MethodAttributes.NewSlot; + } + + if (methodInfo.IsPublic) + { + attributes |= MethodAttributes.Public; + } + + if (methodInfo.IsHideBySig) + { + attributes |= MethodAttributes.HideBySig; + } + if (ProxyUtil.IsInternal(methodInfo) && + ProxyUtil.AreInternalsVisibleToDynamicProxy(methodInfo.DeclaringType.Assembly)) + { + attributes |= MethodAttributes.Assembly; + } + if (methodInfo.IsFamilyAndAssembly) + { + attributes |= MethodAttributes.FamANDAssem; + } + else if (methodInfo.IsFamilyOrAssembly) + { + attributes |= MethodAttributes.FamORAssem; + } + else if (methodInfo.IsFamily) + { + attributes |= MethodAttributes.Family; + } + + if (Standalone == false) + { + attributes |= MethodAttributes.SpecialName; + } + return attributes; + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/MetaProperty.cs b/Castle.Core/DynamicProxy/Generators/MetaProperty.cs new file mode 100644 index 0000000..b4a020f --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/MetaProperty.cs @@ -0,0 +1,199 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators +{ + using System; + using System.Collections.Generic; + using System.Reflection; + using System.Reflection.Emit; + + using Castle.DynamicProxy.Generators.Emitters; + + internal class MetaProperty : MetaTypeElement, IEquatable + { + private readonly Type[] arguments; + private readonly PropertyAttributes attributes; + private readonly IEnumerable customAttributes; + private readonly MetaMethod getter; + private readonly MetaMethod setter; + private PropertyEmitter emitter; + + public MetaProperty(PropertyInfo property, MetaMethod getter, MetaMethod setter, + IEnumerable customAttributes, Type[] arguments) + : base(property) + { + this.getter = getter; + this.setter = setter; + attributes = PropertyAttributes.None; + this.customAttributes = customAttributes; + this.arguments = arguments ?? Type.EmptyTypes; + } + + public Type[] Arguments + { + get { return arguments; } + } + + public bool CanRead + { + get { return getter != null; } + } + + public bool CanWrite + { + get { return setter != null; } + } + + public PropertyEmitter Emitter + { + get + { + if (emitter == null) + { + throw new InvalidOperationException( + "Emitter is not initialized. You have to initialize it first using 'BuildPropertyEmitter' method"); + } + return emitter; + } + } + + public MethodInfo GetMethod + { + get + { + if (!CanRead) + { + throw new InvalidOperationException(); + } + return getter.Method; + } + } + + public MetaMethod Getter + { + get { return getter; } + } + + public MethodInfo SetMethod + { + get + { + if (!CanWrite) + { + throw new InvalidOperationException(); + } + return setter.Method; + } + } + + public MetaMethod Setter + { + get { return setter; } + } + + private Type Type + { + get { return ((PropertyInfo)Member).PropertyType; } + } + + public void BuildPropertyEmitter(ClassEmitter classEmitter) + { + if (emitter != null) + { + throw new InvalidOperationException("Emitter is already created. It is illegal to invoke this method twice."); + } + + emitter = classEmitter.CreateProperty(Name, attributes, Type, arguments); + foreach (var attribute in customAttributes) + { + emitter.DefineCustomAttribute(attribute); + } + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) + { + return false; + } + if (ReferenceEquals(this, obj)) + { + return true; + } + if (obj.GetType() != typeof(MetaProperty)) + { + return false; + } + return Equals((MetaProperty)obj); + } + + public override int GetHashCode() + { + unchecked + { + return ((GetMethod != null ? GetMethod.GetHashCode() : 0)*397) ^ (SetMethod != null ? SetMethod.GetHashCode() : 0); + } + } + + public bool Equals(MetaProperty other) + { + if (ReferenceEquals(null, other)) + { + return false; + } + + if (ReferenceEquals(this, other)) + { + return true; + } + + if (!Type.Equals(other.Type)) + { + return false; + } + + if (!StringComparer.OrdinalIgnoreCase.Equals(Name, other.Name)) + { + return false; + } + if (Arguments.Length != other.Arguments.Length) + { + return false; + } + for (var i = 0; i < Arguments.Length; i++) + { + if (Arguments[i].Equals(other.Arguments[i]) == false) + { + return false; + } + } + + return true; + } + + public override void SwitchToExplicitImplementation() + { + SwitchToExplicitImplementationName(); + if (setter != null) + { + setter.SwitchToExplicitImplementation(); + } + if (getter != null) + { + getter.SwitchToExplicitImplementation(); + } + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/MetaType.cs b/Castle.Core/DynamicProxy/Generators/MetaType.cs new file mode 100644 index 0000000..cd8e04e --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/MetaType.cs @@ -0,0 +1,64 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators +{ + using System.Collections.Generic; + using System.Reflection; + + internal class MetaType + { + private readonly MetaTypeElementCollection events = new MetaTypeElementCollection(); + private readonly MetaTypeElementCollection methods = new MetaTypeElementCollection(); + private readonly Dictionary methodsIndex = new Dictionary(); + private readonly MetaTypeElementCollection properties = new MetaTypeElementCollection(); + + public IEnumerable Events + { + get { return events; } + } + + public IEnumerable Methods + { + get { return methods; // NOTE: should be readonly + } + } + + public IEnumerable Properties + { + get { return properties; } + } + + public void AddEvent(MetaEvent @event) + { + events.Add(@event); + } + + public void AddMethod(MetaMethod method) + { + methods.Add(method); + methodsIndex.Add(method.Method, method); // shouldn't get added twice + } + + public void AddProperty(MetaProperty property) + { + properties.Add(property); + } + + public MetaMethod FindMethod(MethodInfo method) + { + return methodsIndex.TryGetValue(method, out var metaMethod) ? metaMethod : null; + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/MetaTypeElement.cs b/Castle.Core/DynamicProxy/Generators/MetaTypeElement.cs new file mode 100644 index 0000000..12088d8 --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/MetaTypeElement.cs @@ -0,0 +1,99 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators +{ + using System; + using System.Diagnostics; + using System.Reflection; + using System.Text; + + internal abstract class MetaTypeElement + { + private readonly MemberInfo member; + private string name; + + protected MetaTypeElement(MemberInfo member) + { + this.member = member; + this.name = member.Name; + } + + public bool CanBeImplementedExplicitly + { + get { return member.DeclaringType?.IsInterface ?? false; } + } + + public string Name + { + get { return name; } + } + + protected MemberInfo Member + { + get { return member; } + } + + public abstract void SwitchToExplicitImplementation(); + + protected void SwitchToExplicitImplementationName() + { + var name = member.Name; + var sourceType = member.DeclaringType; + var ns = sourceType.Namespace; + Debug.Assert(ns == null || ns != ""); + + if (sourceType.IsGenericType) + { + var nameBuilder = new StringBuilder(); + if (ns != null) + { + nameBuilder.Append(ns); + nameBuilder.Append('.'); + } + AppendTypeName(nameBuilder, sourceType); + nameBuilder.Append('.'); + nameBuilder.Append(name); + this.name = nameBuilder.ToString(); + } + else if (ns != null) + { + this.name = string.Concat(ns, ".", sourceType.Name, ".", name); + } + else + { + this.name = string.Concat(sourceType.Name, ".", name); + } + + static void AppendTypeName(StringBuilder nameBuilder, Type type) + { + nameBuilder.Append(type.Name); + if (type.IsGenericType) + { + nameBuilder.Append('['); + var genericTypeArguments = type.GetGenericArguments(); + for (int i = 0, n = genericTypeArguments.Length; i < n; ++i) + { + if (i > 0) + { + nameBuilder.Append(','); + } + AppendTypeName(nameBuilder, genericTypeArguments[i]); + } + nameBuilder.Append(']'); + } + } + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/MetaTypeElementCollection.cs b/Castle.Core/DynamicProxy/Generators/MetaTypeElementCollection.cs new file mode 100644 index 0000000..210b2f1 --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/MetaTypeElementCollection.cs @@ -0,0 +1,68 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators +{ + using System; + using System.Collections; + using System.Collections.Generic; + + internal class MetaTypeElementCollection : IEnumerable + where TElement : MetaTypeElement, IEquatable + { + private readonly ICollection items = new List(); + + public void Add(TElement item) + { + if (item.CanBeImplementedExplicitly == false) + { + items.Add(item); + return; + } + if (Contains(item)) + { + item.SwitchToExplicitImplementation(); + if (Contains(item)) + { + // there is something *really* wrong going on here + throw new DynamicProxyException("Duplicate element: " + item); + } + } + items.Add(item); + } + + public bool Contains(TElement item) + { + foreach (var element in items) + { + if (element.Equals(item)) + { + return true; + } + } + + return false; + } + + public IEnumerator GetEnumerator() + { + return items.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/MethodFinder.cs b/Castle.Core/DynamicProxy/Generators/MethodFinder.cs new file mode 100644 index 0000000..976f2d5 --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/MethodFinder.cs @@ -0,0 +1,83 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Reflection; + + /// + /// Returns the methods implemented by a type. Use this instead of Type.GetMethods() to work around a CLR issue + /// where duplicate MethodInfos are returned by Type.GetMethods() after a token of a generic type's method was loaded. + /// + internal class MethodFinder + { + private static readonly Dictionary cachedMethodInfosByType = new Dictionary(); + private static readonly object lockObject = new object(); + + public static MethodInfo[] GetAllInstanceMethods(Type type, BindingFlags flags) + { + if ((flags & ~(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) != 0) + { + throw new ArgumentException("MethodFinder only supports the Public, NonPublic, and Instance binding flags.", nameof(flags)); + } + + MethodInfo[] methodsInCache; + + lock (lockObject) + { + if (!cachedMethodInfosByType.TryGetValue(type, out methodsInCache)) + { + // We always load all instance methods into the cache, we will filter them later + methodsInCache = type.GetMethods( + BindingFlags.Public | BindingFlags.NonPublic + | BindingFlags.Instance) + .Distinct(MethodSignatureComparer.Instance) + .ToArray(); + cachedMethodInfosByType.Add( + type, + methodsInCache); + } + } + return MakeFilteredCopy(methodsInCache, flags & (BindingFlags.Public | BindingFlags.NonPublic)); + } + + private static MethodInfo[] MakeFilteredCopy(MethodInfo[] methodsInCache, BindingFlags visibilityFlags) + { + if ((visibilityFlags & ~(BindingFlags.Public | BindingFlags.NonPublic)) != 0) + { + throw new ArgumentException("Only supports BindingFlags.Public and NonPublic.", nameof(visibilityFlags)); + } + + var includePublic = (visibilityFlags & BindingFlags.Public) == BindingFlags.Public; + var includeNonPublic = (visibilityFlags & BindingFlags.NonPublic) == BindingFlags.NonPublic; + + // Return a copy of the cached array, only returning the public methods unless requested otherwise + var result = new List(methodsInCache.Length); + + foreach (var method in methodsInCache) + { + if ((method.IsPublic && includePublic) || (!method.IsPublic && includeNonPublic)) + { + result.Add(method); + } + } + + return result.ToArray(); + } + + } +} diff --git a/Castle.Core/DynamicProxy/Generators/MethodGenerator.cs b/Castle.Core/DynamicProxy/Generators/MethodGenerator.cs new file mode 100644 index 0000000..2bf207f --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/MethodGenerator.cs @@ -0,0 +1,59 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators +{ + using System.Reflection; + + using Castle.DynamicProxy.Contributors; + using Castle.DynamicProxy.Generators.Emitters; + + internal abstract class MethodGenerator : IGenerator + { + private readonly MetaMethod method; + private readonly OverrideMethodDelegate overrideMethod; + + protected MethodGenerator(MetaMethod method, OverrideMethodDelegate overrideMethod) + { + this.method = method; + this.overrideMethod = overrideMethod; + } + + protected MethodInfo MethodOnTarget + { + get { return method.MethodOnTarget; } + } + + protected MethodInfo MethodToOverride + { + get { return method.Method; } + } + + protected abstract MethodEmitter BuildProxiedMethodBody(MethodEmitter emitter, ClassEmitter @class, + INamingScope namingScope); + + public MethodEmitter Generate(ClassEmitter @class, INamingScope namingScope) + { + var methodEmitter = overrideMethod(method.Name, method.Attributes, MethodToOverride); + var proxiedMethod = BuildProxiedMethodBody(methodEmitter, @class, namingScope); + + if (MethodToOverride.DeclaringType.IsInterface) + { + @class.TypeBuilder.DefineMethodOverride(proxiedMethod.MethodBuilder, MethodToOverride); + } + + return proxiedMethod; + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/MethodSignatureComparer.cs b/Castle.Core/DynamicProxy/Generators/MethodSignatureComparer.cs new file mode 100644 index 0000000..87be2ca --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/MethodSignatureComparer.cs @@ -0,0 +1,159 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators +{ + using System; + using System.Collections.Generic; + using System.Reflection; + + internal class MethodSignatureComparer : IEqualityComparer + { + public static readonly MethodSignatureComparer Instance = new MethodSignatureComparer(); + + public bool EqualGenericParameters(MethodInfo x, MethodInfo y) + { + if (x.IsGenericMethod != y.IsGenericMethod) + { + return false; + } + + if (x.IsGenericMethod) + { + var xArgs = x.GetGenericArguments(); + var yArgs = y.GetGenericArguments(); + + if (xArgs.Length != yArgs.Length) + { + return false; + } + + for (var i = 0; i < xArgs.Length; ++i) + { + if (xArgs[i].IsGenericParameter != yArgs[i].IsGenericParameter) + { + return false; + } + + if (!xArgs[i].IsGenericParameter && !xArgs[i].Equals(yArgs[i])) + { + return false; + } + } + } + + return true; + } + + public bool EqualParameters(MethodInfo x, MethodInfo y) + { + var xArgs = x.GetParameters(); + var yArgs = y.GetParameters(); + + if (xArgs.Length != yArgs.Length) + { + return false; + } + + for (var i = 0; i < xArgs.Length; ++i) + { + if (!EqualSignatureTypes(xArgs[i].ParameterType, yArgs[i].ParameterType)) + { + return false; + } + } + + return true; + } + + public bool EqualSignatureTypes(Type x, Type y) + { + if (x.IsGenericParameter != y.IsGenericParameter) + { + return false; + } + else if (x.IsGenericType != y.IsGenericType) + { + return false; + } + + if (x.IsGenericParameter) + { + if (x.GenericParameterPosition != y.GenericParameterPosition) + { + return false; + } + } + else if (x.IsGenericType) + { + var xGenericTypeDef = x.GetGenericTypeDefinition(); + var yGenericTypeDef = y.GetGenericTypeDefinition(); + + if (xGenericTypeDef != yGenericTypeDef) + { + return false; + } + + var xArgs = x.GetGenericArguments(); + var yArgs = y.GetGenericArguments(); + + if (xArgs.Length != yArgs.Length) + { + return false; + } + + for (var i = 0; i < xArgs.Length; ++i) + { + if(!EqualSignatureTypes(xArgs[i], yArgs[i])) return false; + } + } + else + { + if (!x.Equals(y)) + { + return false; + } + } + return true; + } + + public bool Equals(MethodInfo x, MethodInfo y) + { + if (x == null && y == null) + { + return true; + } + + if (x == null || y == null) + { + return false; + } + + return EqualNames(x, y) && + EqualGenericParameters(x, y) && + EqualSignatureTypes(x.ReturnType, y.ReturnType) && + EqualParameters(x, y); + } + + public int GetHashCode(MethodInfo obj) + { + return obj.Name.GetHashCode() ^ obj.GetParameters().Length; // everything else would be too cumbersome + } + + private bool EqualNames(MethodInfo x, MethodInfo y) + { + return x.Name == y.Name; + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/MethodWithInvocationGenerator.cs b/Castle.Core/DynamicProxy/Generators/MethodWithInvocationGenerator.cs new file mode 100644 index 0000000..6d2b5d6 --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/MethodWithInvocationGenerator.cs @@ -0,0 +1,251 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators +{ + using System; + using System.Diagnostics; + using System.Reflection; + using System.Reflection.Emit; +#if FEATURE_SERIALIZATION + using System.Xml.Serialization; +#endif + + using Castle.Core.Internal; + using Castle.DynamicProxy.Contributors; + using Castle.DynamicProxy.Generators.Emitters; + using Castle.DynamicProxy.Generators.Emitters.SimpleAST; + using Castle.DynamicProxy.Internal; + using Castle.DynamicProxy.Tokens; + + internal class MethodWithInvocationGenerator : MethodGenerator + { + private readonly IInvocationCreationContributor contributor; + private readonly GetTargetExpressionDelegate getTargetExpression; + private readonly GetTargetExpressionDelegate getTargetTypeExpression; + private readonly IExpression interceptors; + private readonly Type invocation; + + public MethodWithInvocationGenerator(MetaMethod method, IExpression interceptors, Type invocation, + GetTargetExpressionDelegate getTargetExpression, + OverrideMethodDelegate createMethod, IInvocationCreationContributor contributor) + : this(method, interceptors, invocation, getTargetExpression, null, createMethod, contributor) + { + } + + public MethodWithInvocationGenerator(MetaMethod method, IExpression interceptors, Type invocation, + GetTargetExpressionDelegate getTargetExpression, + GetTargetExpressionDelegate getTargetTypeExpression, + OverrideMethodDelegate createMethod, IInvocationCreationContributor contributor) + : base(method, createMethod) + { + this.invocation = invocation; + this.getTargetExpression = getTargetExpression; + this.getTargetTypeExpression = getTargetTypeExpression; + this.interceptors = interceptors; + this.contributor = contributor; + } + + protected FieldReference BuildMethodInterceptorsField(ClassEmitter @class, MethodInfo method, INamingScope namingScope) + { + var methodInterceptors = @class.CreateField( + namingScope.GetUniqueName(string.Format("interceptors_{0}", method.Name)), + typeof(IInterceptor[]), + false); +#if FEATURE_SERIALIZATION + @class.DefineCustomAttributeFor(methodInterceptors); +#endif + return methodInterceptors; + } + + protected override MethodEmitter BuildProxiedMethodBody(MethodEmitter emitter, ClassEmitter @class, INamingScope namingScope) + { + var invocationType = invocation; + + var genericArguments = Type.EmptyTypes; + + var constructor = invocation.GetConstructors()[0]; + + IExpression proxiedMethodTokenExpression; + if (MethodToOverride.IsGenericMethod) + { + // Not in the cache: generic method + genericArguments = emitter.MethodBuilder.GetGenericArguments(); + proxiedMethodTokenExpression = new MethodTokenExpression(MethodToOverride.MakeGenericMethod(genericArguments)); + + if (invocationType.IsGenericTypeDefinition) + { + // bind generic method arguments to invocation's type arguments + invocationType = invocationType.MakeGenericType(genericArguments); + constructor = TypeBuilder.GetConstructor(invocationType, constructor); + } + } + else + { + var proxiedMethodToken = @class.CreateStaticField(namingScope.GetUniqueName("token_" + MethodToOverride.Name), typeof(MethodInfo)); + @class.ClassConstructor.CodeBuilder.AddStatement(new AssignStatement(proxiedMethodToken, new MethodTokenExpression(MethodToOverride))); + + proxiedMethodTokenExpression = proxiedMethodToken; + } + + var methodInterceptors = SetMethodInterceptors(@class, namingScope, emitter, proxiedMethodTokenExpression); + + var dereferencedArguments = IndirectReference.WrapIfByRef(emitter.Arguments); + var hasByRefArguments = HasByRefArguments(emitter.Arguments); + + var arguments = GetCtorArguments(@class, proxiedMethodTokenExpression, dereferencedArguments, methodInterceptors); + var ctorArguments = ModifyArguments(@class, arguments); + + var invocationLocal = emitter.CodeBuilder.DeclareLocal(invocationType); + emitter.CodeBuilder.AddStatement(new AssignStatement(invocationLocal, + new NewInstanceExpression(constructor, ctorArguments))); + + if (MethodToOverride.ContainsGenericParameters) + { + EmitLoadGenricMethodArguments(emitter, MethodToOverride.MakeGenericMethod(genericArguments), invocationLocal); + } + + if (hasByRefArguments) + { + emitter.CodeBuilder.AddStatement(new TryStatement()); + } + + var proceed = new MethodInvocationExpression(invocationLocal, InvocationMethods.Proceed); + emitter.CodeBuilder.AddStatement(proceed); + + if (hasByRefArguments) + { + emitter.CodeBuilder.AddStatement(new FinallyStatement()); + } + + GeneratorUtil.CopyOutAndRefParameters(dereferencedArguments, invocationLocal, MethodToOverride, emitter); + + if (hasByRefArguments) + { + emitter.CodeBuilder.AddStatement(new EndExceptionBlockStatement()); + } + + if (MethodToOverride.ReturnType != typeof(void)) + { + var getRetVal = new MethodInvocationExpression(invocationLocal, InvocationMethods.GetReturnValue); + + // Emit code to ensure a value type return type is not null, otherwise the cast will cause a null-deref + if (emitter.ReturnType.IsValueType && !emitter.ReturnType.IsNullableType()) + { + LocalReference returnValue = emitter.CodeBuilder.DeclareLocal(typeof(object)); + emitter.CodeBuilder.AddStatement(new AssignStatement(returnValue, getRetVal)); + + emitter.CodeBuilder.AddStatement(new IfNullExpression(returnValue, new ThrowStatement(typeof(InvalidOperationException), + "Interceptors failed to set a return value, or swallowed the exception thrown by the target"))); + } + + // Emit code to return with cast from ReturnValue + emitter.CodeBuilder.AddStatement(new ReturnStatement(new ConvertExpression(emitter.ReturnType, getRetVal))); + } + else + { + emitter.CodeBuilder.AddStatement(new ReturnStatement()); + } + + return emitter; + } + + private IExpression SetMethodInterceptors(ClassEmitter @class, INamingScope namingScope, MethodEmitter emitter, IExpression proxiedMethodTokenExpression) + { + var selector = @class.GetField("__selector"); + if(selector == null) + { + return null; + } + + var methodInterceptorsField = BuildMethodInterceptorsField(@class, MethodToOverride, namingScope); + + IExpression targetTypeExpression; + if (getTargetTypeExpression != null) + { + targetTypeExpression = getTargetTypeExpression(@class, MethodToOverride); + } + else + { + targetTypeExpression = new MethodInvocationExpression(null, TypeUtilMethods.GetTypeOrNull, getTargetExpression(@class, MethodToOverride)); + } + + var emptyInterceptors = new NewArrayExpression(0, typeof(IInterceptor)); + var selectInterceptors = new MethodInvocationExpression(selector, InterceptorSelectorMethods.SelectInterceptors, + targetTypeExpression, + proxiedMethodTokenExpression, interceptors) + { VirtualCall = true }; + + emitter.CodeBuilder.AddStatement( + new IfNullExpression(methodInterceptorsField, + new AssignStatement(methodInterceptorsField, + new NullCoalescingOperatorExpression(selectInterceptors, emptyInterceptors)))); + + return methodInterceptorsField; + } + + private void EmitLoadGenricMethodArguments(MethodEmitter methodEmitter, MethodInfo method, Reference invocationLocal) + { + var genericParameters = Array.FindAll(method.GetGenericArguments(), t => t.IsGenericParameter); + var genericParamsArrayLocal = methodEmitter.CodeBuilder.DeclareLocal(typeof(Type[])); + methodEmitter.CodeBuilder.AddStatement( + new AssignStatement(genericParamsArrayLocal, new NewArrayExpression(genericParameters.Length, typeof(Type)))); + + for (var i = 0; i < genericParameters.Length; ++i) + { + methodEmitter.CodeBuilder.AddStatement( + new AssignArrayStatement(genericParamsArrayLocal, i, new TypeTokenExpression(genericParameters[i]))); + } + methodEmitter.CodeBuilder.AddStatement( + new MethodInvocationExpression(invocationLocal, + InvocationMethods.SetGenericMethodArguments, + genericParamsArrayLocal)); + } + + private IExpression[] GetCtorArguments(ClassEmitter @class, IExpression proxiedMethodTokenExpression, TypeReference[] dereferencedArguments, IExpression methodInterceptors) + { + return new[] + { + getTargetExpression(@class, MethodToOverride), + SelfReference.Self, + methodInterceptors ?? interceptors, + proxiedMethodTokenExpression, + new ReferencesToObjectArrayExpression(dereferencedArguments) + }; + } + + private IExpression[] ModifyArguments(ClassEmitter @class, IExpression[] arguments) + { + if (contributor == null) + { + return arguments; + } + + return contributor.GetConstructorInvocationArguments(arguments, @class); + } + + private bool HasByRefArguments(ArgumentReference[] arguments) + { + for (int i = 0; i < arguments.Length; i++ ) + { + if (arguments[i].Type.IsByRef) + { + return true; + } + } + + return false; + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/MinimialisticMethodGenerator.cs b/Castle.Core/DynamicProxy/Generators/MinimialisticMethodGenerator.cs new file mode 100644 index 0000000..fae27db --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/MinimialisticMethodGenerator.cs @@ -0,0 +1,61 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators +{ + using System.Reflection; + + using Castle.DynamicProxy.Contributors; + using Castle.DynamicProxy.Generators.Emitters; + using Castle.DynamicProxy.Generators.Emitters.SimpleAST; + + internal class MinimialisticMethodGenerator : MethodGenerator + { + public MinimialisticMethodGenerator(MetaMethod method, OverrideMethodDelegate overrideMethod) + : base(method, overrideMethod) + { + } + + protected override MethodEmitter BuildProxiedMethodBody(MethodEmitter emitter, ClassEmitter @class, + INamingScope namingScope) + { + InitOutParameters(emitter, MethodToOverride.GetParameters()); + + if (emitter.ReturnType == typeof(void)) + { + emitter.CodeBuilder.AddStatement(new ReturnStatement()); + } + else + { + emitter.CodeBuilder.AddStatement(new ReturnStatement(new DefaultValueExpression(emitter.ReturnType))); + } + + return emitter; + } + + private void InitOutParameters(MethodEmitter emitter, ParameterInfo[] parameters) + { + for (var index = 0; index < parameters.Length; index++) + { + var parameter = parameters[index]; + if (parameter.IsOut) + { + emitter.CodeBuilder.AddStatement( + new AssignArgumentStatement(new ArgumentReference(parameter.ParameterType, index + 1), + new DefaultValueExpression(parameter.ParameterType))); + } + } + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/NamingScope.cs b/Castle.Core/DynamicProxy/Generators/NamingScope.cs new file mode 100644 index 0000000..57958b2 --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/NamingScope.cs @@ -0,0 +1,61 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators +{ + using System.Collections.Generic; + using System.Diagnostics; + + internal class NamingScope : INamingScope + { + private readonly IDictionary names = new Dictionary(); + private readonly INamingScope parentScope; + + public NamingScope() + { + } + + private NamingScope(INamingScope parent) + { + parentScope = parent; + } + + public INamingScope ParentScope + { + get { return parentScope; } + } + + public string GetUniqueName(string suggestedName) + { + Debug.Assert(string.IsNullOrEmpty(suggestedName) == false, + "string.IsNullOrEmpty(suggestedName) == false"); + + int counter; + if (!names.TryGetValue(suggestedName, out counter)) + { + names.Add(suggestedName, 0); + return suggestedName; + } + + counter++; + names[suggestedName] = counter; + return suggestedName + "_" + counter.ToString(); + } + + public INamingScope SafeSubScope() + { + return new NamingScope(this); + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/OptionallyForwardingMethodGenerator.cs b/Castle.Core/DynamicProxy/Generators/OptionallyForwardingMethodGenerator.cs new file mode 100644 index 0000000..51a36f2 --- /dev/null +++ b/Castle.Core/DynamicProxy/Generators/OptionallyForwardingMethodGenerator.cs @@ -0,0 +1,93 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Generators +{ + using System; + using System.Reflection; + + using Castle.DynamicProxy.Contributors; + using Castle.DynamicProxy.Generators.Emitters; + using Castle.DynamicProxy.Generators.Emitters.SimpleAST; + + internal class OptionallyForwardingMethodGenerator : MethodGenerator + { + // TODO: This class largely duplicates code from Forwarding and Minimalistic generators. Should be refactored to change that + private readonly GetTargetReferenceDelegate getTargetReference; + + public OptionallyForwardingMethodGenerator(MetaMethod method, OverrideMethodDelegate overrideMethod, + GetTargetReferenceDelegate getTargetReference) + : base(method, overrideMethod) + { + this.getTargetReference = getTargetReference; + } + + protected override MethodEmitter BuildProxiedMethodBody(MethodEmitter emitter, ClassEmitter @class, + INamingScope namingScope) + { + var targetReference = getTargetReference(@class, MethodToOverride); + + emitter.CodeBuilder.AddStatement( + new IfNullExpression( + targetReference, + IfNull(emitter.ReturnType), + IfNotNull(targetReference))); + + return emitter; + } + + private IStatement IfNotNull(Reference targetReference) + { + var statements = new BlockStatement(); + var arguments = ArgumentsUtil.ConvertToArgumentReferenceExpression(MethodToOverride.GetParameters()); + + statements.AddStatement(new ReturnStatement( + new MethodInvocationExpression( + targetReference, + MethodToOverride, + arguments) { VirtualCall = true })); + return statements; + } + + private IStatement IfNull(Type returnType) + { + var statements = new BlockStatement(); + InitOutParameters(statements, MethodToOverride.GetParameters()); + + if (returnType == typeof(void)) + { + statements.AddStatement(new ReturnStatement()); + } + else + { + statements.AddStatement(new ReturnStatement(new DefaultValueExpression(returnType))); + } + return statements; + } + + private void InitOutParameters(BlockStatement statements, ParameterInfo[] parameters) + { + for (var index = 0; index < parameters.Length; index++) + { + var parameter = parameters[index]; + if (parameter.IsOut) + { + statements.AddStatement( + new AssignArgumentStatement(new ArgumentReference(parameter.ParameterType, index + 1), + new DefaultValueExpression(parameter.ParameterType))); + } + } + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/IChangeProxyTarget.cs b/Castle.Core/DynamicProxy/IChangeProxyTarget.cs new file mode 100644 index 0000000..8250203 --- /dev/null +++ b/Castle.Core/DynamicProxy/IChangeProxyTarget.cs @@ -0,0 +1,59 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy +{ + using System; + + /// + /// Exposes means to change target objects of proxies and invocations. + /// + public interface IChangeProxyTarget + { + /// + /// Changes the target object () of current . + /// + /// The new value of target of invocation. + /// + /// Although the method takes the actual instance must be of type assignable to , otherwise an will be thrown. + /// Also while it's technically legal to pass null reference (Nothing in Visual Basic) as , for obvious reasons Dynamic Proxy will not be able to call the intercepted method on such target. + /// In this case last interceptor in the pipeline mustn't call or a will be throws. + /// Also while it's technically legal to pass proxy itself as , this would create stack overflow. + /// In this case last interceptor in the pipeline mustn't call or a will be throws. + /// + /// Thrown when is not assignable to the proxied type. + void ChangeInvocationTarget(object target); + + /// + /// Permanently changes the target object of the proxy. This does not affect target of the current invocation. + /// + /// The new value of target of the proxy. + /// + /// Although the method takes the actual instance must be of type assignable to proxy's target type, otherwise an will be thrown. + /// Also while it's technically legal to pass null reference (Nothing in Visual Basic) as , for obvious reasons Dynamic Proxy will not be able to call the intercepted method on such target. + /// In this case last interceptor in the pipeline mustn't call or a will be throws. + /// Also while it's technically legal to pass proxy itself as , this would create stack overflow. + /// In this case last interceptor in the pipeline mustn't call or a will be throws. + /// + /// Thrown when is not assignable to the proxied type. + [Obsolete("Use ((IProxyTargetAccessor)invocation.Proxy).DynProxySetTarget(target) instead.")] + void ChangeProxyTarget(object target); + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/IInterceptor.cs b/Castle.Core/DynamicProxy/IInterceptor.cs new file mode 100644 index 0000000..f5f4378 --- /dev/null +++ b/Castle.Core/DynamicProxy/IInterceptor.cs @@ -0,0 +1,24 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy +{ + /// + /// Provides the main DynamicProxy extension point that allows member interception. + /// + public interface IInterceptor + { + void Intercept(IInvocation invocation); + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/IInterceptorSelector.cs b/Castle.Core/DynamicProxy/IInterceptorSelector.cs new file mode 100644 index 0000000..86d46bd --- /dev/null +++ b/Castle.Core/DynamicProxy/IInterceptorSelector.cs @@ -0,0 +1,42 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy +{ + using System; + using System.Reflection; + + /// + /// Provides an extension point that allows proxies to choose specific interceptors on + /// a per method basis. + /// + public interface IInterceptorSelector + { + /// + /// Selects the interceptors that should intercept calls to the given . + /// + /// The type of the target object. + /// The method that will be intercepted. + /// All interceptors registered with the proxy. + /// An array of interceptors to invoke upon calling the . + /// + /// This method is called only once per proxy instance, upon the first call to the + /// . Either an empty array or null are valid return values to indicate + /// that no interceptor should intercept calls to the method. Although it is not advised, it is + /// legal to return other implementations than these provided in + /// . + /// + IInterceptor[] SelectInterceptors(Type type, MethodInfo method, IInterceptor[] interceptors); + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/IInvocation.cs b/Castle.Core/DynamicProxy/IInvocation.cs new file mode 100644 index 0000000..861eaab --- /dev/null +++ b/Castle.Core/DynamicProxy/IInvocation.cs @@ -0,0 +1,135 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy +{ + using System; + using System.Reflection; + + /// + /// Encapsulates an invocation of a proxied method. + /// + public interface IInvocation + { + /// + /// Gets the arguments that the has been invoked with. + /// + /// The arguments the method was invoked with. + object[] Arguments { get; } + + /// + /// Gets the generic arguments of the method. + /// + /// The generic arguments, or null if not a generic method. + Type[] GenericArguments { get; } + + /// + /// Gets the object on which the invocation is performed. This is different from proxy object + /// because most of the time this will be the proxy target object. + /// + /// + /// The invocation target. + object InvocationTarget { get; } + + /// + /// Gets the representing the method being invoked on the proxy. + /// + /// The representing the method being invoked. + MethodInfo Method { get; } + + /// + /// For interface proxies, this will point to the on the target class. + /// + /// The method invocation target. + MethodInfo MethodInvocationTarget { get; } + + /// + /// Gets the proxy object on which the intercepted method is invoked. + /// + /// Proxy object on which the intercepted method is invoked. + object Proxy { get; } + + /// + /// Gets or sets the return value of the method. + /// + /// The return value of the method. + object ReturnValue { get; set; } + + /// + /// Gets the type of the target object for the intercepted method. + /// + /// The type of the target object. + Type TargetType { get; } + + /// + /// Gets the value of the argument at the specified . + /// + /// The index. + /// The value of the argument at the specified . + object GetArgumentValue(int index); + + /// + /// Returns the concrete instantiation of the on the proxy, with any generic + /// parameters bound to real types. + /// + /// + /// The concrete instantiation of the on the proxy, or the if + /// not a generic method. + /// + /// + /// Can be slower than calling . + /// + MethodInfo GetConcreteMethod(); + + /// + /// Returns the concrete instantiation of , with any + /// generic parameters bound to real types. + /// For interface proxies, this will point to the on the target class. + /// + /// The concrete instantiation of , or + /// if not a generic method. + /// + /// In debug builds this can be slower than calling . + /// + MethodInfo GetConcreteMethodInvocationTarget(); + + /// + /// Proceeds the call to the next interceptor in line, and ultimately to the target method. + /// + /// + /// Since interface proxies without a target don't have the target implementation to proceed to, + /// it is important, that the last interceptor does not call this method, otherwise a + /// will be thrown. + /// + void Proceed(); + + /// + /// Returns an object describing the operation for this + /// at this specific point during interception. + /// + IInvocationProceedInfo CaptureProceedInfo(); + + /// + /// Overrides the value of an argument at the given with the + /// new provided. + /// + /// + /// This method accepts an , however the value provided must be compatible + /// with the type of the argument defined on the method, otherwise an exception will be thrown. + /// + /// The index of the argument to override. + /// The new value for the argument. + void SetArgumentValue(int index, object value); + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/IInvocationProceedInfo.cs b/Castle.Core/DynamicProxy/IInvocationProceedInfo.cs new file mode 100644 index 0000000..4994798 --- /dev/null +++ b/Castle.Core/DynamicProxy/IInvocationProceedInfo.cs @@ -0,0 +1,31 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy +{ + using System; + + /// + /// Describes the operation for an + /// at a specific point during interception. + /// + public interface IInvocationProceedInfo + { + /// + /// Executes the operation described by this instance. + /// + /// There is no interceptor, nor a proxy target object, to proceed to. + void Invoke(); + } +} diff --git a/Castle.Core/DynamicProxy/IProxyBuilder.cs b/Castle.Core/DynamicProxy/IProxyBuilder.cs new file mode 100644 index 0000000..84a525b --- /dev/null +++ b/Castle.Core/DynamicProxy/IProxyBuilder.cs @@ -0,0 +1,137 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy +{ + using System; + using System.Runtime.CompilerServices; + + using Castle.Core.Logging; + using Castle.DynamicProxy.Generators; + + /// + /// Abstracts the implementation of proxy type construction. + /// + public interface IProxyBuilder + { + /// + /// Gets or sets the that this logs to. + /// + ILogger Logger { get; set; } + + /// + /// Gets the associated with this builder. + /// + /// The module scope associated with this builder. + ModuleScope ModuleScope { get; } + + /// + /// Creates a proxy type for given , implementing , using provided. + /// + /// The class type to proxy. + /// Additional interface types to proxy. + /// The proxy generation options. + /// The generated proxy type. + /// + /// Implementers should return a proxy type for the specified class and interfaces. + /// Additional interfaces should be only 'mark' interfaces, that is, they should work like interface proxy without target. (See method.) + /// + /// Thrown when or any of is a generic type definition. + /// Thrown when or any of is not public. + /// Note that to avoid this exception, you can mark offending type internal, and define + /// pointing to Castle Dynamic Proxy assembly, in assembly containing that type, if this is appropriate. + /// + Type CreateClassProxyType(Type classToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options); + + Type CreateClassProxyTypeWithTarget(Type classToProxy, Type[] additionalInterfacesToProxy, + ProxyGenerationOptions options); + + /// + /// Creates a proxy type that proxies calls to members on , implementing , using provided. + /// + /// The interface type to proxy. + /// Additional interface types to proxy. + /// Type implementing on which calls to the interface members should be intercepted. + /// The proxy generation options. + /// The generated proxy type. + /// + /// Implementers should return a proxy type for the specified interface that 'proceeds' executions to the specified target. + /// Additional interfaces should be only 'mark' interfaces, that is, they should work like interface proxy without target. (See method.) + /// + /// Thrown when or any of is a generic type definition. + /// Thrown when or any of is not public. + /// Note that to avoid this exception, you can mark offending type internal, and define + /// pointing to Castle Dynamic Proxy assembly, in assembly containing that type, if this is appropriate. + /// + Type CreateInterfaceProxyTypeWithTarget(Type interfaceToProxy, Type[] additionalInterfacesToProxy, Type targetType, + ProxyGenerationOptions options); + + /// + /// Creates a proxy type for given and that delegates all calls to the provided interceptors and allows interceptors to switch the actual target of invocation. + /// + /// The interface type to proxy. + /// Additional interface types to proxy. + /// The proxy generation options. + /// The generated proxy type. + /// + /// Implementers should return a proxy type for the specified interface(s) that delegate all executions to the specified interceptors + /// and uses an instance of the interface as their targets (i.e. ), rather than a class. All classes should then implement interface, + /// to allow interceptors to switch invocation target with instance of another type implementing called interface. + /// + /// Thrown when or any of is a generic type definition. + /// Thrown when or any of is not public. + /// Note that to avoid this exception, you can mark offending type internal, and define + /// pointing to Castle Dynamic Proxy assembly, in assembly containing that type, if this is appropriate. + /// + Type CreateInterfaceProxyTypeWithTargetInterface(Type interfaceToProxy, Type[] additionalInterfacesToProxy, + ProxyGenerationOptions options); + + /// + /// Creates a proxy type for given that delegates all calls to the provided interceptors. + /// + /// The interface type to proxy. + /// Additional interface types to proxy. + /// The proxy generation options. + /// The generated proxy type. + /// + /// Implementers should return a proxy type for the specified interface and additional interfaces that delegate all executions to the specified interceptors. + /// + /// Thrown when or any of is a generic type definition. + /// Thrown when or any of is not public. + /// Note that to avoid this exception, you can mark offending type internal, and define + /// pointing to Castle Dynamic Proxy assembly, in assembly containing that type, if this is appropriate. + /// + Type CreateInterfaceProxyTypeWithoutTarget(Type interfaceToProxy, Type[] additionalInterfacesToProxy, + ProxyGenerationOptions options); + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/IProxyGenerationHook.cs b/Castle.Core/DynamicProxy/IProxyGenerationHook.cs new file mode 100644 index 0000000..93826e9 --- /dev/null +++ b/Castle.Core/DynamicProxy/IProxyGenerationHook.cs @@ -0,0 +1,50 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy +{ + using System; + using System.Reflection; + + /// + /// Used during the target type inspection process. Implementors have a chance to customize the + /// proxy generation process. + /// + public interface IProxyGenerationHook + { + /// + /// Invoked by the generation process to notify that the whole process has completed. + /// + void MethodsInspected(); + + /// + /// Invoked by the generation process to notify that a member was not marked as virtual. + /// + /// The type which declares the non-virtual member. + /// The non-virtual member. + /// + /// This method gives an opportunity to inspect any non-proxyable member of a type that has + /// been requested to be proxied, and if appropriate - throw an exception to notify the caller. + /// + void NonProxyableMemberNotification(Type type, MemberInfo memberInfo); + + /// + /// Invoked by the generation process to determine if the specified method should be proxied. + /// + /// The type which declares the given method. + /// The method to inspect. + /// True if the given method should be proxied; false otherwise. + bool ShouldInterceptMethod(Type type, MethodInfo methodInfo); + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/IProxyGenerator.cs b/Castle.Core/DynamicProxy/IProxyGenerator.cs new file mode 100644 index 0000000..82b202c --- /dev/null +++ b/Castle.Core/DynamicProxy/IProxyGenerator.cs @@ -0,0 +1,1033 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy +{ + using System; + using System.Reflection; + + using Castle.Core.Logging; + + /// + /// Provides proxy objects for classes and interfaces. + /// + [CLSCompliant(true)] + public interface IProxyGenerator + { + /// + /// Gets or sets the that this log to. + /// + ILogger Logger { get; set; } + + /// + /// Gets the proxy builder instance used to generate proxy types. + /// + /// The proxy builder. + IProxyBuilder ProxyBuilder { get; } + + /// + /// Creates proxy object intercepting calls to members of interface on object with given . + /// + /// Type of the interface implemented by which will be proxied. + /// The target object, calls to which will be intercepted. + /// The interceptors called during the invocation of proxied methods. + /// Object proxying calls to members of on object. + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given array is a null reference (Nothing in Visual Basic). + /// Thrown when given is not an interface type. + /// Thrown when no default constructor exists on actual type of object. + /// Thrown when default constructor of actual type of throws an exception. + /// + /// This method generates new proxy type for each type of , which affects performance. If you don't want to proxy types differently depending on the type of the target + /// use method. + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + TInterface CreateInterfaceProxyWithTarget(TInterface target, params IInterceptor[] interceptors) + where TInterface : class; + + /// + /// Creates proxy object intercepting calls to members of interface on object with given . + /// + /// Type of the interface implemented by which will be proxied. + /// The target object, calls to which will be intercepted. + /// The proxy generation options used to influence generated proxy type and object. + /// The interceptors called during the invocation of proxied methods. + /// + /// Object proxying calls to members of on object. + /// + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given array is a null reference (Nothing in Visual Basic). + /// Thrown when given is not an interface type. + /// Thrown when no default constructor exists on actual type of object. + /// Thrown when default constructor of actual type of throws an exception. + /// + /// This method generates new proxy type for each type of , which affects performance. If you don't want to proxy types differently depending on the type of the target + /// use method. + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + TInterface CreateInterfaceProxyWithTarget(TInterface target, ProxyGenerationOptions options, + params IInterceptor[] interceptors) + where TInterface : class; + + /// + /// Creates proxy object intercepting calls to members of interface on object with given . + /// + /// Type of the interface implemented by which will be proxied. + /// The target object, calls to which will be intercepted. + /// The interceptors called during the invocation of proxied methods. + /// + /// Object proxying calls to members of type on object. + /// + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given array is a null reference (Nothing in Visual Basic). + /// Thrown when given is a generic type definition. + /// Thrown when given is not an interface type. + /// Thrown when given does not implement interface. + /// Thrown when no default constructor exists on actual type of object. + /// Thrown when default constructor of actual type of throws an exception. + /// + /// This method generates new proxy type for each type of , which affects performance. If you don't want to proxy types differently depending on the type of the target + /// use method. + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + object CreateInterfaceProxyWithTarget(Type interfaceToProxy, object target, params IInterceptor[] interceptors); + + /// + /// Creates proxy object intercepting calls to members of interface on object with given . + /// + /// Type of the interface implemented by which will be proxied. + /// The target object, calls to which will be intercepted. + /// The proxy generation options used to influence generated proxy type and object. + /// The interceptors called during the invocation of proxied methods. + /// + /// Object proxying calls to members of type on object. + /// + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given array is a null reference (Nothing in Visual Basic). + /// Thrown when given is a generic type definition. + /// Thrown when given is not an interface type. + /// Thrown when given does not implement interface. + /// Thrown when no default constructor exists on actual type of object. + /// Thrown when default constructor of actual type of throws an exception. + /// + /// This method generates new proxy type for each type of , which affects performance. If you don't want to proxy types differently depending on the type of the target + /// use method. + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + object CreateInterfaceProxyWithTarget(Type interfaceToProxy, object target, ProxyGenerationOptions options, + params IInterceptor[] interceptors); + + /// + /// Creates proxy object intercepting calls to members of interface on object with given . + /// + /// Type of the interface implemented by which will be proxied. + /// The target object, calls to which will be intercepted. + /// Additional interface types. Calls to their members will be proxied as well. + /// The interceptors called during the invocation of proxied methods. + /// + /// Object proxying calls to members of and types on object. + /// + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given array is a null reference (Nothing in Visual Basic). + /// Thrown when given or any of is a generic type definition. + /// Thrown when given is not an interface type. + /// Thrown when given does not implement interface. + /// Thrown when no default constructor exists on actual type of object. + /// Thrown when default constructor of actual type of throws an exception. + /// + /// This method generates new proxy type for each type of , which affects performance. If you don't want to proxy types differently depending on the type of the target + /// use method. + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + object CreateInterfaceProxyWithTarget(Type interfaceToProxy, Type[] additionalInterfacesToProxy, object target, + params IInterceptor[] interceptors); + + /// + /// Creates proxy object intercepting calls to members of interface on object with given . + /// + /// Type of the interface implemented by which will be proxied. + /// The target object, calls to which will be intercepted. + /// The proxy generation options used to influence generated proxy type and object. + /// Additional interface types. Calls to their members will be proxied as well. + /// The interceptors called during the invocation of proxied methods. + /// + /// Object proxying calls to members of and types on object. + /// + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given array is a null reference (Nothing in Visual Basic). + /// Thrown when given or any of is a generic type definition. + /// Thrown when given is not an interface type. + /// Thrown when given does not implement interface. + /// Thrown when no default constructor exists on actual type of object. + /// Thrown when default constructor of actual type of throws an exception. + /// + /// This method generates new proxy type for each type of , which affects performance. If you don't want to proxy types differently depending on the type of the target + /// use method. + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + object CreateInterfaceProxyWithTarget(Type interfaceToProxy, Type[] additionalInterfacesToProxy, + object target, + ProxyGenerationOptions options, + params IInterceptor[] interceptors); + + /// + /// Creates proxy object intercepting calls to members of interface on object with given . + /// Interceptors can use interface to provide other target for method invocation than default . + /// + /// Type of the interface implemented by which will be proxied. + /// The target object, calls to which will be intercepted. + /// The interceptors called during the invocation of proxied methods. + /// + /// Object proxying calls to members of type on object or alternative implementation swapped at runtime by an interceptor. + /// + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given array is a null reference (Nothing in Visual Basic). + /// Thrown when given is a generic type definition. + /// Thrown when given is not an interface type. + /// Thrown when given does not implement interface. + /// Thrown when no default constructor exists on actual type of object. + /// Thrown when default constructor of actual type of throws an exception. + /// + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + object CreateInterfaceProxyWithTargetInterface(Type interfaceToProxy, object target, + params IInterceptor[] interceptors); + + /// + /// Creates proxy object intercepting calls to members of interface on object with given . + /// Interceptors can use interface to provide other target for method invocation than default . + /// + /// Type of the interface implemented by which will be proxied. + /// The target object, calls to which will be intercepted. + /// The interceptors called during the invocation of proxied methods. + /// + /// Object proxying calls to members of type on object or alternative implementation swapped at runtime by an interceptor. + /// + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given array is a null reference (Nothing in Visual Basic). + /// Thrown when given is not an interface type. + /// Thrown when no default constructor exists on actual type of object. + /// Thrown when default constructor of actual type of throws an exception. + /// + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + TInterface CreateInterfaceProxyWithTargetInterface(TInterface target, + params IInterceptor[] interceptors) + where TInterface : class; + + /// + /// Creates proxy object intercepting calls to members of interface on object with given . + /// Interceptors can use interface to provide other target for method invocation than default . + /// + /// Type of the interface implemented by which will be proxied. + /// The target object, calls to which will be intercepted. + /// The proxy generation options used to influence generated proxy type and object. + /// The interceptors called during the invocation of proxied methods. + /// + /// Object proxying calls to members of type on object or alternative implementation swapped at runtime by an interceptor. + /// + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given array is a null reference (Nothing in Visual Basic). + /// Thrown when given is not an interface type. + /// Thrown when no default constructor exists on actual type of object. + /// Thrown when default constructor of actual type of throws an exception. + /// + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + TInterface CreateInterfaceProxyWithTargetInterface(TInterface target, + ProxyGenerationOptions options, + params IInterceptor[] interceptors) + where TInterface : class; + + /// + /// Creates proxy object intercepting calls to members of interface on object with given . + /// Interceptors can use interface to provide other target for method invocation than default . + /// + /// Type of the interface implemented by which will be proxied. + /// The target object, calls to which will be intercepted. + /// Additional interface types. Calls to their members will be proxied as well. + /// The interceptors called during the invocation of proxied methods. + /// + /// Object proxying calls to members of and types on object or alternative implementation swapped at runtime by an interceptor. + /// + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given array is a null reference (Nothing in Visual Basic). + /// Thrown when given or any of is a generic type definition. + /// Thrown when given is not an interface type. + /// Thrown when given does not implement interface. + /// Thrown when no default constructor exists on actual type of object. + /// Thrown when default constructor of actual type of throws an exception. + /// + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + object CreateInterfaceProxyWithTargetInterface(Type interfaceToProxy, Type[] additionalInterfacesToProxy, + object target, params IInterceptor[] interceptors); + + /// + /// Creates proxy object intercepting calls to members of interface on object with given . + /// Interceptors can use interface to provide other target for method invocation than default . + /// + /// Type of the interface implemented by which will be proxied. + /// The target object, calls to which will be intercepted. + /// The proxy generation options used to influence generated proxy type and object. + /// The interceptors called during the invocation of proxied methods. + /// + /// Object proxying calls to members of type on object or alternative implementation swapped at runtime by an interceptor. + /// + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given array is a null reference (Nothing in Visual Basic). + /// Thrown when given is a generic type definition. + /// Thrown when given is not an interface type. + /// Thrown when given does not implement interface. + /// Thrown when no default constructor exists on actual type of object. + /// Thrown when default constructor of actual type of throws an exception. + /// + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + object CreateInterfaceProxyWithTargetInterface(Type interfaceToProxy, object target, + ProxyGenerationOptions options, + params IInterceptor[] interceptors); + + /// + /// Creates proxy object intercepting calls to members of interface on object with given . + /// Interceptors can use interface to provide other target for method invocation than default . + /// + /// Type of the interface implemented by which will be proxied. + /// The target object, calls to which will be intercepted. + /// The proxy generation options used to influence generated proxy type and object. + /// Additional interface types. Calls to their members will be proxied as well. + /// The interceptors called during the invocation of proxied methods. + /// + /// Object proxying calls to members of and types on object or alternative implementation swapped at runtime by an interceptor. + /// + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given array is a null reference (Nothing in Visual Basic). + /// Thrown when given or any of is a generic type definition. + /// Thrown when given is not an interface type. + /// Thrown when given does not implement interface. + /// Thrown when no default constructor exists on actual type of object. + /// Thrown when default constructor of actual type of throws an exception. + /// + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + object CreateInterfaceProxyWithTargetInterface(Type interfaceToProxy, + Type[] additionalInterfacesToProxy, + object target, ProxyGenerationOptions options, + params IInterceptor[] interceptors); + + /// + /// Creates proxy object intercepting calls to members of interface on target object generated at runtime with given . + /// + /// Type of the interface which will be proxied. + /// The interceptors called during the invocation of proxied methods. + /// + /// Object proxying calls to members of types on generated target object. + /// + /// Thrown when given array is a null reference (Nothing in Visual Basic). + /// Thrown when given is not an interface type. + /// + /// Since this method uses an empty-shell implementation of interfaces to proxy generated at runtime, the actual implementation of proxied methods must be provided by given implementations. + /// They are responsible for setting return value (and out parameters) on proxied methods. It is also illegal for an interceptor to call , since there's no actual implementation to proceed with. + /// As a result of that also at least one implementation must be provided. + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + TInterface CreateInterfaceProxyWithoutTarget(IInterceptor interceptor) + where TInterface : class; + + /// + /// Creates proxy object intercepting calls to members of interface on target object generated at runtime with given . + /// + /// Type of the interface which will be proxied. + /// The interceptors called during the invocation of proxied methods. + /// + /// Object proxying calls to members of types on generated target object. + /// + /// Thrown when given array is a null reference (Nothing in Visual Basic). + /// Thrown when given is not an interface type. + /// + /// Since this method uses an empty-shell implementation of interfaces to proxy generated at runtime, the actual implementation of proxied methods must be provided by given implementations. + /// They are responsible for setting return value (and out parameters) on proxied methods. It is also illegal for an interceptor to call , since there's no actual implementation to proceed with. + /// As a result of that also at least one implementation must be provided. + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + TInterface CreateInterfaceProxyWithoutTarget(params IInterceptor[] interceptors) + where TInterface : class; + + /// + /// Creates proxy object intercepting calls to members of interface on target object generated at runtime with given . + /// + /// Type of the interface which will be proxied. + /// The proxy generation options used to influence generated proxy type and object. + /// The interceptors called during the invocation of proxied methods. + /// + /// Object proxying calls to members of types on generated target object. + /// + /// Thrown when given array is a null reference (Nothing in Visual Basic). + /// Thrown when given is not an interface type. + /// + /// Since this method uses an empty-shell implementation of interfaces to proxy generated at runtime, the actual implementation of proxied methods must be provided by given implementations. + /// They are responsible for setting return value (and out parameters) on proxied methods. It is also illegal for an interceptor to call , since there's no actual implementation to proceed with. + /// As a result of that also at least one implementation must be provided. + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + TInterface CreateInterfaceProxyWithoutTarget(ProxyGenerationOptions options, + params IInterceptor[] interceptors) + where TInterface : class; + + /// + /// Creates proxy object intercepting calls to members of interface on target object generated at runtime with given . + /// + /// Type of the interface which will be proxied. + /// The interceptors called during the invocation of proxied methods. + /// + /// Object proxying calls to members of type on generated target object. + /// + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given array is a null reference (Nothing in Visual Basic). + /// Thrown when given is a generic type definition. + /// Thrown when given is not an interface type. + /// + /// Since this method uses an empty-shell implementation of interfaces to proxy generated at runtime, the actual implementation of proxied methods must be provided by given implementations. + /// They are responsible for setting return value (and out parameters) on proxied methods. It is also illegal for an interceptor to call , since there's no actual implementation to proceed with. + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + object CreateInterfaceProxyWithoutTarget(Type interfaceToProxy, IInterceptor interceptor); + + /// + /// Creates proxy object intercepting calls to members of interface on target object generated at runtime with given . + /// + /// Type of the interface which will be proxied. + /// The interceptors called during the invocation of proxied methods. + /// + /// Object proxying calls to members of type on generated target object. + /// + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given array is a null reference (Nothing in Visual Basic). + /// Thrown when given is a generic type definition. + /// Thrown when given is not an interface type. + /// + /// Since this method uses an empty-shell implementation of interfaces to proxy generated at runtime, the actual implementation of proxied methods must be provided by given implementations. + /// They are responsible for setting return value (and out parameters) on proxied methods. It is also illegal for an interceptor to call , since there's no actual implementation to proceed with. + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + object CreateInterfaceProxyWithoutTarget(Type interfaceToProxy, params IInterceptor[] interceptors); + + /// + /// Creates proxy object intercepting calls to members of interface on target object generated at runtime with given . + /// + /// Type of the interface which will be proxied. + /// Additional interface types. Calls to their members will be proxied as well. + /// The interceptors called during the invocation of proxied methods. + /// + /// Object proxying calls to members of and types on generated target object. + /// + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given array is a null reference (Nothing in Visual Basic). + /// Thrown when given or any of is a generic type definition. + /// Thrown when given is not an interface type. + /// + /// Since this method uses an empty-shell implementation of interfaces to proxy generated at runtime, the actual implementation of proxied methods must be provided by given implementations. + /// They are responsible for setting return value (and out parameters) on proxied methods. It is also illegal for an interceptor to call , since there's no actual implementation to proceed with. + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + object CreateInterfaceProxyWithoutTarget(Type interfaceToProxy, Type[] additionalInterfacesToProxy, + params IInterceptor[] interceptors); + + /// + /// Creates proxy object intercepting calls to members of interface on target object generated at runtime with given . + /// + /// Type of the interface which will be proxied. + /// The proxy generation options used to influence generated proxy type and object. + /// The interceptors called during the invocation of proxied methods. + /// + /// Object proxying calls to members of on generated target object. + /// + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given array is a null reference (Nothing in Visual Basic). + /// Thrown when given is a generic type definition. + /// Thrown when given is not an interface type. + /// + /// They are responsible for setting return value (and out parameters) on proxied methods. It is also illegal for an interceptor to call , since there's no actual implementation to proceed with. + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + object CreateInterfaceProxyWithoutTarget(Type interfaceToProxy, ProxyGenerationOptions options, + params IInterceptor[] interceptors); + + /// + /// Creates proxy object intercepting calls to members of interface on target object generated at runtime with given . + /// + /// Type of the interface which will be proxied. + /// The proxy generation options used to influence generated proxy type and object. + /// Additional interface types. Calls to their members will be proxied as well. + /// The interceptors called during the invocation of proxied methods. + /// + /// Object proxying calls to members of and types on generated target object. + /// + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given array is a null reference (Nothing in Visual Basic). + /// Thrown when given or any of is a generic type definition. + /// Thrown when given is not an interface type. + /// + /// Since this method uses an empty-shell implementation of to proxy generated at runtime, the actual implementation of proxied methods must be provided by given implementations. + /// They are responsible for setting return value (and out parameters) on proxied methods. It is also illegal for an interceptor to call , since there's no actual implementation to proceed with. + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + object CreateInterfaceProxyWithoutTarget(Type interfaceToProxy, Type[] additionalInterfacesToProxy, + ProxyGenerationOptions options, + params IInterceptor[] interceptors); + + /// + /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . + /// + /// Type of class which will be proxied. + /// The target object, calls to which will be intercepted. + /// The interceptors called during the invocation of proxied methods. + /// + /// New object of type proxying calls to virtual members of type. + /// + /// Thrown when given is not a class type. + /// Thrown when no default constructor exists on type . + /// Thrown when default constructor of type throws an exception. + /// + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + TClass CreateClassProxyWithTarget(TClass target, params IInterceptor[] interceptors) + where TClass : class; + + /// + /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . + /// + /// Type of class which will be proxied. + /// The target object, calls to which will be intercepted. + /// The proxy generation options used to influence generated proxy type and object. + /// The interceptors called during the invocation of proxied methods. + /// + /// New object of type proxying calls to virtual members of type. + /// + /// Thrown when given is not a class type. + /// Thrown when no default constructor exists on type . + /// Thrown when default constructor of type throws an exception. + /// + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + TClass CreateClassProxyWithTarget(TClass target, ProxyGenerationOptions options, + params IInterceptor[] interceptors) where TClass : class; + + /// + /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . + /// + /// Type of class which will be proxied. + /// Additional interface types. Calls to their members will be proxied as well. + /// The target object, calls to which will be intercepted. + /// The interceptors called during the invocation of proxied methods. + /// + /// New object of type proxying calls to virtual members of and types. + /// + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given or any of is a generic type definition. + /// Thrown when given is not a class type. + /// Thrown when no default constructor exists on type . + /// Thrown when default constructor of type throws an exception. + /// + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + object CreateClassProxyWithTarget(Type classToProxy, Type[] additionalInterfacesToProxy, object target, + params IInterceptor[] interceptors); + + /// + /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . + /// + /// Type of class which will be proxied. + /// The target object, calls to which will be intercepted. + /// The proxy generation options used to influence generated proxy type and object. + /// Arguments of constructor of type which should be used to create a new instance of that type. + /// The interceptors called during the invocation of proxied methods. + /// + /// New object of type proxying calls to virtual members of type. + /// + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given is a generic type definition. + /// Thrown when given is not a class type. + /// Thrown when no constructor exists on type with parameters matching . + /// Thrown when constructor of type throws an exception. + /// + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + object CreateClassProxyWithTarget(Type classToProxy, object target, ProxyGenerationOptions options, + object[] constructorArguments, params IInterceptor[] interceptors); + + /// + /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . + /// + /// Type of class which will be proxied. + /// The target object, calls to which will be intercepted. + /// Arguments of constructor of type which should be used to create a new instance of that type. + /// The interceptors called during the invocation of proxied methods. + /// + /// New object of type proxying calls to virtual members of type. + /// + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given is a generic type definition. + /// Thrown when given is not a class type. + /// Thrown when no constructor exists on type with parameters matching . + /// Thrown when constructor of type throws an exception. + /// + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + object CreateClassProxyWithTarget(Type classToProxy, object target, object[] constructorArguments, + params IInterceptor[] interceptors); + + /// + /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . + /// + /// Type of class which will be proxied. + /// The target object, calls to which will be intercepted. + /// The interceptors called during the invocation of proxied methods. + /// + /// New object of type proxying calls to virtual members of type. + /// + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given is a generic type definition. + /// Thrown when given is not a class type. + /// Thrown when no parameterless constructor exists on type . + /// Thrown when constructor of type throws an exception. + /// + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + object CreateClassProxyWithTarget(Type classToProxy, object target, params IInterceptor[] interceptors); + + /// + /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . + /// + /// Type of class which will be proxied. + /// The target object, calls to which will be intercepted. + /// The proxy generation options used to influence generated proxy type and object. + /// The interceptors called during the invocation of proxied methods. + /// + /// New object of type proxying calls to virtual members of type. + /// + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given is a generic type definition. + /// Thrown when given is not a class type. + /// Thrown when no default constructor exists on type . + /// Thrown when default constructor of type throws an exception. + /// + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + object CreateClassProxyWithTarget(Type classToProxy, object target, ProxyGenerationOptions options, + params IInterceptor[] interceptors); + + /// + /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . + /// + /// Type of class which will be proxied. + /// Additional interface types. Calls to their members will be proxied as well. + /// The target object, calls to which will be intercepted. + /// The proxy generation options used to influence generated proxy type and object. + /// The interceptors called during the invocation of proxied methods. + /// + /// New object of type proxying calls to virtual members of and types. + /// + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given or any of is a generic type definition. + /// Thrown when given is not a class type. + /// Thrown when no default constructor exists on type . + /// Thrown when default constructor of type throws an exception. + /// + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + object CreateClassProxyWithTarget(Type classToProxy, Type[] additionalInterfacesToProxy, object target, + ProxyGenerationOptions options, params IInterceptor[] interceptors); + + /// + /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . + /// + /// Type of class which will be proxied. + /// Additional interface types. Calls to their members will be proxied as well. + /// The target object, calls to which will be intercepted. + /// The proxy generation options used to influence generated proxy type and object. + /// Arguments of constructor of type which should be used to create a new instance of that type. + /// The interceptors called during the invocation of proxied methods. + /// + /// New object of type proxying calls to virtual members of and types. + /// + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given or any of is a generic type definition. + /// Thrown when given is not a class type. + /// Thrown when no constructor exists on type with parameters matching . + /// Thrown when constructor of type throws an exception. + /// + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + object CreateClassProxyWithTarget(Type classToProxy, Type[] additionalInterfacesToProxy, object target, + ProxyGenerationOptions options, object[] constructorArguments, + params IInterceptor[] interceptors); + + /// + /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . + /// + /// Type of class which will be proxied. + /// The interceptors called during the invocation of proxied methods. + /// + /// New object of type proxying calls to virtual members of type. + /// + /// Thrown when given is not a class type. + /// Thrown when no default constructor exists on type . + /// Thrown when default constructor of type throws an exception. + /// + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + TClass CreateClassProxy(params IInterceptor[] interceptors) where TClass : class; + + /// + /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . + /// + /// Type of class which will be proxied. + /// The proxy generation options used to influence generated proxy type and object. + /// The interceptors called during the invocation of proxied methods. + /// + /// New object of type proxying calls to virtual members of type. + /// + /// Thrown when given is not a class type. + /// Thrown when no default constructor exists on type . + /// Thrown when default constructor of type throws an exception. + /// + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + TClass CreateClassProxy(ProxyGenerationOptions options, params IInterceptor[] interceptors) + where TClass : class; + + /// + /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . + /// + /// Type of class which will be proxied. + /// Additional interface types. Calls to their members will be proxied as well. + /// The interceptors called during the invocation of proxied methods. + /// + /// New object of type proxying calls to virtual members of and types. + /// + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given or any of is a generic type definition. + /// Thrown when given is not a class type. + /// Thrown when no default constructor exists on type . + /// Thrown when default constructor of type throws an exception. + /// + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + object CreateClassProxy(Type classToProxy, Type[] additionalInterfacesToProxy, + params IInterceptor[] interceptors); + + /// + /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . + /// + /// Type of class which will be proxied. + /// The proxy generation options used to influence generated proxy type and object. + /// Arguments of constructor of type which should be used to create a new instance of that type. + /// The interceptors called during the invocation of proxied methods. + /// + /// New object of type proxying calls to virtual members of type. + /// + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given is a generic type definition. + /// Thrown when given is not a class type. + /// Thrown when no constructor exists on type with parameters matching . + /// Thrown when constructor of type throws an exception. + /// + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + object CreateClassProxy(Type classToProxy, ProxyGenerationOptions options, object[] constructorArguments, + params IInterceptor[] interceptors); + + /// + /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . + /// + /// Type of class which will be proxied. + /// Arguments of constructor of type which should be used to create a new instance of that type. + /// The interceptors called during the invocation of proxied methods. + /// + /// New object of type proxying calls to virtual members of type. + /// + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given is a generic type definition. + /// Thrown when given is not a class type. + /// Thrown when no constructor exists on type with parameters matching . + /// Thrown when constructor of type throws an exception. + /// + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + object CreateClassProxy(Type classToProxy, object[] constructorArguments, params IInterceptor[] interceptors); + + /// + /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . + /// + /// Type of class which will be proxied. + /// The interceptors called during the invocation of proxied methods. + /// + /// New object of type proxying calls to virtual members of type. + /// + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given is a generic type definition. + /// Thrown when given is not a class type. + /// Thrown when no parameterless constructor exists on type . + /// Thrown when constructor of type throws an exception. + /// + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + object CreateClassProxy(Type classToProxy, params IInterceptor[] interceptors); + + /// + /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . + /// + /// Type of class which will be proxied. + /// The proxy generation options used to influence generated proxy type and object. + /// The interceptors called during the invocation of proxied methods. + /// + /// New object of type proxying calls to virtual members of type. + /// + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given is a generic type definition. + /// Thrown when given is not a class type. + /// Thrown when no default constructor exists on type . + /// Thrown when default constructor of type throws an exception. + /// + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + object CreateClassProxy(Type classToProxy, ProxyGenerationOptions options, params IInterceptor[] interceptors); + + /// + /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . + /// + /// Type of class which will be proxied. + /// Additional interface types. Calls to their members will be proxied as well. + /// The proxy generation options used to influence generated proxy type and object. + /// The interceptors called during the invocation of proxied methods. + /// + /// New object of type proxying calls to virtual members of and types. + /// + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given or any of is a generic type definition. + /// Thrown when given is not a class type. + /// Thrown when no default constructor exists on type . + /// Thrown when default constructor of type throws an exception. + /// + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + object CreateClassProxy(Type classToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options, + params IInterceptor[] interceptors); + + /// + /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . + /// + /// Type of class which will be proxied. + /// Additional interface types. Calls to their members will be proxied as well. + /// The proxy generation options used to influence generated proxy type and object. + /// Arguments of constructor of type which should be used to create a new instance of that type. + /// The interceptors called during the invocation of proxied methods. + /// + /// New object of type proxying calls to virtual members of and types. + /// + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given or any of is a generic type definition. + /// Thrown when given is not a class type. + /// Thrown when no constructor exists on type with parameters matching . + /// Thrown when constructor of type throws an exception. + /// + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + object CreateClassProxy(Type classToProxy, Type[] additionalInterfacesToProxy, + ProxyGenerationOptions options, + object[] constructorArguments, params IInterceptor[] interceptors); + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/IProxyTargetAccessor.cs b/Castle.Core/DynamicProxy/IProxyTargetAccessor.cs new file mode 100644 index 0000000..172618e --- /dev/null +++ b/Castle.Core/DynamicProxy/IProxyTargetAccessor.cs @@ -0,0 +1,39 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy +{ + /// + /// Exposes access to the target object and interceptors of proxy objects. + /// This is a DynamicProxy infrastructure interface and should not be implemented yourself. + /// + public interface IProxyTargetAccessor + { + /// + /// Get the proxy target (note that null is a valid target!) + /// + object DynProxyGetTarget(); + + /// + /// Set the proxy target. + /// + /// New proxy target. + void DynProxySetTarget(object target); + + /// + /// Gets the interceptors for the proxy + /// + IInterceptor[] GetInterceptors(); + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Internal/AttributeUtil.cs b/Castle.Core/DynamicProxy/Internal/AttributeUtil.cs new file mode 100644 index 0000000..e773080 --- /dev/null +++ b/Castle.Core/DynamicProxy/Internal/AttributeUtil.cs @@ -0,0 +1,251 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Internal +{ + using System; + using System.Collections.Generic; + using System.Diagnostics; + using System.Linq; + using System.Reflection; + + using Castle.DynamicProxy.Generators; + + internal static class AttributeUtil + { + public static CustomAttributeInfo CreateInfo(CustomAttributeData attribute) + { + Debug.Assert(attribute != null, "attribute != null"); + + // .NET Core does not provide CustomAttributeData.Constructor, so we'll implement it + // by finding a constructor ourselves + Type[] constructorArgTypes; + object[] constructorArgs; + GetArguments(attribute.ConstructorArguments, out constructorArgTypes, out constructorArgs); + var constructor = attribute.AttributeType.GetConstructor(constructorArgTypes); + + PropertyInfo[] properties; + object[] propertyValues; + FieldInfo[] fields; + object[] fieldValues; + GetSettersAndFields( + attribute.AttributeType, + attribute.NamedArguments, out properties, out propertyValues, out fields, out fieldValues); + + return new CustomAttributeInfo(constructor, + constructorArgs, + properties, + propertyValues, + fields, + fieldValues); + } + + private static void GetArguments(IList constructorArguments, + out Type[] constructorArgTypes, out object[] constructorArgs) + { + constructorArgTypes = new Type[constructorArguments.Count]; + constructorArgs = new object[constructorArguments.Count]; + for (var i = 0; i < constructorArguments.Count; i++) + { + constructorArgTypes[i] = constructorArguments[i].ArgumentType; + constructorArgs[i] = ReadAttributeValue(constructorArguments[i]); + } + } + + private static object[] GetArguments(IList constructorArguments) + { + var arguments = new object[constructorArguments.Count]; + for (var i = 0; i < constructorArguments.Count; i++) + { + arguments[i] = ReadAttributeValue(constructorArguments[i]); + } + + return arguments; + } + + private static object ReadAttributeValue(CustomAttributeTypedArgument argument) + { + var value = argument.Value; + if (argument.ArgumentType.IsArray == false) + { + return value; + } + //special case for handling arrays in attributes + var arguments = GetArguments((IList)value); + var array = new object[arguments.Length]; + arguments.CopyTo(array, 0); + return array; + } + + private static void GetSettersAndFields(Type attributeType, IEnumerable namedArguments, + out PropertyInfo[] properties, out object[] propertyValues, + out FieldInfo[] fields, out object[] fieldValues) + { + var propertyList = new List(); + var propertyValuesList = new List(); + var fieldList = new List(); + var fieldValuesList = new List(); + foreach (var argument in namedArguments) + { + if (argument.IsField) + { + fieldList.Add(attributeType.GetField(argument.MemberName)); + fieldValuesList.Add(ReadAttributeValue(argument.TypedValue)); + } + else + { + propertyList.Add(attributeType.GetProperty(argument.MemberName)); + propertyValuesList.Add(ReadAttributeValue(argument.TypedValue)); + } + } + + properties = propertyList.ToArray(); + propertyValues = propertyValuesList.ToArray(); + fields = fieldList.ToArray(); + fieldValues = fieldValuesList.ToArray(); + } + + public static IEnumerable GetNonInheritableAttributes(this MemberInfo member) + { + Debug.Assert(member != null, "member != null"); + var attributes = member.CustomAttributes; + + foreach (var attribute in attributes) + { + var attributeType = attribute.AttributeType; + if (ShouldSkipAttributeReplication(attributeType, ignoreInheritance: false)) + { + continue; + } + + CustomAttributeInfo info; + try + { + info = CreateInfo(attribute); + } + catch (ArgumentException e) + { + var message = + string.Format( + "Due to limitations in CLR, DynamicProxy was unable to successfully replicate non-inheritable attribute {0} on {1}{2}. " + + "To avoid this error you can chose not to replicate this attribute type by calling '{3}.Add(typeof({0}))'.", + attributeType.FullName, + member.DeclaringType.FullName, + (member is TypeInfo) ? "" : ("." + member.Name), + typeof(AttributesToAvoidReplicating).FullName); + throw new NotSupportedException(message, e); + } + if (info != null) + { + yield return info; + } + } + } + + public static IEnumerable GetNonInheritableAttributes(this ParameterInfo parameter) + { + Debug.Assert(parameter != null, "parameter != null"); + + var attributes = parameter.CustomAttributes; + + var ignoreInheritance = parameter.Member is ConstructorInfo; + + foreach (var attribute in attributes) + { + var attributeType = attribute.AttributeType; + + if (ShouldSkipAttributeReplication(attributeType, ignoreInheritance)) + { + continue; + } + + var info = CreateInfo(attribute); + if (info != null) + { + yield return info; + } + } + } + + /// + /// Attributes should be replicated if they are non-inheritable, + /// but there are some special cases where the attributes means + /// something to the CLR, where they should be skipped. + /// + private static bool ShouldSkipAttributeReplication(Type attribute, bool ignoreInheritance) + { + if (attribute.IsPublic == false) + { + return true; + } + + if (AttributesToAvoidReplicating.ShouldAvoid(attribute)) + { + return true; + } + + // Later, there might be more special cases requiring attribute replication, + // which might justify creating a `SpecialCaseAttributeThatShouldBeReplicated` + // method and an `AttributesToAlwaysReplicate` class. For the moment, `Param- + // ArrayAttribute` is the only special case, so keep it simple for now: + if (attribute == typeof(ParamArrayAttribute)) + { + return false; + } + + if (!ignoreInheritance) + { + var attrs = attribute.GetCustomAttributes(true).ToArray(); + if (attrs.Length != 0) + { + return attrs[0].Inherited; + } + + return true; + } + + return false; + } + + public static CustomAttributeInfo CreateInfo() where TAttribute : Attribute, new() + { + var constructor = typeof(TAttribute).GetConstructor(Type.EmptyTypes); + Debug.Assert(constructor != null, "constructor != null"); + + return new CustomAttributeInfo(constructor, new object[0]); + } + + public static CustomAttributeInfo CreateInfo(Type attribute, object[] constructorArguments) + { + Debug.Assert(attribute != null, "attribute != null"); + Debug.Assert(typeof(Attribute).IsAssignableFrom(attribute), "typeof(Attribute).IsAssignableFrom(attribute)"); + Debug.Assert(constructorArguments != null, "constructorArguments != null"); + + var constructor = attribute.GetConstructor(GetTypes(constructorArguments)); + Debug.Assert(constructor != null, "constructor != null"); + + return new CustomAttributeInfo(constructor, constructorArguments); + } + + private static Type[] GetTypes(object[] objects) + { + var types = new Type[objects.Length]; + for (var i = 0; i < types.Length; i++) + { + types[i] = objects[i].GetType(); + } + return types; + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Internal/CompositionInvocation.cs b/Castle.Core/DynamicProxy/Internal/CompositionInvocation.cs new file mode 100644 index 0000000..0d03e56 --- /dev/null +++ b/Castle.Core/DynamicProxy/Internal/CompositionInvocation.cs @@ -0,0 +1,86 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Internal +{ + using System; + using System.Reflection; + + public abstract class CompositionInvocation : AbstractInvocation + { + protected object target; + + protected CompositionInvocation( + object target, + object proxy, + IInterceptor[] interceptors, + MethodInfo proxiedMethod, + object[] arguments) + : base(proxy, interceptors, proxiedMethod, arguments) + { + this.target = target; + } + + public override object InvocationTarget + { + get { return target; } + } + + public override MethodInfo MethodInvocationTarget + { + get { return InvocationHelper.GetMethodOnObject(target, Method); } + } + + public override Type TargetType + { + get { return TypeUtil.GetTypeOrNull(target); } + } + + protected void EnsureValidProxyTarget(object newTarget) + { + if (newTarget == null) + { + throw new ArgumentNullException(nameof(newTarget)); + } + + if (!ReferenceEquals(newTarget, proxyObject)) + { + return; + } + + var message = "This is a DynamicProxy2 error: target of proxy has been set to the proxy itself. " + + "This would result in recursively calling proxy methods over and over again until stack overflow, which may destabilize your program." + + "This usually signifies a bug in the calling code. Make sure no interceptor sets proxy as its own target."; + throw new InvalidOperationException(message); + } + + protected void EnsureValidTarget() + { + if (target == null) + { + ThrowOnNoTarget(); + } + + if (!ReferenceEquals(target, proxyObject)) + { + return; + } + + var message = "This is a DynamicProxy2 error: target of invocation has been set to the proxy itself. " + + "This may result in recursively calling the method over and over again until stack overflow, which may destabilize your program." + + "This usually signifies a bug in the calling code. Make sure no interceptor sets proxy as its invocation target."; + throw new InvalidOperationException(message); + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Internal/InheritanceInvocation.cs b/Castle.Core/DynamicProxy/Internal/InheritanceInvocation.cs new file mode 100644 index 0000000..a3a6d7f --- /dev/null +++ b/Castle.Core/DynamicProxy/Internal/InheritanceInvocation.cs @@ -0,0 +1,52 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Internal +{ + using System; + using System.Reflection; + + public abstract class InheritanceInvocation : AbstractInvocation + { + private readonly Type targetType; + + protected InheritanceInvocation( + Type targetType, + object proxy, + IInterceptor[] interceptors, + MethodInfo proxiedMethod, + object[] arguments) + : base(proxy, interceptors, proxiedMethod, arguments) + { + this.targetType = targetType; + } + + public override object InvocationTarget + { + get { return Proxy; } + } + + public override MethodInfo MethodInvocationTarget + { + get { return InvocationHelper.GetMethodOnType(targetType, Method); } + } + + public override Type TargetType + { + get { return targetType; } + } + + protected abstract override void InvokeMethodOnTarget(); + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Internal/InterfaceMethodWithoutTargetInvocation.cs b/Castle.Core/DynamicProxy/Internal/InterfaceMethodWithoutTargetInvocation.cs new file mode 100644 index 0000000..a1c92a2 --- /dev/null +++ b/Castle.Core/DynamicProxy/Internal/InterfaceMethodWithoutTargetInvocation.cs @@ -0,0 +1,61 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Internal +{ + using System; + using System.ComponentModel; + using System.Diagnostics; + using System.Reflection; + +#if FEATURE_SERIALIZATION + [Serializable] +#endif + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class InterfaceMethodWithoutTargetInvocation : AbstractInvocation + { + public InterfaceMethodWithoutTargetInvocation(object target, object proxy, IInterceptor[] interceptors, MethodInfo proxiedMethod, object[] arguments) + : base(proxy, interceptors, proxiedMethod, arguments) + { + // This invocation type is suitable for interface method invocations that cannot proceed + // to a target, i.e. where `InvokeMethodOnTarget` will always throw: + + Debug.Assert(target == null, $"{nameof(InterfaceMethodWithoutTargetInvocation)} does not support targets."); + Debug.Assert(proxiedMethod.IsAbstract, $"{nameof(InterfaceMethodWithoutTargetInvocation)} does not support non-abstract methods."); + + // Why this restriction? Because it greatly benefits proxy type generation performance. + // + // For invocations that can proceed to a target, `InvokeMethodOnTarget`'s implementation + // depends on the target method's signature. Because of this, DynamicProxy needs to + // dynamically generate a separate invocation type per such method. Type generation is + // always expensive... that is, slow. + // + // However, if it is known that `InvokeMethodOnTarget` won't forward, but throw, + // no custom (dynamically generated) invocation type is needed at all, and we can use + // this unspecific invocation type instead. + } + + // The next three properties mimick the behavior seen with an interface proxy without target. + // (This is why this type's name starts with `Interface`.) A similar type could be written + // for class proxies without target, but the values returned here would be different. + + public override object InvocationTarget => null; + + public override MethodInfo MethodInvocationTarget => null; + + public override Type TargetType => null; + + protected override void InvokeMethodOnTarget() => ThrowOnNoTarget(); + } +} diff --git a/Castle.Core/DynamicProxy/Internal/InvocationHelper.cs b/Castle.Core/DynamicProxy/Internal/InvocationHelper.cs new file mode 100644 index 0000000..41ddbfa --- /dev/null +++ b/Castle.Core/DynamicProxy/Internal/InvocationHelper.cs @@ -0,0 +1,132 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Internal +{ + using System; + using System.Collections.Generic; + using System.Diagnostics; + using System.Reflection; + using System.Threading; + + using Castle.Core.Internal; + using Castle.DynamicProxy.Generators; + + internal static class InvocationHelper + { + private static readonly SynchronizedDictionary cache = + new SynchronizedDictionary(); + + public static MethodInfo GetMethodOnObject(object target, MethodInfo proxiedMethod) + { + if (target == null) + { + return null; + } + + return GetMethodOnType(target.GetType(), proxiedMethod); + } + + public static MethodInfo GetMethodOnType(Type type, MethodInfo proxiedMethod) + { + if (type == null) + { + throw new ArgumentNullException(nameof(type)); + } + + Debug.Assert(proxiedMethod.DeclaringType.IsAssignableFrom(type), + "proxiedMethod.DeclaringType.IsAssignableFrom(type)"); + + var cacheKey = new CacheKey(proxiedMethod, type); + + return cache.GetOrAdd(cacheKey, ck => ObtainMethod(proxiedMethod, type)); + } + + private static MethodInfo ObtainMethod(MethodInfo proxiedMethod, Type type) + { + Type[] genericArguments = null; + if (proxiedMethod.IsGenericMethod) + { + genericArguments = proxiedMethod.GetGenericArguments(); + proxiedMethod = proxiedMethod.GetGenericMethodDefinition(); + } + var declaringType = proxiedMethod.DeclaringType; + MethodInfo methodOnTarget = null; + if (declaringType.IsInterface) + { + var mapping = type.GetInterfaceMap(declaringType); + var index = Array.IndexOf(mapping.InterfaceMethods, proxiedMethod); + Debug.Assert(index != -1); + methodOnTarget = mapping.TargetMethods[index]; + } + else + { + // NOTE: this implementation sucks, feel free to improve it. + var methods = MethodFinder.GetAllInstanceMethods(type, BindingFlags.Public | BindingFlags.NonPublic); + foreach (var method in methods) + { + if (MethodSignatureComparer.Instance.Equals(method.GetBaseDefinition(), proxiedMethod)) + { + methodOnTarget = method; + break; + } + } + } + if (methodOnTarget == null) + { + throw new ArgumentException( + string.Format("Could not find method overriding {0} on type {1}. This is most likely a bug. Please report it.", + proxiedMethod, type)); + } + + if (genericArguments == null) + { + return methodOnTarget; + } + return methodOnTarget.MakeGenericMethod(genericArguments); + } + + private struct CacheKey : IEquatable + { + public CacheKey(MethodInfo method, Type type) + { + Method = method; + Type = type; + } + public MethodInfo Method { get; } + + public Type Type { get; } + + public bool Equals(CacheKey other) + { + return object.ReferenceEquals(Method, other.Method) && object.ReferenceEquals(Type, other.Type); + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) + return false; + return obj is CacheKey @struct && Equals(@struct); + } + + public override int GetHashCode() + { + unchecked + { + return ((Method != null ? Method.GetHashCode() : 0) * 397) ^ (Type != null ? Type.GetHashCode() : 0); + } + } + } + } +} diff --git a/Castle.Core/DynamicProxy/Internal/TypeUtil.cs b/Castle.Core/DynamicProxy/Internal/TypeUtil.cs new file mode 100644 index 0000000..63a1f2d --- /dev/null +++ b/Castle.Core/DynamicProxy/Internal/TypeUtil.cs @@ -0,0 +1,225 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Internal +{ + using System; + using System.Collections.Generic; + using System.Diagnostics; + using System.Reflection; + using System.Reflection.Emit; + + using Castle.DynamicProxy.Generators.Emitters; + + public static class TypeUtil + { + internal static bool IsNullableType(this Type type) + { + return type.IsGenericType && + type.GetGenericTypeDefinition() == typeof(Nullable<>); + } + + internal static FieldInfo[] GetAllFields(this Type type) + { + if (type == null) + { + throw new ArgumentNullException(nameof(type)); + } + + if (type.IsClass == false) + { + throw new ArgumentException(string.Format("Type {0} is not a class type. This method supports only classes", type)); + } + + var fields = new List(); + var currentType = type; + while (currentType != typeof(object)) + { + Debug.Assert(currentType != null); + var currentFields = currentType.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static); + fields.AddRange(currentFields); + currentType = currentType.BaseType; + } + + return fields.ToArray(); + } + + /// + /// Returns list of all unique interfaces implemented given types, including their base interfaces. + /// + internal static Type[] GetAllInterfaces(params Type[] types) + { + if (types == null) + { + return Type.EmptyTypes; + } + + var interfaces = new HashSet(); + for (var index = 0; index < types.Length; index++) + { + var type = types[index]; + if (type == null) + { + continue; + } + + if (type.IsInterface) + { + if (interfaces.Add(type) == false) + { + continue; + } + } + + var innerInterfaces = type.GetInterfaces(); + for (var i = 0; i < innerInterfaces.Length; i++) + { + var @interface = innerInterfaces[i]; + interfaces.Add(@interface); + } + } + + return Sort(interfaces); + } + + public static Type[] GetAllInterfaces(this Type type) // NOTE: also used by Windsor + { + return GetAllInterfaces(new[] { type }); + } + + + public static Type GetTypeOrNull(object target) + { + if (target == null) + { + return null; + } + return target.GetType(); + } + + internal static Type[] AsTypeArray(this GenericTypeParameterBuilder[] typeInfos) + { + Type[] types = new Type[typeInfos.Length]; + for (int i = 0; i < types.Length; i++) + { + types[i] = typeInfos[i]; + } + return types; + } + + internal static bool IsFinalizer(this MethodInfo methodInfo) + { + return string.Equals("Finalize", methodInfo.Name) && methodInfo.GetBaseDefinition().DeclaringType == typeof(object); + } + + internal static bool IsGetType(this MethodInfo methodInfo) + { + return methodInfo.DeclaringType == typeof(object) && string.Equals("GetType", methodInfo.Name, StringComparison.OrdinalIgnoreCase); + } + + internal static bool IsMemberwiseClone(this MethodInfo methodInfo) + { + return methodInfo.DeclaringType == typeof(object) && string.Equals("MemberwiseClone", methodInfo.Name, StringComparison.OrdinalIgnoreCase); + } + + internal static void SetStaticField(this Type type, string fieldName, BindingFlags additionalFlags, object value) + { + var flags = additionalFlags | BindingFlags.Static; + + FieldInfo field = type.GetField(fieldName, flags); + if (field == null) + { + throw new DynamicProxyException(string.Format( + "Could not find field named '{0}' on type {1}. This is likely a bug in DynamicProxy. Please report it.", + fieldName, type)); + } + + try + { + field.SetValue(null, value); + } + catch (MissingFieldException e) + { + throw new DynamicProxyException( + string.Format( + "Could not find field named '{0}' on type {1}. This is likely a bug in DynamicProxy. Please report it.", + fieldName, + type), e); + } + catch (TargetException e) + { + throw new DynamicProxyException( + string.Format( + "There was an error trying to set field named '{0}' on type {1}. This is likely a bug in DynamicProxy. Please report it.", + fieldName, + type), e); + } + catch (TargetInvocationException e) // yes, this is not documented in MSDN. Yay for documentation + { + if ((e.InnerException is TypeInitializationException) == false) + { + throw; + } + throw new DynamicProxyException( + string.Format( + "There was an error in static constructor on type {0}. This is likely a bug in DynamicProxy. Please report it.", + type), e); + } + } + + public static MemberInfo[] Sort(MemberInfo[] members) + { + var sortedMembers = new MemberInfo[members.Length]; + Array.Copy(members, sortedMembers, members.Length); + Array.Sort(sortedMembers, (l, r) => string.Compare(l.Name, r.Name, StringComparison.OrdinalIgnoreCase)); + return sortedMembers; + } + + /// + /// Checks whether the specified is a delegate type (i.e. a direct subclass of ). + /// + internal static bool IsDelegateType(this Type type) + { + return type.BaseType == typeof(MulticastDelegate); + } + + private static Type[] Sort(ICollection types) + { + var array = new Type[types.Count]; + types.CopyTo(array, 0); + //NOTE: is there a better, stable way to sort Types. We will need to revise this once we allow open generics + Array.Sort(array, TypeNameComparer.Instance); + // ^^^^^^^^^^^^^^^^^^^^^^^^^ + // Using a `IComparer` object instead of a `Comparison` delegate prevents + // an unnecessary level of indirection inside the framework (as the latter get + // wrapped as `IComparer` objects). + return array; + } + + private sealed class TypeNameComparer : IComparer + { + public static readonly TypeNameComparer Instance = new TypeNameComparer(); + + public int Compare(Type x, Type y) + { + // Comparing by `type.AssemblyQualifiedName` would give the same result, + // but it performs a hidden concatenation (and therefore string allocation) + // of `type.FullName` and `type.Assembly.FullName`. We can avoid this + // overhead by comparing the two properties separately. + int result = string.CompareOrdinal(x.FullName, y.FullName); + return result != 0 ? result : string.CompareOrdinal(x.Assembly.FullName, y.Assembly.FullName); + } + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/MixinData.cs b/Castle.Core/DynamicProxy/MixinData.cs new file mode 100644 index 0000000..2d26f51 --- /dev/null +++ b/Castle.Core/DynamicProxy/MixinData.cs @@ -0,0 +1,210 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy +{ + using System; + using System.Collections.Generic; + using System.Diagnostics; + using System.Linq; + using System.Reflection; + + using Castle.DynamicProxy.Generators; + using Castle.DynamicProxy.Internal; + + public class MixinData + { + private readonly Dictionary mixinPositions = new Dictionary(); + private readonly List mixinsImpl = new List(); + private int delegateMixinCount = 0; + + /// + /// Because we need to cache the types based on the mixed in mixins, we do the following here: + /// - Get all the mixin interfaces + /// - Sort them by full name + /// - Return them by position + /// + /// The idea is to have reproducible behavior for the case that mixins are registered in different orders. + /// This method is here because it is required + /// + public MixinData(IEnumerable mixinInstances) + { + if (mixinInstances != null) + { + var sortedMixedInterfaceTypes = new List(); + var interface2Mixin = new Dictionary(); + delegateMixinCount = 0; + + foreach (var mixin in mixinInstances) + { + Type[] mixinInterfaces; + object target; + if (mixin is Delegate) + { + ++delegateMixinCount; + mixinInterfaces = new[] { mixin.GetType() }; + target = mixin; + } + else if (mixin is Type delegateType && delegateType.IsDelegateType()) + { + ++delegateMixinCount; + mixinInterfaces = new[] { delegateType }; + target = null; + } + else + { + mixinInterfaces = mixin.GetType().GetInterfaces(); + target = mixin; + } + + foreach (var inter in mixinInterfaces) + { + sortedMixedInterfaceTypes.Add(inter); + + if (interface2Mixin.TryGetValue(inter, out var interMixin)) + { + string message; + if (interMixin != null) + { + message = string.Format( + "The list of mixins contains two mixins implementing the same interface '{0}': {1} and {2}. An interface cannot be added by more than one mixin.", + inter.FullName, + interMixin.GetType().Name, + mixin.GetType().Name); + } + else + { + Debug.Assert(inter.IsDelegateType()); + message = string.Format( + "The list of mixins already contains a mixin for delegate type '{0}'.", + inter.FullName); + } + throw new ArgumentException(message, nameof(mixinInstances)); + } + interface2Mixin[inter] = target; + } + } + + if (delegateMixinCount > 1) + { + // If at least two delegate mixins have been added, we need to ensure that + // the `Invoke` methods contributed by them don't have identical signatures: + var invokeMethods = new HashSet(); + foreach (var mixedInType in interface2Mixin.Keys) + { + if (mixedInType.IsDelegateType()) + { + var invokeMethod = mixedInType.GetMethod("Invoke"); + if (invokeMethods.Contains(invokeMethod, MethodSignatureComparer.Instance)) + { + throw new ArgumentException("The list of mixins contains at least two delegate mixins for the same delegate signature.", nameof(mixinInstances)); + } + invokeMethods.Add(invokeMethod); + } + } + } + + sortedMixedInterfaceTypes.Sort((x, y) => string.CompareOrdinal(x.FullName, y.FullName)); + + for (var i = 0; i < sortedMixedInterfaceTypes.Count; i++) + { + var mixinInterface = sortedMixedInterfaceTypes[i]; + var mixin = interface2Mixin[mixinInterface]; + + mixinPositions[mixinInterface] = i; + mixinsImpl.Add(mixin); + } + } + } + + public IEnumerable MixinInterfaces + { + get { return mixinPositions.Keys; } + } + + public IEnumerable Mixins + { + get { return mixinsImpl; } + } + + public bool ContainsMixin(Type mixinInterfaceType) + { + return mixinPositions.ContainsKey(mixinInterfaceType); + } + + // For two MixinData objects being regarded equal, only the sorted mixin types are considered, not the actual instances. + public override bool Equals(object obj) + { + if (ReferenceEquals(this, obj)) + { + return true; + } + + var other = obj as MixinData; + if (ReferenceEquals(other, null)) + { + return false; + } + + if (mixinsImpl.Count != other.mixinsImpl.Count) + { + return false; + } + + if (delegateMixinCount != other.delegateMixinCount) + { + return false; + } + + for (var i = 0; i < mixinsImpl.Count; ++i) + { + if (mixinsImpl[i]?.GetType() != other.mixinsImpl[i]?.GetType()) + { + return false; + } + } + + if (delegateMixinCount > 0) + { + var delegateMixinTypes = mixinPositions.Select(m => m.Key).Where(TypeUtil.IsDelegateType); + var otherDelegateMixinTypes = other.mixinPositions.Select(m => m.Key).Where(TypeUtil.IsDelegateType); + return Enumerable.SequenceEqual(delegateMixinTypes, otherDelegateMixinTypes); + } + + return true; + } + + // For two MixinData objects being regarded equal, only the mixin types are considered, not the actual instances. + public override int GetHashCode() + { + var hashCode = 0; + foreach (var mixinImplementation in mixinsImpl) + { + hashCode = unchecked(29 * hashCode + mixinImplementation?.GetType().GetHashCode() ?? 307); + } + + return hashCode; + } + + public object GetMixinInstance(Type mixinInterfaceType) + { + return mixinsImpl[mixinPositions[mixinInterfaceType]]; + } + + public int GetMixinPosition(Type mixinInterfaceType) + { + return mixinPositions[mixinInterfaceType]; + } + } +} diff --git a/Castle.Core/DynamicProxy/ModuleScope.cs b/Castle.Core/DynamicProxy/ModuleScope.cs new file mode 100644 index 0000000..b70b109 --- /dev/null +++ b/Castle.Core/DynamicProxy/ModuleScope.cs @@ -0,0 +1,539 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy +{ + using System; + using System.Collections.Generic; + using System.Diagnostics; + using System.IO; + using System.Reflection; + using System.Reflection.Emit; + using System.Resources; + using System.Threading; + + using Castle.Core.Internal; + using Castle.DynamicProxy.Generators; +#if FEATURE_SERIALIZATION + using Castle.DynamicProxy.Serialization; +#endif + + public class ModuleScope + { + /// + /// The default file name used when the assembly is saved using . + /// + public static readonly string DEFAULT_FILE_NAME = "CastleDynProxy2.dll"; + + /// + /// The default assembly (simple) name used for the assemblies generated by a instance. + /// + public static readonly string DEFAULT_ASSEMBLY_NAME = "DynamicProxyGenAssembly2"; + + private ModuleBuilder moduleBuilderWithStrongName; + private ModuleBuilder moduleBuilder; + + // The names to use for the generated assemblies and the paths (including the names) of their manifest modules + private readonly string strongAssemblyName; + private readonly string weakAssemblyName; + private readonly string strongModulePath; + private readonly string weakModulePath; + + // Keeps track of generated types + private readonly SynchronizedDictionary typeCache = new SynchronizedDictionary(); + + // Used to lock the module builder creation + private readonly object moduleLocker = new object(); + + // Specified whether the generated assemblies are intended to be saved + private readonly bool savePhysicalAssembly; + private readonly bool disableSignedModule; + private readonly INamingScope namingScope; + + /// + /// Initializes a new instance of the class; assemblies created by this instance will not be saved. + /// + public ModuleScope() : this(false, false) + { + } + + /// + /// Initializes a new instance of the class, allowing to specify whether the assemblies generated by this instance + /// should be saved. + /// + /// If set to true saves the generated module. + public ModuleScope(bool savePhysicalAssembly) + : this(savePhysicalAssembly, false) + { + } + + /// + /// Initializes a new instance of the class, allowing to specify whether the assemblies generated by this instance + /// should be saved. + /// + /// If set to true saves the generated module. + /// If set to true disables ability to generate signed module. This should be used in cases where ran under constrained permissions. + public ModuleScope(bool savePhysicalAssembly, bool disableSignedModule) + : this( + savePhysicalAssembly, disableSignedModule, DEFAULT_ASSEMBLY_NAME, DEFAULT_FILE_NAME, DEFAULT_ASSEMBLY_NAME, + DEFAULT_FILE_NAME) + { + } + + /// + /// Initializes a new instance of the class, allowing to specify whether the assemblies generated by this instance + /// should be saved and what simple names are to be assigned to them. + /// + /// If set to true saves the generated module. + /// If set to true disables ability to generate signed module. This should be used in cases where ran under constrained permissions. + /// The simple name of the strong-named assembly generated by this . + /// The path and file name of the manifest module of the strong-named assembly generated by this . + /// The simple name of the weak-named assembly generated by this . + /// The path and file name of the manifest module of the weak-named assembly generated by this . + public ModuleScope(bool savePhysicalAssembly, bool disableSignedModule, string strongAssemblyName, + string strongModulePath, + string weakAssemblyName, string weakModulePath) + : this( + savePhysicalAssembly, disableSignedModule, new NamingScope(), strongAssemblyName, strongModulePath, weakAssemblyName, + weakModulePath) + { + } + + /// + /// Initializes a new instance of the class, allowing to specify whether the assemblies generated by this instance + /// should be saved and what simple names are to be assigned to them. + /// + /// If set to true saves the generated module. + /// If set to true disables ability to generate signed module. This should be used in cases where ran under constrained permissions. + /// Naming scope used to provide unique names to generated types and their members (usually via sub-scopes). + /// The simple name of the strong-named assembly generated by this . + /// The path and file name of the manifest module of the strong-named assembly generated by this . + /// The simple name of the weak-named assembly generated by this . + /// The path and file name of the manifest module of the weak-named assembly generated by this . + internal ModuleScope(bool savePhysicalAssembly, bool disableSignedModule, INamingScope namingScope, + string strongAssemblyName, string strongModulePath, + string weakAssemblyName, string weakModulePath) + { + this.savePhysicalAssembly = savePhysicalAssembly; + this.disableSignedModule = disableSignedModule; + this.namingScope = namingScope; + this.strongAssemblyName = strongAssemblyName; + this.strongModulePath = strongModulePath; + this.weakAssemblyName = weakAssemblyName; + this.weakModulePath = weakModulePath; + } + + internal INamingScope NamingScope + { + get { return namingScope; } + } + + internal SynchronizedDictionary TypeCache => typeCache; + + /// + /// Gets the key pair used to sign the strong-named assembly generated by this . + /// + public static byte[] GetKeyPair() + { + using (var stream = typeof(ModuleScope).Assembly.GetManifestResourceStream("Castle.DynamicProxy.DynProxy.snk")) + { + if (stream == null) + { + throw new MissingManifestResourceException( + "Should have a Castle.DynamicProxy.DynProxy.snk as an embedded resource, so Dynamic Proxy could sign generated assembly"); + } + + var length = (int)stream.Length; + var keyPair = new byte[length]; + stream.Read(keyPair, 0, length); + return keyPair; + } + } + + /// + /// Gets the strong-named module generated by this scope, or if none has yet been generated. + /// + /// The strong-named module generated by this scope, or if none has yet been generated. + internal ModuleBuilder StrongNamedModule + { + get { return moduleBuilderWithStrongName; } + } + + /// + /// Gets the file name of the strongly named module generated by this scope. + /// + /// The file name of the strongly named module generated by this scope. + public string StrongNamedModuleName + { + get { return Path.GetFileName(strongModulePath); } + } + +#if FEATURE_ASSEMBLYBUILDER_SAVE + /// + /// Gets the directory where the strongly named module generated by this scope will be saved, or if the current directory + /// is used. + /// + /// The directory where the strongly named module generated by this scope will be saved when is called + /// (if this scope was created to save modules). + public string StrongNamedModuleDirectory + { + get + { + var directory = Path.GetDirectoryName(strongModulePath); + if (string.IsNullOrEmpty(directory)) + { + return null; + } + return directory; + } + } +#endif + + /// + /// Gets the weak-named module generated by this scope, or if none has yet been generated. + /// + /// The weak-named module generated by this scope, or if none has yet been generated. + internal ModuleBuilder WeakNamedModule + { + get { return moduleBuilder; } + } + + /// + /// Gets the file name of the weakly named module generated by this scope. + /// + /// The file name of the weakly named module generated by this scope. + public string WeakNamedModuleName + { + get { return Path.GetFileName(weakModulePath); } + } + +#if FEATURE_ASSEMBLYBUILDER_SAVE + /// + /// Gets the directory where the weakly named module generated by this scope will be saved, or if the current directory + /// is used. + /// + /// The directory where the weakly named module generated by this scope will be saved when is called + /// (if this scope was created to save modules). + public string WeakNamedModuleDirectory + { + get + { + var directory = Path.GetDirectoryName(weakModulePath); + if (directory == string.Empty) + { + return null; + } + return directory; + } + } +#endif + + /// + /// Gets the specified module generated by this scope, creating a new one if none has yet been generated. + /// + /// If set to true, a strong-named module is returned; otherwise, a weak-named module is returned. + /// A strong-named or weak-named module generated by this scope, as specified by the parameter. + internal ModuleBuilder ObtainDynamicModule(bool isStrongNamed) + { + if (isStrongNamed) + { + return ObtainDynamicModuleWithStrongName(); + } + + return ObtainDynamicModuleWithWeakName(); + } + + /// + /// Gets the strong-named module generated by this scope, creating a new one if none has yet been generated. + /// + /// A strong-named module generated by this scope. + internal ModuleBuilder ObtainDynamicModuleWithStrongName() + { + if (disableSignedModule) + { + throw new InvalidOperationException( + "Usage of signed module has been disabled. Use unsigned module or enable signed module."); + } + lock (moduleLocker) + { + if (moduleBuilderWithStrongName == null) + { + moduleBuilderWithStrongName = CreateModule(true); + } + return moduleBuilderWithStrongName; + } + } + + /// + /// Gets the weak-named module generated by this scope, creating a new one if none has yet been generated. + /// + /// A weak-named module generated by this scope. + internal ModuleBuilder ObtainDynamicModuleWithWeakName() + { + lock (moduleLocker) + { + if (moduleBuilder == null) + { + moduleBuilder = CreateModule(false); + } + return moduleBuilder; + } + } + + private ModuleBuilder CreateModule(bool signStrongName) + { + var assemblyName = GetAssemblyName(signStrongName); + var moduleName = signStrongName ? StrongNamedModuleName : WeakNamedModuleName; +#if FEATURE_APPDOMAIN + if (savePhysicalAssembly) + { + AssemblyBuilder assemblyBuilder; + try + { + assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly( + assemblyName, AssemblyBuilderAccess.RunAndSave, signStrongName ? StrongNamedModuleDirectory : WeakNamedModuleDirectory); + } + catch (ArgumentException e) + { + if (signStrongName == false && e.StackTrace.Contains("ComputePublicKey") == false) + { + // I have no idea what that could be + throw; + } + var message = string.Format( + "There was an error creating dynamic assembly for your proxies - you don't have permissions " + + "required to sign the assembly. To workaround it you can enforce generating non-signed assembly " + + "only when creating {0}. Alternatively ensure that your account has all the required permissions.", + GetType()); + throw new ArgumentException(message, e); + } + var module = assemblyBuilder.DefineDynamicModule(moduleName, moduleName, false); + return module; + } + else +#endif + { +#if FEATURE_APPDOMAIN + var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly( + assemblyName, AssemblyBuilderAccess.Run); +#else + var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); +#endif + + var module = assemblyBuilder.DefineDynamicModule(moduleName); + return module; + } + } + + private AssemblyName GetAssemblyName(bool signStrongName) + { + var assemblyName = new AssemblyName { + Name = signStrongName ? strongAssemblyName : weakAssemblyName + }; + + if (signStrongName) + { +#if FEATURE_ASSEMBLYBUILDER_SAVE + assemblyName.KeyPair = new StrongNameKeyPair(GetKeyPair()); +#else + assemblyName.SetPublicKey(InternalsVisible.DynamicProxyGenAssembly2PublicKey); +#endif + } + + return assemblyName; + } + +#if FEATURE_ASSEMBLYBUILDER_SAVE + /// + /// Saves the generated assembly with the name and directory information given when this instance was created (or with + /// the and current directory if none was given). + /// + /// + /// + /// This method stores the generated assembly in the directory passed as part of the module information specified when this instance was + /// constructed (if any, else the current directory is used). If both a strong-named and a weak-named assembly + /// have been generated, it will throw an exception; in this case, use the overload. + /// + /// + /// If this was created without indicating that the assembly should be saved, this method does nothing. + /// + /// + /// Both a strong-named and a weak-named assembly have been generated. + /// The path of the generated assembly file, or null if no file has been generated. + public string SaveAssembly() + { + if (!savePhysicalAssembly) + { + return null; + } + + if (StrongNamedModule != null && WeakNamedModule != null) + { + throw new InvalidOperationException("Both a strong-named and a weak-named assembly have been generated."); + } + + if (StrongNamedModule != null) + { + return SaveAssembly(true); + } + + if (WeakNamedModule != null) + { + return SaveAssembly(false); + } + + return null; + } + + /// + /// Saves the specified generated assembly with the name and directory information given when this instance was created + /// (or with the and current directory if none was given). + /// + /// True if the generated assembly with a strong name should be saved (see ); + /// false if the generated assembly without a strong name should be saved (see . + /// + /// + /// This method stores the specified generated assembly in the directory passed as part of the module information specified when this instance was + /// constructed (if any, else the current directory is used). + /// + /// + /// If this was created without indicating that the assembly should be saved, this method does nothing. + /// + /// + /// No assembly has been generated that matches the parameter. + /// + /// The path of the generated assembly file, or null if no file has been generated. + public string SaveAssembly(bool strongNamed) + { + if (!savePhysicalAssembly) + { + return null; + } + + AssemblyBuilder assemblyBuilder; + string assemblyFileName; + string assemblyFilePath; + + if (strongNamed) + { + if (StrongNamedModule == null) + { + throw new InvalidOperationException("No strong-named assembly has been generated."); + } + assemblyBuilder = (AssemblyBuilder)StrongNamedModule.Assembly; + assemblyFileName = StrongNamedModuleName; + assemblyFilePath = StrongNamedModule.FullyQualifiedName; + } + else + { + if (WeakNamedModule == null) + { + throw new InvalidOperationException("No weak-named assembly has been generated."); + } + assemblyBuilder = (AssemblyBuilder)WeakNamedModule.Assembly; + assemblyFileName = WeakNamedModuleName; + assemblyFilePath = WeakNamedModule.FullyQualifiedName; + } + + if (File.Exists(assemblyFilePath)) + { + File.Delete(assemblyFilePath); + } + +#if FEATURE_SERIALIZATION + AddCacheMappings(assemblyBuilder); +#endif + + assemblyBuilder.Save(assemblyFileName); + return assemblyFilePath; + } +#endif + +#if FEATURE_SERIALIZATION + private void AddCacheMappings(AssemblyBuilder builder) + { + var mappings = new Dictionary(); + + typeCache.ForEach((key, value) => + { + // NOTE: using == returns invalid results. + // we need to use Equals here for it to work properly + if (builder.Equals(value.Assembly)) + { + mappings.Add(key, value.FullName); + } + }); + + CacheMappingsAttribute.ApplyTo(builder, mappings); + } + + /// + /// Loads the generated types from the given assembly into this 's cache. + /// + /// The assembly to load types from. This assembly must have been saved via or + /// , or it must have the manually applied. + /// + /// This method can be used to load previously generated and persisted proxy types from disk into this scope's type cache, e.g. in order + /// to avoid the performance hit associated with proxy generation. + /// + public void LoadAssemblyIntoCache(Assembly assembly) + { + if (assembly == null) + { + throw new ArgumentNullException(nameof(assembly)); + } + + var cacheMappings = + (CacheMappingsAttribute[])assembly.GetCustomAttributes(typeof(CacheMappingsAttribute), false); + + if (cacheMappings.Length == 0) + { + var message = string.Format( + "The given assembly '{0}' does not contain any cache information for generated types.", + assembly.FullName); + throw new ArgumentException(message, nameof(assembly)); + } + + foreach (var mapping in cacheMappings[0].GetDeserializedMappings()) + { + var loadedType = assembly.GetType(mapping.Value); + + if (loadedType != null) + { + typeCache.AddOrUpdateWithoutTakingLock(mapping.Key, loadedType); + } + } + } +#endif + + internal TypeBuilder DefineType(bool inSignedModulePreferably, string name, TypeAttributes flags) + { + var module = ObtainDynamicModule(disableSignedModule == false && inSignedModulePreferably); + return module.DefineType(name, flags); + } + } +} diff --git a/Castle.Core/DynamicProxy/PersistentProxyBuilder.cs b/Castle.Core/DynamicProxy/PersistentProxyBuilder.cs new file mode 100644 index 0000000..c874f9b --- /dev/null +++ b/Castle.Core/DynamicProxy/PersistentProxyBuilder.cs @@ -0,0 +1,49 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#if FEATURE_ASSEMBLYBUILDER_SAVE + +namespace Castle.DynamicProxy +{ + /// + /// ProxyBuilder that persists the generated type. + /// + /// + /// The saved assembly contains just the last generated type. + /// + public class PersistentProxyBuilder : DefaultProxyBuilder + { + /// + /// Initializes a new instance of the class. + /// + public PersistentProxyBuilder() : base(new ModuleScope(true)) + { + } + + /// + /// Saves the generated assembly to a physical file. Note that this renders the unusable. + /// + /// The path of the generated assembly file, or null if no assembly has been generated. + /// + /// This method does not support saving multiple files. If both a signed and an unsigned module have been generated, use the + /// respective methods of the . + /// + public string SaveAssembly() + { + return ModuleScope.SaveAssembly(); + } + } +} + +#endif \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/ProxyGenerationOptions.cs b/Castle.Core/DynamicProxy/ProxyGenerationOptions.cs new file mode 100644 index 0000000..515de4b --- /dev/null +++ b/Castle.Core/DynamicProxy/ProxyGenerationOptions.cs @@ -0,0 +1,353 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Reflection; + using System.Reflection.Emit; +#if FEATURE_SERIALIZATION + using System.Runtime.Serialization; +#endif + + using Castle.DynamicProxy.Internal; + + /// + /// allows customization of the behavior of proxies created by + /// an (or proxy types generated by an ). + /// + /// You should not modify an instance of once it has been + /// used to create a proxy (or proxy type). + /// + /// +#if FEATURE_SERIALIZATION + [Serializable] +#endif + public class ProxyGenerationOptions +#if FEATURE_SERIALIZATION + : ISerializable +#endif + { + public static readonly ProxyGenerationOptions Default = new ProxyGenerationOptions(); + + private List mixins; + private readonly IList additionalAttributes = new List(); + +#if FEATURE_SERIALIZATION + [NonSerialized] +#endif + private MixinData mixinData; // this is calculated dynamically on proxy type creation + + /// + /// Initializes a new instance of the class. + /// + /// The hook. + public ProxyGenerationOptions(IProxyGenerationHook hook) + { + BaseTypeForInterfaceProxy = typeof(object); + Hook = hook; + } + + /// + /// Initializes a new instance of the class. + /// + public ProxyGenerationOptions() + : this(new AllMethodsHook()) + { + } + +#if FEATURE_SERIALIZATION + private ProxyGenerationOptions(SerializationInfo info, StreamingContext context) + { + Hook = (IProxyGenerationHook)info.GetValue("hook", typeof(IProxyGenerationHook)); + Selector = (IInterceptorSelector)info.GetValue("selector", typeof(IInterceptorSelector)); + mixins = (List)info.GetValue("mixins", typeof(List)); + BaseTypeForInterfaceProxy = Type.GetType(info.GetString("baseTypeForInterfaceProxy.AssemblyQualifiedName")); + } +#endif + + public void Initialize() + { + if (mixinData == null) + { + try + { + mixinData = new MixinData(mixins); + } + catch (ArgumentException ex) + { + throw new InvalidOperationException( + "There is a problem with the mixins added to this ProxyGenerationOptions. See the inner exception for details.", ex); + } + } + } + +#if FEATURE_SERIALIZATION + public void GetObjectData(SerializationInfo info, StreamingContext context) + { + info.AddValue("hook", Hook); + info.AddValue("selector", Selector); + info.AddValue("mixins", mixins); + info.AddValue("baseTypeForInterfaceProxy.AssemblyQualifiedName", BaseTypeForInterfaceProxy.AssemblyQualifiedName); + } +#endif + + /// + /// Gets or sets the that should be used during proxy type + /// generation. Defaults to an instance of . + /// + /// You should not modify this property once this instance + /// has been used to create a proxy. + /// + /// + public IProxyGenerationHook Hook { get; set; } + + /// + /// Gets or sets the that should be used by created proxies + /// to determine which interceptors to use for an interception. If set to + /// (which is the default), created proxies will not use any selector. + /// + /// You should not modify this property once this instance + /// has been used to create a proxy. + /// + /// + public IInterceptorSelector Selector { get; set; } + + /// + /// Gets or sets the class type from which generated interface proxy types will be derived. + /// Defaults to (). + /// + /// You should not modify this property once this instance + /// has been used to create a proxy. + /// + /// + public Type BaseTypeForInterfaceProxy { get; set; } + + /// + /// Gets the collection of additional custom attributes that will be put on generated proxy types. + /// This collection is initially empty. + /// + /// You should not modify this collection once this instance + /// has been used to create a proxy. + /// + /// + public IList AdditionalAttributes + { + get { return additionalAttributes; } + } + + public MixinData MixinData + { + get + { + if (mixinData == null) + { + throw new InvalidOperationException("Call Initialize before accessing the MixinData property."); + } + return mixinData; + } + } + + /// + /// Adds a delegate type to the list of mixins that will be added to generated proxies. + /// That is, generated proxies will have a `Invoke` method with a signature matching that + /// of the specified . + /// + /// You should not call this method once this instance + /// has been used to create a proxy. + /// + /// + /// The delegate type whose `Invoke` method should be reproduced in generated proxies. + /// is . + /// is not a delegate type. + public void AddDelegateTypeMixin(Type delegateType) + { + if (delegateType == null) throw new ArgumentNullException(nameof(delegateType)); + if (!delegateType.IsDelegateType()) throw new ArgumentException("Type must be a delegate type.", nameof(delegateType)); + + AddMixinImpl(delegateType); + } + + /// + /// Adds a delegate to be mixed into generated proxies. The + /// will act as the target for calls to a `Invoke` method with a signature matching that + /// of the delegate. + /// + /// You should not call this method once this instance + /// has been used to create a proxy. + /// + /// + /// The delegate that should act as the target for calls to `Invoke` methods with a matching signature. + /// is . + public void AddDelegateMixin(Delegate @delegate) + { + if (@delegate == null) throw new ArgumentNullException(nameof(@delegate)); + + AddMixinImpl(@delegate); + } + + /// + /// Mixes the interfaces implemented by the specified object into + /// created proxies, and uses as the target for these mixed-in interfaces. + /// + /// You should not call this method once this instance + /// has been used to create a proxy. + /// + /// + /// The object that should act as the target for all of its implemented interfaces' methods. + /// is . + /// is an instance of . + public void AddMixinInstance(object instance) + { + if (instance == null) throw new ArgumentNullException(nameof(instance)); + if (instance is Type) throw new ArgumentException("You may not mix in types using this method.", nameof(instance)); + + AddMixinImpl(instance); + } + + private void AddMixinImpl(object instanceOrType) + { + if (mixins == null) + { + mixins = new List(); + } + + mixins.Add(instanceOrType); + mixinData = null; + } + + public object[] MixinsAsArray() + { + if (mixins == null) + { + return new object[0]; + } + + return mixins.ToArray(); + } + + public bool HasMixins + { + get { return mixins != null && mixins.Count != 0; } + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(this, obj)) + { + return true; + } + + var proxyGenerationOptions = obj as ProxyGenerationOptions; + if (ReferenceEquals(proxyGenerationOptions, null)) + { + return false; + } + + // ensure initialization before accessing MixinData + Initialize(); + proxyGenerationOptions.Initialize(); + + if (!Equals(Hook, proxyGenerationOptions.Hook)) + { + return false; + } + if (!Equals(Selector == null, proxyGenerationOptions.Selector == null)) + { + return false; + } + if (!Equals(MixinData, proxyGenerationOptions.MixinData)) + { + return false; + } + if (!Equals(BaseTypeForInterfaceProxy, proxyGenerationOptions.BaseTypeForInterfaceProxy)) + { + return false; + } + if (!HasEquivalentAdditionalAttributes(proxyGenerationOptions)) + { + return false; + } + return true; + } + + public override int GetHashCode() + { + // ensure initialization before accessing MixinData + Initialize(); + + var result = Hook != null ? Hook.GetType().GetHashCode() : 0; + result = 29*result + (Selector != null ? 1 : 0); + result = 29*result + MixinData.GetHashCode(); + result = 29*result + (BaseTypeForInterfaceProxy != null ? BaseTypeForInterfaceProxy.GetHashCode() : 0); + result = 29*result + GetAdditionalAttributesHashCode(); + return result; + } + + private int GetAdditionalAttributesHashCode() + { + var result = 0; + for (var i = 0; i < additionalAttributes.Count; i++) + { + if (additionalAttributes[i] != null) + { + // simply add since order does not matter + result += additionalAttributes[i].GetHashCode(); + } + } + + return result; + } + + private bool HasEquivalentAdditionalAttributes(ProxyGenerationOptions other) + { + var listA = additionalAttributes; + var listB = other.additionalAttributes; + + if (listA.Count != listB.Count) + { + return false; + } + + // copy contents to another list so that contents can be removed as they are found, + // in order to consider duplicates + var listBAvailableContents = listB.ToList(); + + // order is not important, just make sure that each entry in A is also found in B + for (var i = 0; i < listA.Count; i++) + { + var found = false; + + for (var j = 0; j < listBAvailableContents.Count; j++) + { + if (Equals(listA[i], listBAvailableContents[j])) + { + found = true; + listBAvailableContents.RemoveAt(j); + break; + } + } + + if (!found) + { + return false; + } + } + + return true; + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/ProxyGenerator.cs b/Castle.Core/DynamicProxy/ProxyGenerator.cs new file mode 100644 index 0000000..019b230 --- /dev/null +++ b/Castle.Core/DynamicProxy/ProxyGenerator.cs @@ -0,0 +1,1564 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy +{ + using System; + using System.Collections.Generic; + using System.Diagnostics; + using System.Reflection; + using System.Runtime.InteropServices; + using System.Text; + + using Castle.Core.Internal; + using Castle.Core.Logging; + using Castle.DynamicProxy.Generators; + + /// + /// Provides proxy objects for classes and interfaces. + /// + [CLSCompliant(true)] + public class ProxyGenerator : IProxyGenerator + { + private ILogger logger = NullLogger.Instance; + private readonly IProxyBuilder proxyBuilder; + + /// + /// Initializes a new instance of the class. + /// + /// Proxy types builder. + public ProxyGenerator(IProxyBuilder builder) + { + proxyBuilder = builder; + + Logger = NullLogger.Instance; + } + + /// + /// Initializes a new instance of the class. + /// + public ProxyGenerator() : this(new DefaultProxyBuilder()) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// If true forces all types to be generated into an unsigned module. + public ProxyGenerator(bool disableSignedModule) : this(new DefaultProxyBuilder(new ModuleScope(false, disableSignedModule))) + { + } + + /// + /// Gets or sets the that this log to. + /// + public ILogger Logger + { + get { return logger; } + set + { + logger = value; + proxyBuilder.Logger = value; + } + } + + /// + /// Gets the proxy builder instance used to generate proxy types. + /// + /// The proxy builder. + public IProxyBuilder ProxyBuilder + { + get { return proxyBuilder; } + } + + /// + /// Creates proxy object intercepting calls to members of interface on object with given . + /// + /// Type of the interface implemented by which will be proxied. + /// The target object, calls to which will be intercepted. + /// The interceptors called during the invocation of proxied methods. + /// Object proxying calls to members of on object. + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given array is a null reference (Nothing in Visual Basic). + /// Thrown when given is not an interface type. + /// Thrown when no default constructor exists on actual type of object. + /// Thrown when default constructor of actual type of throws an exception. + /// + /// This method generates new proxy type for each type of , which affects performance. If you don't want to proxy types differently depending on the type of the target + /// use method. + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + public TInterface CreateInterfaceProxyWithTarget(TInterface target, params IInterceptor[] interceptors) + where TInterface : class + { + // NOTE: we don't need to document exception case where interface type is null, since it can never be for a generic method. + // If we leave target as being of type TInterface we also have covered exception where target does not implement TInterface. + + // NOTE: Can any other Activator.CreateInstance exception be thrown in this context? + + return + (TInterface) + CreateInterfaceProxyWithTarget(typeof(TInterface), target, ProxyGenerationOptions.Default, interceptors); + } + + /// + /// Creates proxy object intercepting calls to members of interface on object with given . + /// + /// Type of the interface implemented by which will be proxied. + /// The target object, calls to which will be intercepted. + /// The proxy generation options used to influence generated proxy type and object. + /// The interceptors called during the invocation of proxied methods. + /// + /// Object proxying calls to members of on object. + /// + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given array is a null reference (Nothing in Visual Basic). + /// Thrown when given is not an interface type. + /// Thrown when no default constructor exists on actual type of object. + /// Thrown when default constructor of actual type of throws an exception. + /// + /// This method generates new proxy type for each type of , which affects performance. If you don't want to proxy types differently depending on the type of the target + /// use method. + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + public TInterface CreateInterfaceProxyWithTarget(TInterface target, ProxyGenerationOptions options, + params IInterceptor[] interceptors) + where TInterface : class + { + return (TInterface)CreateInterfaceProxyWithTarget(typeof(TInterface), target, options, interceptors); + } + + /// + /// Creates proxy object intercepting calls to members of interface on object with given . + /// + /// Type of the interface implemented by which will be proxied. + /// The target object, calls to which will be intercepted. + /// The interceptors called during the invocation of proxied methods. + /// + /// Object proxying calls to members of type on object. + /// + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given array is a null reference (Nothing in Visual Basic). + /// Thrown when given is a generic type definition. + /// Thrown when given is not an interface type. + /// Thrown when given does not implement interface. + /// Thrown when no default constructor exists on actual type of object. + /// Thrown when default constructor of actual type of throws an exception. + /// + /// This method generates new proxy type for each type of , which affects performance. If you don't want to proxy types differently depending on the type of the target + /// use method. + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + public object CreateInterfaceProxyWithTarget(Type interfaceToProxy, object target, params IInterceptor[] interceptors) + { + return CreateInterfaceProxyWithTarget(interfaceToProxy, target, ProxyGenerationOptions.Default, interceptors); + } + + /// + /// Creates proxy object intercepting calls to members of interface on object with given . + /// + /// Type of the interface implemented by which will be proxied. + /// The target object, calls to which will be intercepted. + /// The proxy generation options used to influence generated proxy type and object. + /// The interceptors called during the invocation of proxied methods. + /// + /// Object proxying calls to members of type on object. + /// + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given array is a null reference (Nothing in Visual Basic). + /// Thrown when given is a generic type definition. + /// Thrown when given is not an interface type. + /// Thrown when given does not implement interface. + /// Thrown when no default constructor exists on actual type of object. + /// Thrown when default constructor of actual type of throws an exception. + /// + /// This method generates new proxy type for each type of , which affects performance. If you don't want to proxy types differently depending on the type of the target + /// use method. + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + public object CreateInterfaceProxyWithTarget(Type interfaceToProxy, object target, ProxyGenerationOptions options, + params IInterceptor[] interceptors) + { + return CreateInterfaceProxyWithTarget(interfaceToProxy, null, target, options, interceptors); + } + + /// + /// Creates proxy object intercepting calls to members of interface on object with given . + /// + /// Type of the interface implemented by which will be proxied. + /// The target object, calls to which will be intercepted. + /// Additional interface types. Calls to their members will be proxied as well. + /// The interceptors called during the invocation of proxied methods. + /// + /// Object proxying calls to members of and types on object. + /// + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given array is a null reference (Nothing in Visual Basic). + /// Thrown when given or any of is a generic type definition. + /// Thrown when given is not an interface type. + /// Thrown when given does not implement interface. + /// Thrown when no default constructor exists on actual type of object. + /// Thrown when default constructor of actual type of throws an exception. + /// + /// This method generates new proxy type for each type of , which affects performance. If you don't want to proxy types differently depending on the type of the target + /// use method. + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + public object CreateInterfaceProxyWithTarget(Type interfaceToProxy, Type[] additionalInterfacesToProxy, object target, + params IInterceptor[] interceptors) + { + return CreateInterfaceProxyWithTarget(interfaceToProxy, additionalInterfacesToProxy, target, + ProxyGenerationOptions.Default, interceptors); + } + + /// + /// Creates proxy object intercepting calls to members of interface on object with given . + /// + /// Type of the interface implemented by which will be proxied. + /// The target object, calls to which will be intercepted. + /// The proxy generation options used to influence generated proxy type and object. + /// Additional interface types. Calls to their members will be proxied as well. + /// The interceptors called during the invocation of proxied methods. + /// + /// Object proxying calls to members of and types on object. + /// + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given array is a null reference (Nothing in Visual Basic). + /// Thrown when given or any of is a generic type definition. + /// Thrown when given is not an interface type. + /// Thrown when given does not implement interface. + /// Thrown when no default constructor exists on actual type of object. + /// Thrown when default constructor of actual type of throws an exception. + /// + /// This method generates new proxy type for each type of , which affects performance. If you don't want to proxy types differently depending on the type of the target + /// use method. + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + public virtual object CreateInterfaceProxyWithTarget(Type interfaceToProxy, Type[] additionalInterfacesToProxy, + object target, + ProxyGenerationOptions options, + params IInterceptor[] interceptors) + { + if (interfaceToProxy == null) + { + throw new ArgumentNullException(nameof(interfaceToProxy)); + } + if (target == null) + { + throw new ArgumentNullException(nameof(target)); + } + if (interceptors == null) + { + throw new ArgumentNullException(nameof(interceptors)); + } + + if (!interfaceToProxy.IsInterface) + { + throw new ArgumentException("Specified type is not an interface", nameof(interfaceToProxy)); + } + + var targetType = target.GetType(); + if (!interfaceToProxy.IsAssignableFrom(targetType)) + { + throw new ArgumentException("Target does not implement interface " + interfaceToProxy.FullName, nameof(target)); + } + + CheckNotGenericTypeDefinition(interfaceToProxy, nameof(interfaceToProxy)); + CheckNotGenericTypeDefinitions(additionalInterfacesToProxy, nameof(additionalInterfacesToProxy)); + + var generatedType = CreateInterfaceProxyTypeWithTarget(interfaceToProxy, additionalInterfacesToProxy, targetType, + options); + + var arguments = GetConstructorArguments(target, interceptors, options); + return Activator.CreateInstance(generatedType, arguments.ToArray()); + } + + protected List GetConstructorArguments(object target, IInterceptor[] interceptors, + ProxyGenerationOptions options) + { + // create constructor arguments (initialized with mixin implementations, interceptors and target type constructor arguments) + var arguments = new List(options.MixinData.Mixins) { interceptors, target }; + if (options.Selector != null) + { + arguments.Add(options.Selector); + } + return arguments; + } + + /// + /// Creates proxy object intercepting calls to members of interface on object with given . + /// Interceptors can use interface to provide other target for method invocation than default . + /// + /// Type of the interface implemented by which will be proxied. + /// The target object, calls to which will be intercepted. + /// The interceptors called during the invocation of proxied methods. + /// + /// Object proxying calls to members of type on object or alternative implementation swapped at runtime by an interceptor. + /// + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given array is a null reference (Nothing in Visual Basic). + /// Thrown when given is a generic type definition. + /// Thrown when given is not an interface type. + /// Thrown when given does not implement interface. + /// Thrown when no default constructor exists on actual type of object. + /// Thrown when default constructor of actual type of throws an exception. + /// + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + public object CreateInterfaceProxyWithTargetInterface(Type interfaceToProxy, object target, + params IInterceptor[] interceptors) + { + return CreateInterfaceProxyWithTargetInterface(interfaceToProxy, target, ProxyGenerationOptions.Default, interceptors); + } + + /// + /// Creates proxy object intercepting calls to members of interface on object with given . + /// Interceptors can use interface to provide other target for method invocation than default . + /// + /// Type of the interface implemented by which will be proxied. + /// The target object, calls to which will be intercepted. + /// The interceptors called during the invocation of proxied methods. + /// + /// Object proxying calls to members of type on object or alternative implementation swapped at runtime by an interceptor. + /// + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given array is a null reference (Nothing in Visual Basic). + /// Thrown when given is not an interface type. + /// Thrown when no default constructor exists on actual type of object. + /// Thrown when default constructor of actual type of throws an exception. + /// + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + public TInterface CreateInterfaceProxyWithTargetInterface(TInterface target, + params IInterceptor[] interceptors) + where TInterface : class + { + return (TInterface)CreateInterfaceProxyWithTargetInterface(typeof(TInterface), + target, + ProxyGenerationOptions.Default, + interceptors); + } + + /// + /// Creates proxy object intercepting calls to members of interface on object with given . + /// Interceptors can use interface to provide other target for method invocation than default . + /// + /// Type of the interface implemented by which will be proxied. + /// The target object, calls to which will be intercepted. + /// The proxy generation options used to influence generated proxy type and object. + /// The interceptors called during the invocation of proxied methods. + /// + /// Object proxying calls to members of type on object or alternative implementation swapped at runtime by an interceptor. + /// + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given array is a null reference (Nothing in Visual Basic). + /// Thrown when given is not an interface type. + /// Thrown when no default constructor exists on actual type of object. + /// Thrown when default constructor of actual type of throws an exception. + /// + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + public TInterface CreateInterfaceProxyWithTargetInterface(TInterface target, + ProxyGenerationOptions options, + params IInterceptor[] interceptors) + where TInterface : class + { + return (TInterface)CreateInterfaceProxyWithTargetInterface(typeof(TInterface), + target, + options, + interceptors); + } + + /// + /// Creates proxy object intercepting calls to members of interface on object with given . + /// Interceptors can use interface to provide other target for method invocation than default . + /// + /// Type of the interface implemented by which will be proxied. + /// The target object, calls to which will be intercepted. + /// Additional interface types. Calls to their members will be proxied as well. + /// The interceptors called during the invocation of proxied methods. + /// + /// Object proxying calls to members of and types on object or alternative implementation swapped at runtime by an interceptor. + /// + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given array is a null reference (Nothing in Visual Basic). + /// Thrown when given or any of is a generic type definition. + /// Thrown when given is not an interface type. + /// Thrown when given does not implement interface. + /// Thrown when no default constructor exists on actual type of object. + /// Thrown when default constructor of actual type of throws an exception. + /// + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + public object CreateInterfaceProxyWithTargetInterface(Type interfaceToProxy, Type[] additionalInterfacesToProxy, + object target, params IInterceptor[] interceptors) + { + return CreateInterfaceProxyWithTargetInterface(interfaceToProxy, additionalInterfacesToProxy, target, + ProxyGenerationOptions.Default, interceptors); + } + + /// + /// Creates proxy object intercepting calls to members of interface on object with given . + /// Interceptors can use interface to provide other target for method invocation than default . + /// + /// Type of the interface implemented by which will be proxied. + /// The target object, calls to which will be intercepted. + /// The proxy generation options used to influence generated proxy type and object. + /// The interceptors called during the invocation of proxied methods. + /// + /// Object proxying calls to members of type on object or alternative implementation swapped at runtime by an interceptor. + /// + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given array is a null reference (Nothing in Visual Basic). + /// Thrown when given is a generic type definition. + /// Thrown when given is not an interface type. + /// Thrown when given does not implement interface. + /// Thrown when no default constructor exists on actual type of object. + /// Thrown when default constructor of actual type of throws an exception. + /// + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + public object CreateInterfaceProxyWithTargetInterface(Type interfaceToProxy, object target, + ProxyGenerationOptions options, + params IInterceptor[] interceptors) + { + return CreateInterfaceProxyWithTargetInterface(interfaceToProxy, null, target, options, interceptors); + } + + /// + /// Creates proxy object intercepting calls to members of interface on object with given . + /// Interceptors can use interface to provide other target for method invocation than default . + /// + /// Type of the interface implemented by which will be proxied. + /// The target object, calls to which will be intercepted. + /// The proxy generation options used to influence generated proxy type and object. + /// Additional interface types. Calls to their members will be proxied as well. + /// The interceptors called during the invocation of proxied methods. + /// + /// Object proxying calls to members of and types on object or alternative implementation swapped at runtime by an interceptor. + /// + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given array is a null reference (Nothing in Visual Basic). + /// Thrown when given or any of is a generic type definition. + /// Thrown when given is not an interface type. + /// Thrown when given does not implement interface. + /// Thrown when no default constructor exists on actual type of object. + /// Thrown when default constructor of actual type of throws an exception. + /// + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + public virtual object CreateInterfaceProxyWithTargetInterface(Type interfaceToProxy, + Type[] additionalInterfacesToProxy, + object target, ProxyGenerationOptions options, + params IInterceptor[] interceptors) + { + //TODO: add to xml comments to show how to use IChangeProxyTarget + + if (interfaceToProxy == null) + { + throw new ArgumentNullException(nameof(interfaceToProxy)); + } + // In the case of a transparent proxy, the call to IsInstanceOfType was executed on the real object. + if (target != null && interfaceToProxy.IsInstanceOfType(target) == false) + { + throw new ArgumentException("Target does not implement interface " + interfaceToProxy.FullName, nameof(target)); + } + if (interceptors == null) + { + throw new ArgumentNullException(nameof(interceptors)); + } + + if (!interfaceToProxy.IsInterface) + { + throw new ArgumentException("Specified type is not an interface", nameof(interfaceToProxy)); + } + + if (target != null) + { + if (Marshal.IsComObject(target)) + { + var interfaceId = interfaceToProxy.GUID; + if (interfaceId != Guid.Empty) + { + var iUnknown = Marshal.GetIUnknownForObject(target); // Increment the reference count + var interfacePointer = IntPtr.Zero; + var result = Marshal.QueryInterface(iUnknown, ref interfaceId, out interfacePointer); // Increment the reference count + var isInterfacePointerNull = interfacePointer == IntPtr.Zero; + Marshal.Release(iUnknown); // Decrement the reference count + if (!isInterfacePointerNull) + { + Marshal.Release(interfacePointer); // Decrement the reference count + } + + if (result == 0 && isInterfacePointerNull) + { + throw new ArgumentException("Target COM object does not implement interface " + interfaceToProxy.FullName, + nameof(target)); + } + } + } + } + + CheckNotGenericTypeDefinition(interfaceToProxy, nameof(interfaceToProxy)); + CheckNotGenericTypeDefinitions(additionalInterfacesToProxy, nameof(additionalInterfacesToProxy)); + + var generatedType = CreateInterfaceProxyTypeWithTargetInterface(interfaceToProxy, additionalInterfacesToProxy, + options); + var arguments = GetConstructorArguments(target, interceptors, options); + return Activator.CreateInstance(generatedType, arguments.ToArray()); + } + + /// + /// Creates proxy object intercepting calls to members of interface on target object generated at runtime with given . + /// + /// Type of the interface which will be proxied. + /// The interceptors called during the invocation of proxied methods. + /// + /// Object proxying calls to members of types on generated target object. + /// + /// Thrown when given array is a null reference (Nothing in Visual Basic). + /// Thrown when given is not an interface type. + /// + /// Since this method uses an empty-shell implementation of interfaces to proxy generated at runtime, the actual implementation of proxied methods must be provided by given implementations. + /// They are responsible for setting return value (and out parameters) on proxied methods. It is also illegal for an interceptor to call , since there's no actual implementation to proceed with. + /// As a result of that also at least one implementation must be provided. + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + public TInterface CreateInterfaceProxyWithoutTarget(IInterceptor interceptor) + where TInterface : class + { + return (TInterface)CreateInterfaceProxyWithoutTarget(typeof(TInterface), interceptor); + } + + /// + /// Creates proxy object intercepting calls to members of interface on target object generated at runtime with given . + /// + /// Type of the interface which will be proxied. + /// The interceptors called during the invocation of proxied methods. + /// + /// Object proxying calls to members of types on generated target object. + /// + /// Thrown when given array is a null reference (Nothing in Visual Basic). + /// Thrown when given is not an interface type. + /// + /// Since this method uses an empty-shell implementation of interfaces to proxy generated at runtime, the actual implementation of proxied methods must be provided by given implementations. + /// They are responsible for setting return value (and out parameters) on proxied methods. It is also illegal for an interceptor to call , since there's no actual implementation to proceed with. + /// As a result of that also at least one implementation must be provided. + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + public TInterface CreateInterfaceProxyWithoutTarget(params IInterceptor[] interceptors) + where TInterface : class + { + return (TInterface)CreateInterfaceProxyWithoutTarget(typeof(TInterface), interceptors); + } + + /// + /// Creates proxy object intercepting calls to members of interface on target object generated at runtime with given . + /// + /// Type of the interface which will be proxied. + /// The proxy generation options used to influence generated proxy type and object. + /// The interceptors called during the invocation of proxied methods. + /// + /// Object proxying calls to members of types on generated target object. + /// + /// Thrown when given array is a null reference (Nothing in Visual Basic). + /// Thrown when given is not an interface type. + /// + /// Since this method uses an empty-shell implementation of interfaces to proxy generated at runtime, the actual implementation of proxied methods must be provided by given implementations. + /// They are responsible for setting return value (and out parameters) on proxied methods. It is also illegal for an interceptor to call , since there's no actual implementation to proceed with. + /// As a result of that also at least one implementation must be provided. + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + public TInterface CreateInterfaceProxyWithoutTarget(ProxyGenerationOptions options, + params IInterceptor[] interceptors) + where TInterface : class + { + return (TInterface)CreateInterfaceProxyWithoutTarget(typeof(TInterface), Type.EmptyTypes, options, interceptors); + } + + /// + /// Creates proxy object intercepting calls to members of interface on target object generated at runtime with given . + /// + /// Type of the interface which will be proxied. + /// The interceptors called during the invocation of proxied methods. + /// + /// Object proxying calls to members of type on generated target object. + /// + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given array is a null reference (Nothing in Visual Basic). + /// Thrown when given is a generic type definition. + /// Thrown when given is not an interface type. + /// + /// Since this method uses an empty-shell implementation of interfaces to proxy generated at runtime, the actual implementation of proxied methods must be provided by given implementations. + /// They are responsible for setting return value (and out parameters) on proxied methods. It is also illegal for an interceptor to call , since there's no actual implementation to proceed with. + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + public object CreateInterfaceProxyWithoutTarget(Type interfaceToProxy, IInterceptor interceptor) + { + return CreateInterfaceProxyWithoutTarget(interfaceToProxy, Type.EmptyTypes, ProxyGenerationOptions.Default, + interceptor); + } + + /// + /// Creates proxy object intercepting calls to members of interface on target object generated at runtime with given . + /// + /// Type of the interface which will be proxied. + /// The interceptors called during the invocation of proxied methods. + /// + /// Object proxying calls to members of type on generated target object. + /// + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given array is a null reference (Nothing in Visual Basic). + /// Thrown when given is a generic type definition. + /// Thrown when given is not an interface type. + /// + /// Since this method uses an empty-shell implementation of interfaces to proxy generated at runtime, the actual implementation of proxied methods must be provided by given implementations. + /// They are responsible for setting return value (and out parameters) on proxied methods. It is also illegal for an interceptor to call , since there's no actual implementation to proceed with. + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + public object CreateInterfaceProxyWithoutTarget(Type interfaceToProxy, params IInterceptor[] interceptors) + { + return CreateInterfaceProxyWithoutTarget(interfaceToProxy, Type.EmptyTypes, ProxyGenerationOptions.Default, + interceptors); + } + + /// + /// Creates proxy object intercepting calls to members of interface on target object generated at runtime with given . + /// + /// Type of the interface which will be proxied. + /// Additional interface types. Calls to their members will be proxied as well. + /// The interceptors called during the invocation of proxied methods. + /// + /// Object proxying calls to members of and types on generated target object. + /// + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given array is a null reference (Nothing in Visual Basic). + /// Thrown when given or any of is a generic type definition. + /// Thrown when given is not an interface type. + /// + /// Since this method uses an empty-shell implementation of interfaces to proxy generated at runtime, the actual implementation of proxied methods must be provided by given implementations. + /// They are responsible for setting return value (and out parameters) on proxied methods. It is also illegal for an interceptor to call , since there's no actual implementation to proceed with. + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + public object CreateInterfaceProxyWithoutTarget(Type interfaceToProxy, Type[] additionalInterfacesToProxy, + params IInterceptor[] interceptors) + { + return CreateInterfaceProxyWithoutTarget(interfaceToProxy, additionalInterfacesToProxy, + ProxyGenerationOptions.Default, interceptors); + } + + /// + /// Creates proxy object intercepting calls to members of interface on target object generated at runtime with given . + /// + /// Type of the interface which will be proxied. + /// The proxy generation options used to influence generated proxy type and object. + /// The interceptors called during the invocation of proxied methods. + /// + /// Object proxying calls to members of on generated target object. + /// + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given array is a null reference (Nothing in Visual Basic). + /// Thrown when given is a generic type definition. + /// Thrown when given is not an interface type. + /// + /// They are responsible for setting return value (and out parameters) on proxied methods. It is also illegal for an interceptor to call , since there's no actual implementation to proceed with. + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + public object CreateInterfaceProxyWithoutTarget(Type interfaceToProxy, ProxyGenerationOptions options, + params IInterceptor[] interceptors) + { + return CreateInterfaceProxyWithoutTarget(interfaceToProxy, Type.EmptyTypes, options, interceptors); + } + + /// + /// Creates proxy object intercepting calls to members of interface on target object generated at runtime with given . + /// + /// Type of the interface which will be proxied. + /// The proxy generation options used to influence generated proxy type and object. + /// Additional interface types. Calls to their members will be proxied as well. + /// The interceptors called during the invocation of proxied methods. + /// + /// Object proxying calls to members of and types on generated target object. + /// + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given array is a null reference (Nothing in Visual Basic). + /// Thrown when given or any of is a generic type definition. + /// Thrown when given is not an interface type. + /// + /// Since this method uses an empty-shell implementation of to proxy generated at runtime, the actual implementation of proxied methods must be provided by given implementations. + /// They are responsible for setting return value (and out parameters) on proxied methods. It is also illegal for an interceptor to call , since there's no actual implementation to proceed with. + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + public virtual object CreateInterfaceProxyWithoutTarget(Type interfaceToProxy, Type[] additionalInterfacesToProxy, + ProxyGenerationOptions options, + params IInterceptor[] interceptors) + { + if (interfaceToProxy == null) + { + throw new ArgumentNullException(nameof(interfaceToProxy)); + } + if (interceptors == null) + { + throw new ArgumentNullException(nameof(interceptors)); + } + + if (!interfaceToProxy.IsInterface) + { + throw new ArgumentException("Specified type is not an interface", nameof(interfaceToProxy)); + } + + CheckNotGenericTypeDefinition(interfaceToProxy, nameof(interfaceToProxy)); + CheckNotGenericTypeDefinitions(additionalInterfacesToProxy, nameof(additionalInterfacesToProxy)); + + var generatedType = CreateInterfaceProxyTypeWithoutTarget(interfaceToProxy, additionalInterfacesToProxy, options); + var arguments = GetConstructorArguments(null, interceptors, options); + return Activator.CreateInstance(generatedType, arguments.ToArray()); + } + + /// + /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . + /// + /// Type of class which will be proxied. + /// The target object, calls to which will be intercepted. + /// The interceptors called during the invocation of proxied methods. + /// + /// New object of type proxying calls to virtual members of type. + /// + /// Thrown when given is not a class type. + /// Thrown when no default constructor exists on type . + /// Thrown when default constructor of type throws an exception. + /// + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + public TClass CreateClassProxyWithTarget(TClass target, params IInterceptor[] interceptors) + where TClass : class + { + return (TClass)CreateClassProxyWithTarget(typeof(TClass), + Type.EmptyTypes, + target, + ProxyGenerationOptions.Default, + new object[0], + interceptors); + } + + /// + /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . + /// + /// Type of class which will be proxied. + /// The target object, calls to which will be intercepted. + /// The proxy generation options used to influence generated proxy type and object. + /// The interceptors called during the invocation of proxied methods. + /// + /// New object of type proxying calls to virtual members of type. + /// + /// Thrown when given is not a class type. + /// Thrown when no default constructor exists on type . + /// Thrown when default constructor of type throws an exception. + /// + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + public TClass CreateClassProxyWithTarget(TClass target, ProxyGenerationOptions options, + params IInterceptor[] interceptors) where TClass : class + { + return (TClass)CreateClassProxyWithTarget(typeof(TClass), + Type.EmptyTypes, + target, + options, + new object[0], + interceptors); + } + + /// + /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . + /// + /// Type of class which will be proxied. + /// Additional interface types. Calls to their members will be proxied as well. + /// The target object, calls to which will be intercepted. + /// The interceptors called during the invocation of proxied methods. + /// + /// New object of type proxying calls to virtual members of and types. + /// + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given or any of is a generic type definition. + /// Thrown when given is not a class type. + /// Thrown when no default constructor exists on type . + /// Thrown when default constructor of type throws an exception. + /// + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + public object CreateClassProxyWithTarget(Type classToProxy, Type[] additionalInterfacesToProxy, object target, + params IInterceptor[] interceptors) + { + return CreateClassProxyWithTarget(classToProxy, + additionalInterfacesToProxy, + target, + ProxyGenerationOptions.Default, + new object[0], + interceptors); + } + + /// + /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . + /// + /// Type of class which will be proxied. + /// The target object, calls to which will be intercepted. + /// The proxy generation options used to influence generated proxy type and object. + /// Arguments of constructor of type which should be used to create a new instance of that type. + /// The interceptors called during the invocation of proxied methods. + /// + /// New object of type proxying calls to virtual members of type. + /// + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given is a generic type definition. + /// Thrown when given is not a class type. + /// Thrown when no constructor exists on type with parameters matching . + /// Thrown when constructor of type throws an exception. + /// + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + public object CreateClassProxyWithTarget(Type classToProxy, object target, ProxyGenerationOptions options, + object[] constructorArguments, params IInterceptor[] interceptors) + { + return CreateClassProxyWithTarget(classToProxy, + Type.EmptyTypes, + target, + options, + constructorArguments, + interceptors); + } + + /// + /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . + /// + /// Type of class which will be proxied. + /// The target object, calls to which will be intercepted. + /// Arguments of constructor of type which should be used to create a new instance of that type. + /// The interceptors called during the invocation of proxied methods. + /// + /// New object of type proxying calls to virtual members of type. + /// + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given is a generic type definition. + /// Thrown when given is not a class type. + /// Thrown when no constructor exists on type with parameters matching . + /// Thrown when constructor of type throws an exception. + /// + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + public object CreateClassProxyWithTarget(Type classToProxy, object target, object[] constructorArguments, + params IInterceptor[] interceptors) + { + return CreateClassProxyWithTarget(classToProxy, + Type.EmptyTypes, + target, + ProxyGenerationOptions.Default, + constructorArguments, + interceptors); + } + + /// + /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . + /// + /// Type of class which will be proxied. + /// The target object, calls to which will be intercepted. + /// The interceptors called during the invocation of proxied methods. + /// + /// New object of type proxying calls to virtual members of type. + /// + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given is a generic type definition. + /// Thrown when given is not a class type. + /// Thrown when no parameterless constructor exists on type . + /// Thrown when constructor of type throws an exception. + /// + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + public object CreateClassProxyWithTarget(Type classToProxy, object target, params IInterceptor[] interceptors) + { + return CreateClassProxyWithTarget(classToProxy, + Type.EmptyTypes, + target, + ProxyGenerationOptions.Default, + new object[0], + interceptors); + } + + /// + /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . + /// + /// Type of class which will be proxied. + /// The target object, calls to which will be intercepted. + /// The proxy generation options used to influence generated proxy type and object. + /// The interceptors called during the invocation of proxied methods. + /// + /// New object of type proxying calls to virtual members of type. + /// + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given is a generic type definition. + /// Thrown when given is not a class type. + /// Thrown when no default constructor exists on type . + /// Thrown when default constructor of type throws an exception. + /// + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + public object CreateClassProxyWithTarget(Type classToProxy, object target, ProxyGenerationOptions options, + params IInterceptor[] interceptors) + { + return CreateClassProxyWithTarget(classToProxy, + Type.EmptyTypes, + target, + options, + new object[0], + interceptors); + } + + /// + /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . + /// + /// Type of class which will be proxied. + /// Additional interface types. Calls to their members will be proxied as well. + /// The target object, calls to which will be intercepted. + /// The proxy generation options used to influence generated proxy type and object. + /// The interceptors called during the invocation of proxied methods. + /// + /// New object of type proxying calls to virtual members of and types. + /// + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given or any of is a generic type definition. + /// Thrown when given is not a class type. + /// Thrown when no default constructor exists on type . + /// Thrown when default constructor of type throws an exception. + /// + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + public object CreateClassProxyWithTarget(Type classToProxy, Type[] additionalInterfacesToProxy, object target, + ProxyGenerationOptions options, params IInterceptor[] interceptors) + { + return CreateClassProxyWithTarget(classToProxy, + additionalInterfacesToProxy, + target, + options, + new object[0], + interceptors); + } + + /// + /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . + /// + /// Type of class which will be proxied. + /// Additional interface types. Calls to their members will be proxied as well. + /// The target object, calls to which will be intercepted. + /// The proxy generation options used to influence generated proxy type and object. + /// Arguments of constructor of type which should be used to create a new instance of that type. + /// The interceptors called during the invocation of proxied methods. + /// + /// New object of type proxying calls to virtual members of and types. + /// + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given or any of is a generic type definition. + /// Thrown when given is not a class type. + /// Thrown when no constructor exists on type with parameters matching . + /// Thrown when constructor of type throws an exception. + /// + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + public virtual object CreateClassProxyWithTarget(Type classToProxy, Type[] additionalInterfacesToProxy, object target, + ProxyGenerationOptions options, object[] constructorArguments, + params IInterceptor[] interceptors) + { + if (classToProxy == null) + { + throw new ArgumentNullException(nameof(classToProxy)); + } + if (options == null) + { + throw new ArgumentNullException(nameof(options)); + } + if (!classToProxy.IsClass) + { + throw new ArgumentException("'classToProxy' must be a class", nameof(classToProxy)); + } + + CheckNotGenericTypeDefinition(classToProxy, nameof(classToProxy)); + CheckNotGenericTypeDefinitions(additionalInterfacesToProxy, nameof(additionalInterfacesToProxy)); + + var proxyType = CreateClassProxyTypeWithTarget(classToProxy, additionalInterfacesToProxy, options); + + // create constructor arguments (initialized with mixin implementations, interceptors and target type constructor arguments) + var arguments = BuildArgumentListForClassProxyWithTarget(target, options, interceptors); + if (constructorArguments != null && constructorArguments.Length != 0) + { + arguments.AddRange(constructorArguments); + } + return CreateClassProxyInstance(proxyType, arguments, classToProxy, constructorArguments); + } + + /// + /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . + /// + /// Type of class which will be proxied. + /// The interceptors called during the invocation of proxied methods. + /// + /// New object of type proxying calls to virtual members of type. + /// + /// Thrown when given is not a class type. + /// Thrown when no default constructor exists on type . + /// Thrown when default constructor of type throws an exception. + /// + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + public TClass CreateClassProxy(params IInterceptor[] interceptors) where TClass : class + { + return (TClass)CreateClassProxy(typeof(TClass), ProxyGenerationOptions.Default, interceptors); + } + + /// + /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . + /// + /// Type of class which will be proxied. + /// The proxy generation options used to influence generated proxy type and object. + /// The interceptors called during the invocation of proxied methods. + /// + /// New object of type proxying calls to virtual members of type. + /// + /// Thrown when given is not a class type. + /// Thrown when no default constructor exists on type . + /// Thrown when default constructor of type throws an exception. + /// + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + public TClass CreateClassProxy(ProxyGenerationOptions options, params IInterceptor[] interceptors) + where TClass : class + { + return (TClass)CreateClassProxy(typeof(TClass), options, interceptors); + } + + /// + /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . + /// + /// Type of class which will be proxied. + /// Additional interface types. Calls to their members will be proxied as well. + /// The interceptors called during the invocation of proxied methods. + /// + /// New object of type proxying calls to virtual members of and types. + /// + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given or any of is a generic type definition. + /// Thrown when given is not a class type. + /// Thrown when no default constructor exists on type . + /// Thrown when default constructor of type throws an exception. + /// + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + public object CreateClassProxy(Type classToProxy, Type[] additionalInterfacesToProxy, + params IInterceptor[] interceptors) + { + return CreateClassProxy(classToProxy, additionalInterfacesToProxy, ProxyGenerationOptions.Default, interceptors); + } + + /// + /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . + /// + /// Type of class which will be proxied. + /// The proxy generation options used to influence generated proxy type and object. + /// Arguments of constructor of type which should be used to create a new instance of that type. + /// The interceptors called during the invocation of proxied methods. + /// + /// New object of type proxying calls to virtual members of type. + /// + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given is a generic type definition. + /// Thrown when given is not a class type. + /// Thrown when no constructor exists on type with parameters matching . + /// Thrown when constructor of type throws an exception. + /// + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + public object CreateClassProxy(Type classToProxy, ProxyGenerationOptions options, object[] constructorArguments, + params IInterceptor[] interceptors) + { + return CreateClassProxy(classToProxy, null, options, constructorArguments, interceptors); + } + + /// + /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . + /// + /// Type of class which will be proxied. + /// Arguments of constructor of type which should be used to create a new instance of that type. + /// The interceptors called during the invocation of proxied methods. + /// + /// New object of type proxying calls to virtual members of type. + /// + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given is a generic type definition. + /// Thrown when given is not a class type. + /// Thrown when no constructor exists on type with parameters matching . + /// Thrown when constructor of type throws an exception. + /// + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + public object CreateClassProxy(Type classToProxy, object[] constructorArguments, params IInterceptor[] interceptors) + { + return CreateClassProxy(classToProxy, null, ProxyGenerationOptions.Default, constructorArguments, interceptors); + } + + /// + /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . + /// + /// Type of class which will be proxied. + /// The interceptors called during the invocation of proxied methods. + /// + /// New object of type proxying calls to virtual members of type. + /// + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given is a generic type definition. + /// Thrown when given is not a class type. + /// Thrown when no parameterless constructor exists on type . + /// Thrown when constructor of type throws an exception. + /// + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + public object CreateClassProxy(Type classToProxy, params IInterceptor[] interceptors) + { + return CreateClassProxy(classToProxy, null, ProxyGenerationOptions.Default, + null, interceptors); + } + + /// + /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . + /// + /// Type of class which will be proxied. + /// The proxy generation options used to influence generated proxy type and object. + /// The interceptors called during the invocation of proxied methods. + /// + /// New object of type proxying calls to virtual members of type. + /// + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given is a generic type definition. + /// Thrown when given is not a class type. + /// Thrown when no default constructor exists on type . + /// Thrown when default constructor of type throws an exception. + /// + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + public object CreateClassProxy(Type classToProxy, ProxyGenerationOptions options, params IInterceptor[] interceptors) + { + return CreateClassProxy(classToProxy, null, options, interceptors); + } + + /// + /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . + /// + /// Type of class which will be proxied. + /// Additional interface types. Calls to their members will be proxied as well. + /// The proxy generation options used to influence generated proxy type and object. + /// The interceptors called during the invocation of proxied methods. + /// + /// New object of type proxying calls to virtual members of and types. + /// + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given or any of is a generic type definition. + /// Thrown when given is not a class type. + /// Thrown when no default constructor exists on type . + /// Thrown when default constructor of type throws an exception. + /// + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + public object CreateClassProxy(Type classToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options, + params IInterceptor[] interceptors) + { + return CreateClassProxy(classToProxy, additionalInterfacesToProxy, options, null, interceptors); + } + + /// + /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . + /// + /// Type of class which will be proxied. + /// Additional interface types. Calls to their members will be proxied as well. + /// The proxy generation options used to influence generated proxy type and object. + /// Arguments of constructor of type which should be used to create a new instance of that type. + /// The interceptors called during the invocation of proxied methods. + /// + /// New object of type proxying calls to virtual members of and types. + /// + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given object is a null reference (Nothing in Visual Basic). + /// Thrown when given or any of is a generic type definition. + /// Thrown when given is not a class type. + /// Thrown when no constructor exists on type with parameters matching . + /// Thrown when constructor of type throws an exception. + /// + /// This method uses implementation to generate a proxy type. + /// As such caller should expect any type of exception that given implementation may throw. + /// + public virtual object CreateClassProxy(Type classToProxy, Type[] additionalInterfacesToProxy, + ProxyGenerationOptions options, + object[] constructorArguments, params IInterceptor[] interceptors) + { + if (classToProxy == null) + { + throw new ArgumentNullException(nameof(classToProxy)); + } + if (options == null) + { + throw new ArgumentNullException(nameof(options)); + } + if (!classToProxy.IsClass) + { + throw new ArgumentException("'classToProxy' must be a class", nameof(classToProxy)); + } + + CheckNotGenericTypeDefinition(classToProxy, nameof(classToProxy)); + CheckNotGenericTypeDefinitions(additionalInterfacesToProxy, nameof(additionalInterfacesToProxy)); + + var proxyType = CreateClassProxyType(classToProxy, additionalInterfacesToProxy, options); + + // create constructor arguments (initialized with mixin implementations, interceptors and target type constructor arguments) + var arguments = BuildArgumentListForClassProxy(options, interceptors); + if (constructorArguments != null && constructorArguments.Length != 0) + { + arguments.AddRange(constructorArguments); + } + return CreateClassProxyInstance(proxyType, arguments, classToProxy, constructorArguments); + } + + protected object CreateClassProxyInstance(Type proxyType, List proxyArguments, Type classToProxy, + object[] constructorArguments) + { + try + { + return Activator.CreateInstance(proxyType, proxyArguments.ToArray()); + } + catch (MissingMethodException ex) + { + var message = new StringBuilder(); + message.AppendFormat("Can not instantiate proxy of class: {0}.", classToProxy.FullName); + message.AppendLine(); + if (constructorArguments == null || constructorArguments.Length == 0) + { + message.Append("Could not find a parameterless constructor."); + } + else + { + message.AppendLine("Could not find a constructor that would match given arguments:"); + foreach (var argument in constructorArguments) + { + var argumentText = argument == null ? "" : argument.GetType().ToString(); + message.AppendLine(argumentText); + } + } + + throw new ArgumentException(message.ToString(), nameof(constructorArguments), ex); + } + } + + protected void CheckNotGenericTypeDefinition(Type type, string argumentName) + { + if (type != null && type.IsGenericTypeDefinition) + { + throw new ArgumentException( + $"Can not create proxy for type {type.GetBestName()} because it is an open generic type.", + argumentName); + } + } + + protected void CheckNotGenericTypeDefinitions(IEnumerable types, string argumentName) + { + if (types == null) + { + return; + } + foreach (var t in types) + { + CheckNotGenericTypeDefinition(t, argumentName); + } + } + + protected List BuildArgumentListForClassProxyWithTarget(object target, ProxyGenerationOptions options, + IInterceptor[] interceptors) + { + var arguments = new List(); + arguments.Add(target); + arguments.AddRange(options.MixinData.Mixins); + arguments.Add(interceptors); + if (options.Selector != null) + { + arguments.Add(options.Selector); + } + return arguments; + } + + protected List BuildArgumentListForClassProxy(ProxyGenerationOptions options, IInterceptor[] interceptors) + { + var arguments = new List(options.MixinData.Mixins) { interceptors }; + if (options.Selector != null) + { + arguments.Add(options.Selector); + } + return arguments; + } + + /// + /// Creates the proxy type for class proxy with given class, implementing given and using provided . + /// + /// The base class for proxy type. + /// The interfaces that proxy type should implement. + /// The options for proxy generation process. + /// of proxy. + protected Type CreateClassProxyType(Type classToProxy, Type[] additionalInterfacesToProxy, + ProxyGenerationOptions options) + { + // create proxy + return ProxyBuilder.CreateClassProxyType(classToProxy, additionalInterfacesToProxy, options); + } + + /// + /// Creates the proxy type for interface proxy with target for given interface, implementing given on given and using provided . + /// + /// The interface proxy type should implement. + /// The additional interfaces proxy type should implement. + /// Actual type that the proxy type will encompass. + /// The options for proxy generation process. + /// of proxy. + protected Type CreateInterfaceProxyTypeWithTarget(Type interfaceToProxy, Type[] additionalInterfacesToProxy, + Type targetType, + ProxyGenerationOptions options) + { + // create proxy + return ProxyBuilder.CreateInterfaceProxyTypeWithTarget(interfaceToProxy, additionalInterfacesToProxy, targetType, + options); + } + + /// + /// Creates the proxy type for interface proxy with target interface for given interface, implementing given on given and using provided . + /// + /// The interface proxy type should implement. + /// The additional interfaces proxy type should implement. + /// The options for proxy generation process. + /// of proxy. + protected Type CreateInterfaceProxyTypeWithTargetInterface(Type interfaceToProxy, Type[] additionalInterfacesToProxy, + ProxyGenerationOptions options) + { + // create proxy + return ProxyBuilder.CreateInterfaceProxyTypeWithTargetInterface(interfaceToProxy, additionalInterfacesToProxy, + options); + } + + /// + /// Creates the proxy type for interface proxy without target for given interface, implementing given and using provided . + /// + /// The interface proxy type should implement. + /// The additional interfaces proxy type should implement. + /// The options for proxy generation process. + /// of proxy. + protected Type CreateInterfaceProxyTypeWithoutTarget(Type interfaceToProxy, Type[] additionalInterfacesToProxy, + ProxyGenerationOptions options) + { + // create proxy + return ProxyBuilder.CreateInterfaceProxyTypeWithoutTarget(interfaceToProxy, additionalInterfacesToProxy, options); + } + + protected Type CreateClassProxyTypeWithTarget(Type classToProxy, Type[] additionalInterfacesToProxy, + ProxyGenerationOptions options) + { + // create proxy + return ProxyBuilder.CreateClassProxyTypeWithTarget(classToProxy, additionalInterfacesToProxy, options); + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/ProxyUtil.cs b/Castle.Core/DynamicProxy/ProxyUtil.cs new file mode 100644 index 0000000..cf94e77 --- /dev/null +++ b/Castle.Core/DynamicProxy/ProxyUtil.cs @@ -0,0 +1,236 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Reflection; + using System.Runtime.CompilerServices; + using System.Threading; + + using Castle.Core.Internal; + using Castle.DynamicProxy.Generators; + using Castle.DynamicProxy.Internal; + + public static class ProxyUtil + { + private static readonly SynchronizedDictionary internalsVisibleToDynamicProxy = new SynchronizedDictionary(); + + /// + /// Creates a delegate of the specified type to a suitable `Invoke` method + /// on the given instance. + /// + /// The proxy instance to which the delegate should be bound. + /// The type of delegate that should be created. + /// + /// The does not have an `Invoke` method that is compatible with + /// the requested type. + /// + public static TDelegate CreateDelegateToMixin(object proxy) + { + return (TDelegate)(object)CreateDelegateToMixin(proxy, typeof(TDelegate)); + } + + /// + /// Creates a delegate of the specified type to a suitable `Invoke` method + /// on the given instance. + /// + /// The proxy instance to which the delegate should be bound. + /// The type of delegate that should be created. + /// + /// The does not have an `Invoke` method that is compatible with + /// the requested . + /// + public static Delegate CreateDelegateToMixin(object proxy, Type delegateType) + { + if (proxy == null) throw new ArgumentNullException(nameof(proxy)); + if (delegateType == null) throw new ArgumentNullException(nameof(delegateType)); + if (!delegateType.IsDelegateType()) throw new ArgumentException("Type is not a delegate type.", nameof(delegateType)); + + var invokeMethod = delegateType.GetMethod("Invoke"); + var proxiedInvokeMethod = + proxy + .GetType() + .GetMember("Invoke", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) + .Cast() + .FirstOrDefault(m => MethodSignatureComparer.Instance.EqualParameters(m, invokeMethod)); + + if (proxiedInvokeMethod == null) + { + throw new MissingMethodException("The proxy does not have an Invoke method " + + "that is compatible with the requested delegate type."); + } + else + { + return Delegate.CreateDelegate(delegateType, proxy, proxiedInvokeMethod); + } + } + + public static object GetUnproxiedInstance(object instance) + { + if (instance is IProxyTargetAccessor accessor) + { + instance = accessor.DynProxyGetTarget(); + } + + return instance; + } + + public static Type GetUnproxiedType(object instance) + { + if (instance is IProxyTargetAccessor accessor) + { + var target = accessor.DynProxyGetTarget(); + if (target != null) + { + if (ReferenceEquals(target, instance)) + { + return instance.GetType().BaseType; + } + + instance = target; + } + } + + return instance.GetType(); + } + + public static bool IsProxy(object instance) + { + return instance is IProxyTargetAccessor; + } + + public static bool IsProxyType(Type type) + { + return typeof(IProxyTargetAccessor).IsAssignableFrom(type); + } + + /// + /// Checks whether the specified method is accessible to DynamicProxy. + /// The method to check. + /// true if the method is accessible to DynamicProxy, false otherwise. + public static bool IsAccessible(MethodBase method) + { + return IsAccessibleMethod(method) && IsAccessibleType(method.DeclaringType); + } + + /// + /// Checks whether the specified method is accessible to DynamicProxy. + /// The method to check. + /// If the method is accessible to DynamicProxy, null; otherwise, an explanation of why the method is not accessible. + /// true if the method is accessible to DynamicProxy, false otherwise. + public static bool IsAccessible(MethodBase method, out string message) + { + if (IsAccessible(method)) + { + message = null; + return true; + } + + message = CreateMessageForInaccessibleMethod(method); + return false; + } + + /// + /// Checks whether the specified type is accessible to DynamicProxy. + /// The type to check. + /// true if the type is accessible to DynamicProxy, false otherwise. + public static bool IsAccessible(Type type) + { + return IsAccessibleType(type); + } + + /// + /// Determines whether this assembly has internals visible to DynamicProxy. + /// + /// The assembly to inspect. + internal static bool AreInternalsVisibleToDynamicProxy(Assembly asm) + { + return internalsVisibleToDynamicProxy.GetOrAdd(asm, a => + { + var internalsVisibleTo = asm.GetCustomAttributes(); + return internalsVisibleTo.Any(attr => attr.AssemblyName.Contains(ModuleScope.DEFAULT_ASSEMBLY_NAME)); + }); + } + + internal static bool IsAccessibleType(Type target) + { + var isPublic = target.IsPublic || target.IsNestedPublic; + if (isPublic) + { + return true; + } + + var isTargetNested = target.IsNested; + var isNestedAndInternal = isTargetNested && (target.IsNestedAssembly || target.IsNestedFamORAssem); + var isInternalNotNested = target.IsVisible == false && isTargetNested == false; + var isInternal = isInternalNotNested || isNestedAndInternal; + if (isInternal && AreInternalsVisibleToDynamicProxy(target.Assembly)) + { + return true; + } + + return false; + } + + /// + /// Checks whether the specified method is accessible to DynamicProxy. + /// Unlike with , the declaring type's accessibility is ignored. + /// + /// The method to check. + /// true if the method is accessible to DynamicProxy, false otherwise. + internal static bool IsAccessibleMethod(MethodBase method) + { + if (method.IsPublic || method.IsFamily || method.IsFamilyOrAssembly) + { + return true; + } + + if (method.IsAssembly || method.IsFamilyAndAssembly) + { + return AreInternalsVisibleToDynamicProxy(method.DeclaringType.Assembly); + } + + return false; + } + + /// + /// Determines whether the specified method is internal. + /// + /// The method. + /// + /// true if the specified method is internal; otherwise, false. + /// + internal static bool IsInternal(MethodBase method) + { + return method.IsAssembly || (method.IsFamilyAndAssembly && !method.IsFamilyOrAssembly); + } + + private static string CreateMessageForInaccessibleMethod(MethodBase inaccessibleMethod) + { + var containingType = inaccessibleMethod.DeclaringType; + var targetAssembly = containingType.Assembly; + + var messageFormat = "Can not create proxy for method {0} because it or its declaring type is not accessible. "; + + var message = string.Format(messageFormat, + inaccessibleMethod); + + var instructions = ExceptionMessageBuilder.CreateInstructionsToMakeVisible(targetAssembly); + return message + instructions; + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Serialization/CacheMappingsAttribute.cs b/Castle.Core/DynamicProxy/Serialization/CacheMappingsAttribute.cs new file mode 100644 index 0000000..c9c5a31 --- /dev/null +++ b/Castle.Core/DynamicProxy/Serialization/CacheMappingsAttribute.cs @@ -0,0 +1,73 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#if FEATURE_SERIALIZATION + +namespace Castle.DynamicProxy.Serialization +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Reflection; + using System.Reflection.Emit; + using System.Runtime.Serialization.Formatters.Binary; + + using Castle.DynamicProxy.Generators; + + /// + /// Applied to the assemblies saved by in order to persist the cache data included in the persisted assembly. + /// + [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = false)] + [CLSCompliant(false)] + public class CacheMappingsAttribute : Attribute + { + private static readonly ConstructorInfo constructor = + typeof(CacheMappingsAttribute).GetConstructor(new[] { typeof(byte[]) }); + + private readonly byte[] serializedCacheMappings; + + public CacheMappingsAttribute(byte[] serializedCacheMappings) + { + this.serializedCacheMappings = serializedCacheMappings; + } + + public byte[] SerializedCacheMappings + { + get { return serializedCacheMappings; } + } + + internal Dictionary GetDeserializedMappings() + { + using (var stream = new MemoryStream(SerializedCacheMappings)) + { + var formatter = new BinaryFormatter(); + return (Dictionary)formatter.Deserialize(stream); + } + } + + internal static void ApplyTo(AssemblyBuilder assemblyBuilder, Dictionary mappings) + { + using (var stream = new MemoryStream()) + { + var formatter = new BinaryFormatter(); + formatter.Serialize(stream, mappings); + var bytes = stream.ToArray(); + var attributeBuilder = new CustomAttributeBuilder(constructor, new object[] { bytes }); + assemblyBuilder.SetCustomAttribute(attributeBuilder); + } + } + } +} + +#endif \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Serialization/ProxyObjectReference.cs b/Castle.Core/DynamicProxy/Serialization/ProxyObjectReference.cs new file mode 100644 index 0000000..461715e --- /dev/null +++ b/Castle.Core/DynamicProxy/Serialization/ProxyObjectReference.cs @@ -0,0 +1,294 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#if FEATURE_SERIALIZATION + +namespace Castle.DynamicProxy.Serialization +{ + using System; + using System.Collections.Generic; + using System.Diagnostics; + using System.Reflection; + using System.Runtime.Serialization; + + using Castle.DynamicProxy.Generators; + using Castle.DynamicProxy.Internal; + + /// + /// Handles the deserialization of proxies. + /// + [Serializable] + public class ProxyObjectReference : IObjectReference, ISerializable, IDeserializationCallback + { + private static ModuleScope scope = new ModuleScope(); + + private readonly SerializationInfo info; + private readonly StreamingContext context; + + private readonly Type baseType; + private readonly Type[] interfaces; + private readonly object proxy; + private readonly ProxyGenerationOptions proxyGenerationOptions; + + private bool isInterfaceProxy; + private bool delegateToBase; + + /// + /// Resets the used for deserialization to a new scope. + /// + /// + /// This is useful for test cases. + /// + public static void ResetScope() + { + SetScope(new ModuleScope()); + } + + /// + /// Resets the used for deserialization to a given . + /// + /// The scope to be used for deserialization. + /// + /// By default, the deserialization process uses a different scope than the rest of the application, which can lead to multiple proxies + /// being generated for the same type. By explicitly setting the deserialization scope to the application's scope, this can be avoided. + /// + public static void SetScope(ModuleScope scope) + { + if (scope == null) + { + throw new ArgumentNullException(nameof(scope)); + } + ProxyObjectReference.scope = scope; + } + + /// + /// Gets the used for deserialization. + /// + /// As has no way of automatically determining the scope used by the application (and the application might use more than one scope at the same time), uses a dedicated scope instance for deserializing proxy types. This instance can be reset and set to a specific value via and . + public static ModuleScope ModuleScope + { + get { return scope; } + } + + protected ProxyObjectReference(SerializationInfo info, StreamingContext context) + { + this.info = info; + this.context = context; + + baseType = DeserializeTypeFromString("__baseType"); + + var _interfaceNames = (string[])info.GetValue("__interfaces", typeof(string[])); + interfaces = new Type[_interfaceNames.Length]; + + for (var i = 0; i < _interfaceNames.Length; i++) + { + interfaces[i] = Type.GetType(_interfaceNames[i]); + } + + proxyGenerationOptions = + (ProxyGenerationOptions)info.GetValue("__proxyGenerationOptions", typeof(ProxyGenerationOptions)); + proxy = RecreateProxy(); + + // We'll try to deserialize as much of the proxy state as possible here. This is just best effort; due to deserialization dependency reasons, + // we need to repeat this in OnDeserialization to guarantee correct state deserialization. + DeserializeProxyState(); + } + + private Type DeserializeTypeFromString(string key) + { + return Type.GetType(info.GetString(key), true, false); + } + + protected virtual object RecreateProxy() + { + var generatorType = GetValue("__proxyTypeId"); + if (generatorType.Equals(ProxyTypeConstants.Class)) + { + isInterfaceProxy = false; + return RecreateClassProxy(); + } + if (generatorType.Equals(ProxyTypeConstants.ClassWithTarget)) + { + isInterfaceProxy = false; + return RecreateClassProxyWithTarget(); + } + isInterfaceProxy = true; + return RecreateInterfaceProxy(generatorType); + } + + private object RecreateClassProxyWithTarget() + { + var generator = new ClassProxyWithTargetGenerator(scope, baseType, interfaces, proxyGenerationOptions); + var proxyType = generator.GetProxyType(); + return InstantiateClassProxy(proxyType); + } + + public object RecreateInterfaceProxy(string generatorType) + { + var @interface = DeserializeTypeFromString("__theInterface"); + var targetType = DeserializeTypeFromString("__targetFieldType"); + + BaseInterfaceProxyGenerator generator; + if (generatorType == ProxyTypeConstants.InterfaceWithTarget) + { + generator = new InterfaceProxyWithTargetGenerator(scope, @interface, interfaces, targetType, proxyGenerationOptions); + } + else if (generatorType == ProxyTypeConstants.InterfaceWithoutTarget) + { + generator = new InterfaceProxyWithoutTargetGenerator(scope, @interface, interfaces, targetType, proxyGenerationOptions); + } + else if (generatorType == ProxyTypeConstants.InterfaceWithTargetInterface) + { + generator = new InterfaceProxyWithTargetInterfaceGenerator(scope, @interface, interfaces, targetType, proxyGenerationOptions); + } + else + { + throw new InvalidOperationException( + string.Format( + "Got value {0} for the interface generator type, which is not known for the purpose of serialization.", + generatorType)); + } + + var proxyType = generator.GetProxyType(); + return FormatterServices.GetSafeUninitializedObject(proxyType); + } + + public object RecreateClassProxy() + { + var generator = new ClassProxyGenerator(scope, baseType, interfaces, proxyGenerationOptions); + var proxyType = generator.GetProxyType(); + return InstantiateClassProxy(proxyType); + } + + private object InstantiateClassProxy(Type proxy_type) + { + delegateToBase = GetValue("__delegateToBase"); + if (delegateToBase) + { + return Activator.CreateInstance(proxy_type, new object[] { info, context }); + } + else + { + return FormatterServices.GetSafeUninitializedObject(proxy_type); + } + } + + protected void InvokeCallback(object target) + { + if (target is IDeserializationCallback) + { + (target as IDeserializationCallback).OnDeserialization(this); + } + } + + public object GetRealObject(StreamingContext context) + { + return proxy; + } + + public void GetObjectData(SerializationInfo info, StreamingContext context) + { + // There is no need to implement this method as + // this class would never be serialized. + } + + public void OnDeserialization(object sender) + { + var interceptors = GetValue("__interceptors"); + SetInterceptors(interceptors); + + DeserializeProxyMembers(); + + // Get the proxy state again, to get all those members we couldn't get in the constructor due to deserialization ordering. + DeserializeProxyState(); + InvokeCallback(proxy); + } + + private void DeserializeProxyMembers() + { + var proxyType = proxy.GetType(); + var members = FormatterServices.GetSerializableMembers(proxyType); + + var deserializedMembers = new List(); + var deserializedValues = new List(); + for (var i = 0; i < members.Length; i++) + { + var member = members[i] as FieldInfo; + // we get some inherited members... + if (member.DeclaringType != proxyType) + { + continue; + } + + Debug.Assert(member != null); + var value = info.GetValue(member.Name, member.FieldType); + deserializedMembers.Add(member); + deserializedValues.Add(value); + } + FormatterServices.PopulateObjectMembers(proxy, deserializedMembers.ToArray(), deserializedValues.ToArray()); + } + + private void DeserializeProxyState() + { + if (isInterfaceProxy) + { + var target = GetValue("__target"); + SetTarget(target); + } + else if (!delegateToBase) + { + var baseMemberData = GetValue("__data"); + var members = FormatterServices.GetSerializableMembers(baseType); + + // Sort to keep order on both serialize and deserialize side the same, c.f DYNPROXY-ISSUE-127 + members = TypeUtil.Sort(members); + + FormatterServices.PopulateObjectMembers(proxy, members, baseMemberData); + } + } + + private void SetTarget(object target) + { + var targetField = proxy.GetType().GetField("__target", BindingFlags.Instance | BindingFlags.NonPublic); + if (targetField == null) + { + throw new SerializationException( + "The SerializationInfo specifies an invalid interface proxy type, which has no __target field."); + } + + targetField.SetValue(proxy, target); + } + + private void SetInterceptors(IInterceptor[] interceptors) + { + var interceptorField = proxy.GetType().GetField("__interceptors", BindingFlags.Instance | BindingFlags.NonPublic); + if (interceptorField == null) + { + throw new SerializationException( + "The SerializationInfo specifies an invalid proxy type, which has no __interceptors field."); + } + + interceptorField.SetValue(proxy, interceptors); + } + + private T GetValue(string name) + { + return (T)info.GetValue(name, typeof(T)); + } + } +} + +#endif \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Serialization/ProxyTypeConstants.cs b/Castle.Core/DynamicProxy/Serialization/ProxyTypeConstants.cs new file mode 100644 index 0000000..c4e055a --- /dev/null +++ b/Castle.Core/DynamicProxy/Serialization/ProxyTypeConstants.cs @@ -0,0 +1,25 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Serialization +{ + internal static class ProxyTypeConstants + { + public static readonly string Class = "class"; + public static readonly string ClassWithTarget = "class.with.target"; + public static readonly string InterfaceWithTarget = "interface.with.target"; + public static readonly string InterfaceWithTargetInterface = "interface.with.target.interface"; + public static readonly string InterfaceWithoutTarget = "interface.without.target"; + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/StandardInterceptor.cs b/Castle.Core/DynamicProxy/StandardInterceptor.cs new file mode 100644 index 0000000..05163c1 --- /dev/null +++ b/Castle.Core/DynamicProxy/StandardInterceptor.cs @@ -0,0 +1,44 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy +{ + using System; + +#if FEATURE_SERIALIZATION + [Serializable] +#endif + public class StandardInterceptor : IInterceptor + { + public void Intercept(IInvocation invocation) + { + PreProceed(invocation); + PerformProceed(invocation); + PostProceed(invocation); + } + + protected virtual void PerformProceed(IInvocation invocation) + { + invocation.Proceed(); + } + + protected virtual void PreProceed(IInvocation invocation) + { + } + + protected virtual void PostProceed(IInvocation invocation) + { + } + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Tokens/DelegateMethods.cs b/Castle.Core/DynamicProxy/Tokens/DelegateMethods.cs new file mode 100644 index 0000000..e0886d3 --- /dev/null +++ b/Castle.Core/DynamicProxy/Tokens/DelegateMethods.cs @@ -0,0 +1,25 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Tokens +{ + using System; + using System.Reflection; + + internal static class DelegateMethods + { + public static readonly MethodInfo CreateDelegate = + typeof(Delegate).GetMethod("CreateDelegate", new[] { typeof(Type), typeof(object), typeof(MethodInfo) }); + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Tokens/FormatterServicesMethods.cs b/Castle.Core/DynamicProxy/Tokens/FormatterServicesMethods.cs new file mode 100644 index 0000000..0754821 --- /dev/null +++ b/Castle.Core/DynamicProxy/Tokens/FormatterServicesMethods.cs @@ -0,0 +1,33 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#if FEATURE_SERIALIZATION + +namespace Castle.DynamicProxy.Tokens +{ + using System; + using System.Reflection; + using System.Runtime.Serialization; + + internal static class FormatterServicesMethods + { + public static readonly MethodInfo GetObjectData = + typeof(FormatterServices).GetMethod("GetObjectData", new[] { typeof(object), typeof(MemberInfo[]) }); + + public static readonly MethodInfo GetSerializableMembers = + typeof(FormatterServices).GetMethod("GetSerializableMembers", new[] { typeof(Type) }); + } +} + +#endif \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Tokens/InterceptorSelectorMethods.cs b/Castle.Core/DynamicProxy/Tokens/InterceptorSelectorMethods.cs new file mode 100644 index 0000000..9f74b0a --- /dev/null +++ b/Castle.Core/DynamicProxy/Tokens/InterceptorSelectorMethods.cs @@ -0,0 +1,23 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Tokens +{ + using System.Reflection; + + internal static class InterceptorSelectorMethods + { + public static readonly MethodInfo SelectInterceptors = typeof(IInterceptorSelector).GetMethod("SelectInterceptors", BindingFlags.Instance | BindingFlags.Public); + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Tokens/InvocationMethods.cs b/Castle.Core/DynamicProxy/Tokens/InvocationMethods.cs new file mode 100644 index 0000000..52cf16e --- /dev/null +++ b/Castle.Core/DynamicProxy/Tokens/InvocationMethods.cs @@ -0,0 +1,103 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Tokens +{ + using System; + using System.Reflection; + + using Castle.DynamicProxy.Internal; + + /// + /// Holds objects representing methods of class. + /// + internal static class InvocationMethods + { + public static readonly ConstructorInfo CompositionInvocationConstructor = + typeof(CompositionInvocation).GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, + new[] + { + typeof(object), + typeof(object), + typeof(IInterceptor[]), + typeof(MethodInfo), + typeof(object[]) + }, + null); + + public static readonly MethodInfo CompositionInvocationEnsureValidTarget = + typeof(CompositionInvocation).GetMethod("EnsureValidTarget", BindingFlags.Instance | BindingFlags.NonPublic); + + public static readonly MethodInfo GetArgumentValue = + typeof(AbstractInvocation).GetMethod("GetArgumentValue"); + + public static readonly MethodInfo GetArguments = + typeof(AbstractInvocation).GetMethod("get_Arguments"); + + public static readonly MethodInfo GetReturnValue = + typeof(AbstractInvocation).GetMethod("get_ReturnValue"); + + public static readonly ConstructorInfo InheritanceInvocationConstructor = + typeof(InheritanceInvocation).GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, + new[] + { + typeof(Type), + typeof(object), + typeof(IInterceptor[]), + typeof(MethodInfo), + typeof(object[]) + }, + null); + + public static readonly ConstructorInfo InheritanceInvocationConstructorWithSelector = + typeof(InheritanceInvocation).GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, + new[] + { + typeof(Type), + typeof(object), + typeof(IInterceptor[]), + typeof(MethodInfo), + typeof(object[]), + typeof(IInterceptorSelector), + typeof(IInterceptor[]).MakeByRefType() + }, + null); + + public static readonly MethodInfo Proceed = + typeof(AbstractInvocation).GetMethod("Proceed", BindingFlags.Instance | BindingFlags.Public); + + public static readonly FieldInfo ProxyObject = + typeof(AbstractInvocation).GetField("proxyObject", BindingFlags.Instance | BindingFlags.NonPublic); + + public static readonly MethodInfo SetArgumentValue = + typeof(AbstractInvocation).GetMethod("SetArgumentValue"); + + public static readonly MethodInfo SetGenericMethodArguments = + typeof(AbstractInvocation).GetMethod("SetGenericMethodArguments", new[] { typeof(Type[]) }); + + public static readonly MethodInfo SetReturnValue = + typeof(AbstractInvocation).GetMethod("set_ReturnValue"); + + public static readonly FieldInfo CompositionInvocationTarget = + typeof(CompositionInvocation).GetField("target", BindingFlags.Instance | BindingFlags.NonPublic); + + public static readonly MethodInfo ThrowOnNoTarget = + typeof(AbstractInvocation).GetMethod("ThrowOnNoTarget", BindingFlags.Instance | BindingFlags.NonPublic); + + // The following two fields are not used internally, but kept for back-compatibility + // because we renamed the public fields `EnsureValidTarget` and `Target`: + public static readonly MethodInfo EnsureValidTarget = CompositionInvocationEnsureValidTarget; + public static readonly FieldInfo Target = CompositionInvocationTarget; + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Tokens/MethodBaseMethods.cs b/Castle.Core/DynamicProxy/Tokens/MethodBaseMethods.cs new file mode 100644 index 0000000..7df1821 --- /dev/null +++ b/Castle.Core/DynamicProxy/Tokens/MethodBaseMethods.cs @@ -0,0 +1,25 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Tokens +{ + using System; + using System.Reflection; + + internal static class MethodBaseMethods + { + public static readonly MethodInfo GetMethodFromHandle = + typeof(MethodBase).GetMethod("GetMethodFromHandle", new[] { typeof(RuntimeMethodHandle), typeof(RuntimeTypeHandle) }); + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Tokens/SerializationInfoMethods.cs b/Castle.Core/DynamicProxy/Tokens/SerializationInfoMethods.cs new file mode 100644 index 0000000..7a22bda --- /dev/null +++ b/Castle.Core/DynamicProxy/Tokens/SerializationInfoMethods.cs @@ -0,0 +1,60 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#if FEATURE_SERIALIZATION + +namespace Castle.DynamicProxy.Tokens +{ + using System; + using System.Reflection; + using System.Runtime.Serialization; + + /// + /// Holds objects representing methods of class. + /// + internal static class SerializationInfoMethods + { + /// + /// + /// + public static readonly MethodInfo AddValue_Bool = + typeof(SerializationInfo).GetMethod("AddValue", new[] { typeof(string), typeof(bool) }); + + /// + /// + /// + public static readonly MethodInfo AddValue_Int32 = + typeof(SerializationInfo).GetMethod("AddValue", new[] { typeof(string), typeof(int) }); + + /// + /// + /// + public static readonly MethodInfo AddValue_Object = + typeof(SerializationInfo).GetMethod("AddValue", new[] { typeof(string), typeof(object) }); + + /// + /// + /// + public static readonly MethodInfo GetValue = + typeof(SerializationInfo).GetMethod("GetValue", new[] { typeof(string), typeof(Type) }); + + /// + /// + /// + public static readonly MethodInfo SetType = + typeof(SerializationInfo).GetMethod("SetType"); + } +} + +#endif \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Tokens/TypeMethods.cs b/Castle.Core/DynamicProxy/Tokens/TypeMethods.cs new file mode 100644 index 0000000..0ac5fb0 --- /dev/null +++ b/Castle.Core/DynamicProxy/Tokens/TypeMethods.cs @@ -0,0 +1,26 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Tokens +{ + using System; + using System.Reflection; + + internal static class TypeMethods + { + public static readonly MethodInfo GetTypeFromHandle = typeof(Type).GetMethod("GetTypeFromHandle"); + + public static readonly MethodInfo StaticGetType = typeof(Type).GetMethod("GetType", new[] { typeof(string), typeof(bool), typeof(bool) }); + } +} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Tokens/TypeUtilMethods.cs b/Castle.Core/DynamicProxy/Tokens/TypeUtilMethods.cs new file mode 100644 index 0000000..3e89f83 --- /dev/null +++ b/Castle.Core/DynamicProxy/Tokens/TypeUtilMethods.cs @@ -0,0 +1,26 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Tokens +{ + using System.Reflection; + + using Castle.DynamicProxy.Internal; + + internal static class TypeUtilMethods + { + public static readonly MethodInfo Sort = typeof(TypeUtil).GetMethod("Sort", BindingFlags.Public | BindingFlags.Static); + public static readonly MethodInfo GetTypeOrNull = typeof(TypeUtil).GetMethod("GetTypeOrNull", BindingFlags.Public | BindingFlags.Static); + } +} \ No newline at end of file diff --git a/Castle.Core/Properties/InternalsVisibleToTests.cs b/Castle.Core/Properties/InternalsVisibleToTests.cs new file mode 100644 index 0000000..d70d590 --- /dev/null +++ b/Castle.Core/Properties/InternalsVisibleToTests.cs @@ -0,0 +1,17 @@ +// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("Castle.Core.Tests, PublicKey=002400000480000094000000060200000024000052534131000400000100010077f5e87030dadccce6902c6adab7a987bd69cb5819991531f560785eacfc89b6fcddf6bb2a00743a7194e454c0273447fc6eec36474ba8e5a3823147d214298e4f9a631b1afee1a51ffeae4672d498f14b000e3d321453cdd8ac064de7e1cf4d222b7e81f54d4fd46725370d702a05b48738cc29d09228f1aa722ae1a9ca02fb")] diff --git a/SimpleProxy.sln b/SimpleProxy.sln index ae71018..2ea4d5c 100644 --- a/SimpleProxy.sln +++ b/SimpleProxy.sln @@ -1,27 +1,17 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.28307.489 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.31112.23 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimpleProxy", "SimpleProxy\SimpleProxy.csproj", "{076C09AD-12A5-4CE0-BE41-B461606FED62}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SampleApp", "SampleApp\SampleApp.csproj", "{F1589C2B-CA8A-4B56-B964-C64C561ADB01}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimpleProxy.Caching", "SimpleProxy.Caching\SimpleProxy.Caching.csproj", "{3B583E8E-6FB9-40E6-A294-35A26F9A9430}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimpleProxy.Diagnostics", "SimpleProxy.Diagnostics\SimpleProxy.Diagnostics.csproj", "{D513380A-89DF-4074-B6C9-EA146AE7D8B5}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimpleProxy.Logging", "SimpleProxy.Logging\SimpleProxy.Logging.csproj", "{65B0C87F-FA32-4EC3-8D67-15D1746924E2}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimpleProxy.UnitOfWork", "SimpleProxy.UnitOfWork\SimpleProxy.UnitOfWork.csproj", "{8E20AC91-9FBA-4975-90EE-46078318F4C8}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleProxy.Tests", "Unit Tests\SimpleProxy.Tests\SimpleProxy.Tests.csproj", "{4463FE87-A9DE-4076-B942-595C0B107924}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Core", "Core", "{4A4DE7A9-6C40-4F7F-9E49-0090BAA9B1E1}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Unit Tests", "Unit Tests", "{8E20A6AB-AC37-43E6-89F9-BF21FEB70339}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CastleCore", "CastleCore", "{FC20E617-CC98-4E90-A382-8A417A8F4A4A}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Interceptors", "Interceptors", "{08F8CC95-6646-4F02-8A2C-C7884CA0DBD0}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Castle.Core", "Castle.Core\Castle.Core.csproj", "{41621639-2171-41BE-A1E3-E27C77DE8C61}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Core", "Core", "{4A4DE7A9-6C40-4F7F-9E49-0090BAA9B1E1}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Castle.Core.AsyncInterceptor", "Castle.Core.AsyncInterceptor\Castle.Core.AsyncInterceptor.csproj", "{75792845-FF7F-454B-B826-79DBB4D40B4C}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -33,41 +23,22 @@ Global {076C09AD-12A5-4CE0-BE41-B461606FED62}.Debug|Any CPU.Build.0 = Debug|Any CPU {076C09AD-12A5-4CE0-BE41-B461606FED62}.Release|Any CPU.ActiveCfg = Release|Any CPU {076C09AD-12A5-4CE0-BE41-B461606FED62}.Release|Any CPU.Build.0 = Release|Any CPU - {F1589C2B-CA8A-4B56-B964-C64C561ADB01}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F1589C2B-CA8A-4B56-B964-C64C561ADB01}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F1589C2B-CA8A-4B56-B964-C64C561ADB01}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F1589C2B-CA8A-4B56-B964-C64C561ADB01}.Release|Any CPU.Build.0 = Release|Any CPU - {3B583E8E-6FB9-40E6-A294-35A26F9A9430}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3B583E8E-6FB9-40E6-A294-35A26F9A9430}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3B583E8E-6FB9-40E6-A294-35A26F9A9430}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3B583E8E-6FB9-40E6-A294-35A26F9A9430}.Release|Any CPU.Build.0 = Release|Any CPU - {D513380A-89DF-4074-B6C9-EA146AE7D8B5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D513380A-89DF-4074-B6C9-EA146AE7D8B5}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D513380A-89DF-4074-B6C9-EA146AE7D8B5}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D513380A-89DF-4074-B6C9-EA146AE7D8B5}.Release|Any CPU.Build.0 = Release|Any CPU - {65B0C87F-FA32-4EC3-8D67-15D1746924E2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {65B0C87F-FA32-4EC3-8D67-15D1746924E2}.Debug|Any CPU.Build.0 = Debug|Any CPU - {65B0C87F-FA32-4EC3-8D67-15D1746924E2}.Release|Any CPU.ActiveCfg = Release|Any CPU - {65B0C87F-FA32-4EC3-8D67-15D1746924E2}.Release|Any CPU.Build.0 = Release|Any CPU - {8E20AC91-9FBA-4975-90EE-46078318F4C8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8E20AC91-9FBA-4975-90EE-46078318F4C8}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8E20AC91-9FBA-4975-90EE-46078318F4C8}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8E20AC91-9FBA-4975-90EE-46078318F4C8}.Release|Any CPU.Build.0 = Release|Any CPU - {4463FE87-A9DE-4076-B942-595C0B107924}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4463FE87-A9DE-4076-B942-595C0B107924}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4463FE87-A9DE-4076-B942-595C0B107924}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4463FE87-A9DE-4076-B942-595C0B107924}.Release|Any CPU.Build.0 = Release|Any CPU + {41621639-2171-41BE-A1E3-E27C77DE8C61}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {41621639-2171-41BE-A1E3-E27C77DE8C61}.Debug|Any CPU.Build.0 = Debug|Any CPU + {41621639-2171-41BE-A1E3-E27C77DE8C61}.Release|Any CPU.ActiveCfg = Release|Any CPU + {41621639-2171-41BE-A1E3-E27C77DE8C61}.Release|Any CPU.Build.0 = Release|Any CPU + {75792845-FF7F-454B-B826-79DBB4D40B4C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {75792845-FF7F-454B-B826-79DBB4D40B4C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {75792845-FF7F-454B-B826-79DBB4D40B4C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {75792845-FF7F-454B-B826-79DBB4D40B4C}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution {076C09AD-12A5-4CE0-BE41-B461606FED62} = {4A4DE7A9-6C40-4F7F-9E49-0090BAA9B1E1} - {3B583E8E-6FB9-40E6-A294-35A26F9A9430} = {08F8CC95-6646-4F02-8A2C-C7884CA0DBD0} - {D513380A-89DF-4074-B6C9-EA146AE7D8B5} = {08F8CC95-6646-4F02-8A2C-C7884CA0DBD0} - {65B0C87F-FA32-4EC3-8D67-15D1746924E2} = {08F8CC95-6646-4F02-8A2C-C7884CA0DBD0} - {8E20AC91-9FBA-4975-90EE-46078318F4C8} = {08F8CC95-6646-4F02-8A2C-C7884CA0DBD0} - {4463FE87-A9DE-4076-B942-595C0B107924} = {8E20A6AB-AC37-43E6-89F9-BF21FEB70339} + {41621639-2171-41BE-A1E3-E27C77DE8C61} = {FC20E617-CC98-4E90-A382-8A417A8F4A4A} + {75792845-FF7F-454B-B826-79DBB4D40B4C} = {FC20E617-CC98-4E90-A382-8A417A8F4A4A} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {8F627740-E1C8-4756-8BA6-39E4135E9350} diff --git a/SimpleProxy/SimpleProxy.csproj b/SimpleProxy/SimpleProxy.csproj index dae9805..0004256 100644 --- a/SimpleProxy/SimpleProxy.csproj +++ b/SimpleProxy/SimpleProxy.csproj @@ -5,7 +5,7 @@ Simple Proxy is a simple extension library built to solve the problem of Aspect Orientated Programming in Net Core projects. Robert Perry https://github.com/f135ta/SimpleProxy - 1.0.6 + 1.0.7 false SimpleProxyCp SimpleProxyCp @@ -15,8 +15,6 @@ - - @@ -28,4 +26,9 @@ + + + + + From ac6526c32ca859f9d32714f556e065a930e2b7e1 Mon Sep 17 00:00:00 2001 From: "shoguns6@yahoo.com" Date: Tue, 13 Apr 2021 18:40:35 +0530 Subject: [PATCH 09/13] Update --- .../Castle.Core.AsyncInterceptor.csproj | 9 ++- Castle.Core/Castle.Core.csproj | 21 ------ SimpleProxy/Interfaces/IMethodInterceptor.cs | 6 +- SimpleProxy/Internal/CoreInterceptor.cs | 68 +++++++++++++------ SimpleProxy/SimpleProxy.csproj | 4 +- 5 files changed, 59 insertions(+), 49 deletions(-) diff --git a/Castle.Core.AsyncInterceptor/Castle.Core.AsyncInterceptor.csproj b/Castle.Core.AsyncInterceptor/Castle.Core.AsyncInterceptor.csproj index 87e7997..f22605c 100644 --- a/Castle.Core.AsyncInterceptor/Castle.Core.AsyncInterceptor.csproj +++ b/Castle.Core.AsyncInterceptor/Castle.Core.AsyncInterceptor.csproj @@ -8,14 +8,12 @@ false enable AllEnabledByDefault - ..\stylecop.ruleset false James Skimming AsyncInterceptor is an extension to Castle DynamicProxy to simplify the development of interceptors for asynchronous methods. Copyright © 2016-2021 James Skimming Apache-2.0 https://github.com/JSkimming/Castle.Core.AsyncInterceptor - castle-logo.png true true https://github.com/JSkimming/Castle.Core.AsyncInterceptor @@ -24,6 +22,9 @@ snupkg async asynchronous-methods castle castle-core dynamic dynamicproxy dynamic-proxy dynamicproxy2 intercept-methods proxy true + 0.0.0.2 + 0.0.0.2 + 0.0.0.2 @@ -33,6 +34,7 @@ true false + Castle.Core.AsyncInterceptor_NL @@ -46,9 +48,6 @@ - - - diff --git a/Castle.Core/Castle.Core.csproj b/Castle.Core/Castle.Core.csproj index 606b655..86cbd14 100644 --- a/Castle.Core/Castle.Core.csproj +++ b/Castle.Core/Castle.Core.csproj @@ -12,7 +12,6 @@ Castle Castle Core Castle Core, including DynamicProxy(with limited logging), Logging Abstractions and DictionaryAdapter - ..\..\buildscripts\CastleKey.snk false true castle dynamicproxy dynamic proxy dynamicproxy2 dictionaryadapter emailsender @@ -21,26 +20,6 @@ 4.4.1.1 - - - - - - - - - - - - - - - - - - - - diff --git a/SimpleProxy/Interfaces/IMethodInterceptor.cs b/SimpleProxy/Interfaces/IMethodInterceptor.cs index 6feb5f0..3b1ea2c 100644 --- a/SimpleProxy/Interfaces/IMethodInterceptor.cs +++ b/SimpleProxy/Interfaces/IMethodInterceptor.cs @@ -1,4 +1,6 @@ -namespace SimpleProxy.Interfaces +using System.Threading.Tasks; + +namespace SimpleProxy.Interfaces { /// /// Defines a mapping between an interceptor and the attribute the interceptor responds to. @@ -8,7 +10,7 @@ public interface IMethodInterceptor /// /// Method that is invoked instead of the method to which the interceptor has been applied /// - void BeforeInvoke(InvocationContext invocationContext); + Task BeforeInvoke(InvocationContext invocationContext); /// /// Method that is invoked instead of the method to which the interceptor has been applied diff --git a/SimpleProxy/Internal/CoreInterceptor.cs b/SimpleProxy/Internal/CoreInterceptor.cs index 1e1fbce..30b87db 100644 --- a/SimpleProxy/Internal/CoreInterceptor.cs +++ b/SimpleProxy/Internal/CoreInterceptor.cs @@ -39,19 +39,19 @@ public CoreInterceptor(IServiceProvider serviceProvider, SimpleProxyConfiguratio public void InterceptSynchronous(IInvocation invocation) { - var proceedWithInterception = InterceptBeforeProceed(invocation, out var invocationMetadataCollection, out var orderingStrategy); + var proceedWithInterception = InterceptBeforeProceed(invocation).Result; - if (!proceedWithInterception) { + if (!proceedWithInterception.DontProceed) { invocation.Proceed(); return; } // Execute the Real Method - if (!invocationMetadataCollection.Any(p => p.InvocationIsBypassed)) { + if (!proceedWithInterception.InvocationContexts.Any(p => p.InvocationIsBypassed)) { invocation.Proceed(); } - InterceptAfterProceed(invocationMetadataCollection, orderingStrategy); + InterceptAfterProceed(proceedWithInterception.InvocationContexts, proceedWithInterception.OrderingStrategy); } public void InterceptAsynchronous(IInvocation invocation) @@ -61,9 +61,9 @@ public void InterceptAsynchronous(IInvocation invocation) private async Task InternalInterceptAsynchronousAsync(IInvocation invocation) { - var proceedWithInterception = InterceptBeforeProceed(invocation, out var invocationMetadataCollection, out var orderingStrategy); + var proceedWithInterception = await InterceptBeforeProceed(invocation); - if (!proceedWithInterception) { + if (!proceedWithInterception.DontProceed) { invocation.Proceed(); var task = (Task)invocation.ReturnValue; await task; @@ -71,13 +71,13 @@ private async Task InternalInterceptAsynchronousAsync(IInvocation invocation) } // Execute the Real Method - if (!invocationMetadataCollection.Any(p => p.InvocationIsBypassed)) { + if (!proceedWithInterception.InvocationContexts.Any(p => p.InvocationIsBypassed)) { invocation.Proceed(); var task = (Task)invocation.ReturnValue; await task; } - InterceptAfterProceed(invocationMetadataCollection, orderingStrategy); + InterceptAfterProceed(proceedWithInterception.InvocationContexts, proceedWithInterception.OrderingStrategy); } public void InterceptAsynchronous(IInvocation invocation) @@ -87,11 +87,11 @@ public void InterceptAsynchronous(IInvocation invocation) private async Task InternalInterceptAsynchronousAsync(IInvocation invocation) { - var proceedWithInterception = InterceptBeforeProceed(invocation, out var invocationMetadataCollection, out var orderingStrategy); + var proceedWithInterception = await InterceptBeforeProceed(invocation); TResult result; - if (!proceedWithInterception) { + if (!proceedWithInterception.DontProceed) { invocation.Proceed(); var task = (Task)invocation.ReturnValue; result = await task; @@ -99,7 +99,7 @@ private async Task InternalInterceptAsynchronousAsync(IInvocat } // Execute the Real Method - if (!invocationMetadataCollection.Any(p => p.InvocationIsBypassed)) { + if (!proceedWithInterception.InvocationContexts.Any(p => p.InvocationIsBypassed)) { invocation.Proceed(); var task = (Task)invocation.ReturnValue; result = await task; @@ -108,31 +108,51 @@ private async Task InternalInterceptAsynchronousAsync(IInvocat result = default; } - InterceptAfterProceed(invocationMetadataCollection, orderingStrategy); + InterceptAfterProceed(proceedWithInterception.InvocationContexts, proceedWithInterception.OrderingStrategy); return result; } - private bool InterceptBeforeProceed(IInvocation invocation, out List invocationMetadataCollection, out IOrderingStrategy orderingStrategy) + private async Task InterceptBeforeProceed(IInvocation invocation) { + InterceptorData data = new InterceptorData(); + // Map the configured interceptors to this type based on its attributes - invocationMetadataCollection = InvocationExtensions.GetInterceptorMetadataForMethod(invocation, this.serviceProvider, this.proxyConfiguration); + var invocationMetadataCollection = InvocationExtensions.GetInterceptorMetadataForMethod(invocation, this.serviceProvider, this.proxyConfiguration); + // If there are no configured interceptors, leave now if (invocationMetadataCollection == null || !invocationMetadataCollection.Any()) { - orderingStrategy = null; - return false; + data.OrderingStrategy = null; + data.DontProceed = false; } // Get the Ordering Strategy for Interceptors - orderingStrategy = this.proxyConfiguration.OrderingStrategy; + var orderingStrategy = this.proxyConfiguration.OrderingStrategy; + data.OrderingStrategy = orderingStrategy; + + data.InvocationContexts = new List(); // Process the BEFORE Interceptions - foreach (var invocationContext in orderingStrategy.OrderBeforeInterception(invocationMetadataCollection)) { - invocationContext.Interceptor.BeforeInvoke(invocationContext); + foreach (var invocationContext in orderingStrategy.OrderBeforeInterception(invocationMetadataCollection)) + { + + var dontProceed = await invocationContext.Interceptor.BeforeInvoke(invocationContext); + if (dontProceed) + { + data.DontProceed = true; + invocationContext.BypassInvocation(); + data.InvocationContexts.Add(invocationContext); + return data; + } + + // in case it is valid one, add it to our list + data.InvocationContexts.Add(invocationContext); } - return true; + + data.DontProceed = true; + return data; } private static void InterceptAfterProceed(List invocationMetadataCollection, IOrderingStrategy orderingStrategy) @@ -145,4 +165,12 @@ private static void InterceptAfterProceed(List invocationMeta } + internal class InterceptorData + { + public List InvocationContexts { get; set; } + public IOrderingStrategy OrderingStrategy { get; set; } + + public bool DontProceed { get; set; } + } + } diff --git a/SimpleProxy/SimpleProxy.csproj b/SimpleProxy/SimpleProxy.csproj index 0004256..f78249b 100644 --- a/SimpleProxy/SimpleProxy.csproj +++ b/SimpleProxy/SimpleProxy.csproj @@ -5,13 +5,15 @@ Simple Proxy is a simple extension library built to solve the problem of Aspect Orientated Programming in Net Core projects. Robert Perry https://github.com/f135ta/SimpleProxy - 1.0.7 + 1.0.9 false SimpleProxyCp SimpleProxyCp SimpleProxyCp SimpleProxyCp LICENSE + 1.0.9.0 + 1.0.9.0 From 93c242425e362ba398e1bee95b1a5984a5ac2f82 Mon Sep 17 00:00:00 2001 From: "shoguns6@yahoo.com" Date: Mon, 28 Jun 2021 12:12:45 +0530 Subject: [PATCH 10/13] Update - Downgrade 5.* to 3.* for Azure Function integration --- SimpleProxy/SimpleProxy.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SimpleProxy/SimpleProxy.csproj b/SimpleProxy/SimpleProxy.csproj index f78249b..1a0addb 100644 --- a/SimpleProxy/SimpleProxy.csproj +++ b/SimpleProxy/SimpleProxy.csproj @@ -17,8 +17,8 @@ - - + + From 2d7272ae179475478ad0f28d38f4ff8aaaa67049 Mon Sep 17 00:00:00 2001 From: "shoguns6@yahoo.com" Date: Mon, 28 Jun 2021 16:53:43 +0530 Subject: [PATCH 11/13] Update --- SimpleProxy/Interfaces/IMethodInterceptor.cs | 6 +- SimpleProxy/Internal/CoreInterceptor.cs | 80 ++++++++------------ SimpleProxy/SimpleProxy.csproj | 17 ++--- 3 files changed, 39 insertions(+), 64 deletions(-) diff --git a/SimpleProxy/Interfaces/IMethodInterceptor.cs b/SimpleProxy/Interfaces/IMethodInterceptor.cs index 3b1ea2c..6feb5f0 100644 --- a/SimpleProxy/Interfaces/IMethodInterceptor.cs +++ b/SimpleProxy/Interfaces/IMethodInterceptor.cs @@ -1,6 +1,4 @@ -using System.Threading.Tasks; - -namespace SimpleProxy.Interfaces +namespace SimpleProxy.Interfaces { /// /// Defines a mapping between an interceptor and the attribute the interceptor responds to. @@ -10,7 +8,7 @@ public interface IMethodInterceptor /// /// Method that is invoked instead of the method to which the interceptor has been applied /// - Task BeforeInvoke(InvocationContext invocationContext); + void BeforeInvoke(InvocationContext invocationContext); /// /// Method that is invoked instead of the method to which the interceptor has been applied diff --git a/SimpleProxy/Internal/CoreInterceptor.cs b/SimpleProxy/Internal/CoreInterceptor.cs index 30b87db..0466f5f 100644 --- a/SimpleProxy/Internal/CoreInterceptor.cs +++ b/SimpleProxy/Internal/CoreInterceptor.cs @@ -39,19 +39,21 @@ public CoreInterceptor(IServiceProvider serviceProvider, SimpleProxyConfiguratio public void InterceptSynchronous(IInvocation invocation) { - var proceedWithInterception = InterceptBeforeProceed(invocation).Result; + var proceedWithInterception = InterceptBeforeProceed(invocation, out var invocationMetadataCollection, out var orderingStrategy); - if (!proceedWithInterception.DontProceed) { + if (!proceedWithInterception) + { invocation.Proceed(); return; } // Execute the Real Method - if (!proceedWithInterception.InvocationContexts.Any(p => p.InvocationIsBypassed)) { + if (!invocationMetadataCollection.Any(p => p.InvocationIsBypassed)) + { invocation.Proceed(); } - InterceptAfterProceed(proceedWithInterception.InvocationContexts, proceedWithInterception.OrderingStrategy); + InterceptAfterProceed(invocationMetadataCollection, orderingStrategy); } public void InterceptAsynchronous(IInvocation invocation) @@ -61,9 +63,10 @@ public void InterceptAsynchronous(IInvocation invocation) private async Task InternalInterceptAsynchronousAsync(IInvocation invocation) { - var proceedWithInterception = await InterceptBeforeProceed(invocation); + var proceedWithInterception = InterceptBeforeProceed(invocation, out var invocationMetadataCollection, out var orderingStrategy); - if (!proceedWithInterception.DontProceed) { + if (!proceedWithInterception) + { invocation.Proceed(); var task = (Task)invocation.ReturnValue; await task; @@ -71,13 +74,14 @@ private async Task InternalInterceptAsynchronousAsync(IInvocation invocation) } // Execute the Real Method - if (!proceedWithInterception.InvocationContexts.Any(p => p.InvocationIsBypassed)) { + if (!invocationMetadataCollection.Any(p => p.InvocationIsBypassed)) + { invocation.Proceed(); var task = (Task)invocation.ReturnValue; await task; } - InterceptAfterProceed(proceedWithInterception.InvocationContexts, proceedWithInterception.OrderingStrategy); + InterceptAfterProceed(invocationMetadataCollection, orderingStrategy); } public void InterceptAsynchronous(IInvocation invocation) @@ -87,11 +91,12 @@ public void InterceptAsynchronous(IInvocation invocation) private async Task InternalInterceptAsynchronousAsync(IInvocation invocation) { - var proceedWithInterception = await InterceptBeforeProceed(invocation); + var proceedWithInterception = InterceptBeforeProceed(invocation, out var invocationMetadataCollection, out var orderingStrategy); TResult result; - if (!proceedWithInterception.DontProceed) { + if (!proceedWithInterception) + { invocation.Proceed(); var task = (Task)invocation.ReturnValue; result = await task; @@ -99,78 +104,55 @@ private async Task InternalInterceptAsynchronousAsync(IInvocat } // Execute the Real Method - if (!proceedWithInterception.InvocationContexts.Any(p => p.InvocationIsBypassed)) { + if (!invocationMetadataCollection.Any(p => p.InvocationIsBypassed)) + { invocation.Proceed(); var task = (Task)invocation.ReturnValue; result = await task; } - else { + else + { result = default; } - InterceptAfterProceed(proceedWithInterception.InvocationContexts, proceedWithInterception.OrderingStrategy); + InterceptAfterProceed(invocationMetadataCollection, orderingStrategy); return result; } - private async Task InterceptBeforeProceed(IInvocation invocation) + private bool InterceptBeforeProceed(IInvocation invocation, out List invocationMetadataCollection, out IOrderingStrategy orderingStrategy) { - InterceptorData data = new InterceptorData(); - // Map the configured interceptors to this type based on its attributes - var invocationMetadataCollection = InvocationExtensions.GetInterceptorMetadataForMethod(invocation, this.serviceProvider, this.proxyConfiguration); - + invocationMetadataCollection = InvocationExtensions.GetInterceptorMetadataForMethod(invocation, this.serviceProvider, this.proxyConfiguration); // If there are no configured interceptors, leave now - if (invocationMetadataCollection == null || !invocationMetadataCollection.Any()) { - data.OrderingStrategy = null; - data.DontProceed = false; + if (invocationMetadataCollection == null || !invocationMetadataCollection.Any()) + { + orderingStrategy = null; + return false; } // Get the Ordering Strategy for Interceptors - var orderingStrategy = this.proxyConfiguration.OrderingStrategy; - data.OrderingStrategy = orderingStrategy; - - data.InvocationContexts = new List(); + orderingStrategy = this.proxyConfiguration.OrderingStrategy; // Process the BEFORE Interceptions foreach (var invocationContext in orderingStrategy.OrderBeforeInterception(invocationMetadataCollection)) { - - var dontProceed = await invocationContext.Interceptor.BeforeInvoke(invocationContext); - if (dontProceed) - { - data.DontProceed = true; - invocationContext.BypassInvocation(); - data.InvocationContexts.Add(invocationContext); - return data; - } - - // in case it is valid one, add it to our list - data.InvocationContexts.Add(invocationContext); + invocationContext.Interceptor.BeforeInvoke(invocationContext); } - - data.DontProceed = true; - return data; + return true; } private static void InterceptAfterProceed(List invocationMetadataCollection, IOrderingStrategy orderingStrategy) { // Process the AFTER Interceptions - foreach (var invocationContext in orderingStrategy.OrderAfterInterception(invocationMetadataCollection)) { + foreach (var invocationContext in orderingStrategy.OrderAfterInterception(invocationMetadataCollection)) + { invocationContext.Interceptor.AfterInvoke(invocationContext, invocationContext.GetMethodReturnValue()); } } } - internal class InterceptorData - { - public List InvocationContexts { get; set; } - public IOrderingStrategy OrderingStrategy { get; set; } - - public bool DontProceed { get; set; } - } - } diff --git a/SimpleProxy/SimpleProxy.csproj b/SimpleProxy/SimpleProxy.csproj index 1a0addb..aa092ae 100644 --- a/SimpleProxy/SimpleProxy.csproj +++ b/SimpleProxy/SimpleProxy.csproj @@ -4,21 +4,21 @@ netcoreapp3.1 Simple Proxy is a simple extension library built to solve the problem of Aspect Orientated Programming in Net Core projects. Robert Perry - https://github.com/f135ta/SimpleProxy - 1.0.9 + + 1.0.11 false SimpleProxyCp SimpleProxyCp SimpleProxyCp SimpleProxyCp LICENSE - 1.0.9.0 - 1.0.9.0 - - + + + + @@ -28,9 +28,4 @@ - - - - - From 24ec3487ea7f7dda437fb35419793d6819035cd3 Mon Sep 17 00:00:00 2001 From: "shoguns6@yahoo.com" Date: Mon, 28 Jun 2021 16:55:32 +0530 Subject: [PATCH 12/13] Update --- SimpleProxy/SimpleProxy.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SimpleProxy/SimpleProxy.csproj b/SimpleProxy/SimpleProxy.csproj index aa092ae..02831e1 100644 --- a/SimpleProxy/SimpleProxy.csproj +++ b/SimpleProxy/SimpleProxy.csproj @@ -17,8 +17,8 @@ - - + + From 90231b933f8631235a6d58017157693ca4639c87 Mon Sep 17 00:00:00 2001 From: "shoguns6@yahoo.com" Date: Mon, 28 Jun 2021 17:06:06 +0530 Subject: [PATCH 13/13] UPdate --- .../AsyncDeterminationInterceptor.cs | 115 -- .../AsyncInterceptorBase.cs | 205 --- .../AsyncTimingInterceptor.cs | 55 - .../Castle.Core.AsyncInterceptor.csproj | 56 - .../IAsyncInterceptor.cs | 32 - .../NoCoverage/RethrowHelper.cs | 67 - .../ProcessingAsyncInterceptor.cs | 147 -- .../Properties/AssemblyInfo.cs | 35 - .../ProxyGeneratorExtensions.cs | 444 ----- Castle.Core.AsyncInterceptor/SharedKey.snk | Bin 596 -> 0 bytes Castle.Core/Castle.Core.csproj | 31 - .../AbstractDictionaryAdapter.cs | 170 -- .../AbstractDictionaryAdapterVisitor.cs | 159 -- .../Attributes/ComponentAttribute.cs | 94 - .../Attributes/DictionaryAdapterAttribute.cs | 32 - .../Attributes/DictionaryBehaviorAttribute.cs | 40 - .../Attributes/FetchAttribute.cs | 45 - .../Attributes/GroupAttribute.cs | 48 - .../Attributes/IfExistsAttribute.cs | 26 - .../Attributes/KeyAttribute.cs | 50 - .../Attributes/KeyPrefixAttribute.cs | 54 - .../Attributes/KeySubstitutionAttribute.cs | 44 - .../Attributes/MultiLevelEditAttribute.cs | 30 - .../Attributes/NewGuidAttribute.cs | 39 - .../Attributes/OnDemandAttribute.cs | 198 --- .../Attributes/ReferenceAttribute.cs | 27 - .../Attributes/RemoveIfAttribute.cs | 123 -- .../Attributes/RemoveIfEmptyAttribute.cs | 60 - .../Attributes/StringFormatAttribute.cs | 77 - .../Attributes/StringListAttribute.cs | 245 --- .../Attributes/StringStorageAttribute.cs | 28 - .../Attributes/StringValuesAttribute.cs | 58 - .../SuppressNotificationsAttribute.cs | 30 - .../Attributes/TypeKeyPrefixAttribute.cs | 30 - .../Attributes/VolatileAttribute.cs | 26 - .../Attributes/XPathAttribute.cs | 57 - .../Attributes/XPathFunctionAttribute.cs | 38 - .../Attributes/XPathVariableAttribute.cs | 34 - .../Attributes/XmlDefaultsAttribute.cs | 26 - .../Attributes/XmlNamespaceAttribute.cs | 36 - .../CascadingDictionaryAdapter.cs | 56 - .../DefaultPropertyGetter.cs | 74 - .../DictionaryAdapterBase.Coerce.cs | 40 - .../DictionaryAdapterBase.Copy.cs | 56 - .../DictionaryAdapterBase.Create.cs | 61 - .../DictionaryAdapterBase.Edit.cs | 244 --- .../DictionaryAdapterBase.Notify.cs | 215 --- .../DictionaryAdapterBase.Validate.cs | 105 -- .../DictionaryAdapterBase.cs | 216 --- .../DictionaryAdapterExtensions.cs | 29 - .../DictionaryAdapterFactory.cs | 495 ------ .../DictionaryAdapterInstance.cs | 154 -- .../DictionaryAdapterMeta.cs | 130 -- .../DictionaryValidateGroup.cs | 106 -- .../DynamicDictionary.cs | 52 - .../GenericDictionaryAdapter.cs | 66 - .../IDictionaryAdapter.cs | 52 - .../IDictionaryAdapterFactory.cs | 128 -- .../IDictionaryAdapterVisitor.cs | 34 - .../IDictionaryBehavior.cs | 33 - .../IDictionaryBehaviorBuilder.cs | 29 - .../IDictionaryCoerceStrategy.cs | 23 - .../IDictionaryCopyStrategy.cs | 23 - .../IDictionaryCreate.cs | 37 - .../IDictionaryCreateStrategy.cs | 24 - .../IDictionaryEdit.cs | 37 - .../IDictionaryEqualityHashCodeStrategy.cs | 23 - .../IDictionaryInitializer.cs | 29 - .../IDictionaryKeyBuilder.cs | 34 - .../IDictionaryMetaInitializer.cs | 43 - .../IDictionaryNotify.cs | 37 - .../IDictionaryPropertyGetter.cs | 36 - .../IDictionaryPropertySetter.cs | 34 - .../IDictionaryReferenceManager.cs | 26 - .../IDictionaryValidate.cs | 35 - .../IDictionaryValidator.cs | 50 - .../IPropertyDescriptorInitializer.cs | 29 - .../MemberwiseEqualityHashCodeStrategy.cs | 152 -- .../NameValueCollectionAdapter.cs | 93 - .../PropertyChangedEventArgsEx.cs | 41 - .../PropertyChangingEventArgsEx.cs | 48 - .../PropertyDescriptor.cs | 471 ----- .../Util/BindingList.cs | 325 ---- .../Util/BindingListInitializer.cs | 114 -- .../Util/DynamicValue.cs | 36 - .../Util/DynamicValueDelegate.cs | 33 - .../Util/EditableBindingList.cs | 94 - .../Util/EditableList.cs | 107 -- .../Util/IBindingList.cs | 42 - .../Util/IBindingListSource.cs | 23 - .../Util/ICollectionAdapter.cs | 45 - .../Util/ICollectionAdapterObserver.cs | 27 - .../Util/ICollectionProjection.cs | 25 - .../Util/ICondition.cs | 24 - .../Util/IDynamicValue.cs | 33 - .../Util/IValueInitializer.cs | 21 - .../Util/IVirtual.cs | 36 - .../Util/IVirtualSite.cs | 21 - .../Util/IVirtualTarget.cs | 21 - .../Util/ListProjection.cs | 603 ------- .../Util/ListProjectionDebugView.cs | 48 - .../Util/SetProjection.cs | 159 -- .../Util/VirtualObject.cs | 97 - .../Util/VirtualSite.cs | 74 - .../Xml/Core/DefaultXmlReferenceFormat.cs | 65 - .../Xml/Core/IXmlReferenceFormat.cs | 28 - .../Xml/Core/XmlAdapter.cs | 504 ------ .../Xml/Core/XmlMetadata.cs | 385 ---- .../Xml/Core/XmlMetadataBehavior.cs | 56 - .../Xml/Core/XmlReferenceManager.cs | 584 ------ .../Xml/Internal/Accessors/IXmlAccessor.cs | 32 - .../Accessors/IXmlBehaviorSemantics.cs | 25 - .../Accessors/IXmlCollectionAccessor.cs | 25 - .../Accessors/IXmlPropertyAccessor.cs | 24 - .../Accessors/XPathBehaviorAccessor.cs | 220 --- .../Xml/Internal/Accessors/XmlAccessor.cs | 345 ---- .../Internal/Accessors/XmlAccessorFactory.cs | 22 - .../Accessors/XmlArrayBehaviorAccessor.cs | 131 -- .../Accessors/XmlAttributeBehaviorAccessor.cs | 64 - .../Accessors/XmlDefaultBehaviorAccessor.cs | 50 - .../Accessors/XmlElementBehaviorAccessor.cs | 122 -- .../Accessors/XmlIgnoreBehaviorAccessor.cs | 111 -- .../Xml/Internal/Accessors/XmlNodeAccessor.cs | 223 --- .../Xml/Internal/Accessors/XmlSelfAccessor.cs | 37 - .../Collections/XmlCollectionAdapter.cs | 258 --- .../Internal/Collections/XmlCollectionItem.cs | 41 - .../Xml/Internal/Collections/XmlNodeList.cs | 41 - .../Xml/Internal/Collections/XmlNodeSet.cs | 41 - .../Xml/Internal/Cursors/Base/CursorFlags.cs | 57 - .../Xml/Internal/Cursors/Base/IXmlContext.cs | 33 - .../Xml/Internal/Cursors/Base/IXmlCursor.cs | 30 - .../Xml/Internal/Cursors/Base/IXmlIterator.cs | 23 - .../Cursors/Base/IXmlNamespaceSource.cs | 22 - .../Xml/Internal/Cursors/Base/IXmlNode.cs | 55 - .../Internal/Cursors/Base/IXmlNodeSource.cs | 21 - .../Xml/Internal/Cursors/Base/XmlContext.cs | 62 - .../Internal/Cursors/Base/XmlContextBase.cs | 287 --- .../Internal/Cursors/Base/XmlExtensions.cs | 46 - .../Xml/Internal/Cursors/Base/XmlName.cs | 100 -- .../Internal/Cursors/Base/XmlNameComparer.cs | 52 - .../Xml/Internal/Cursors/Base/XmlNodeBase.cs | 81 - .../Cursors/Base/XmlPositionComparer.cs | 94 - .../Internal/Cursors/Base/XmlSelfCursor.cs | 250 --- .../Cursors/SystemXml/SysXmlCursor.cs | 566 ------ .../Cursors/SystemXml/SysXmlExtensions.cs | 57 - .../Internal/Cursors/SystemXml/SysXmlNode.cs | 298 ---- .../SystemXml/SysXmlSubtreeIterator.cs | 96 - .../Internal/Cursors/XPath/CompiledXPath.cs | 88 - .../Cursors/XPath/CompiledXPathNode.cs | 136 -- .../Cursors/XPath/CompiledXPathStep.cs | 44 - .../XPath/XPathBufferedNodeIterator.cs | 83 - .../Internal/Cursors/XPath/XPathCompiler.cs | 452 ----- .../Internal/Cursors/XPath/XPathContext.cs | 68 - .../Internal/Cursors/XPath/XPathExtensions.cs | 76 - .../Cursors/XPath/XPathMutableCursor.cs | 415 ----- .../Xml/Internal/Cursors/XPath/XPathNode.cs | 233 --- .../Cursors/XPath/XPathReadOnlyCursor.cs | 140 -- .../Xml/Internal/Namespaces/Wsdl.cs | 27 - .../Xml/Internal/Namespaces/XRef.cs | 53 - .../Xml/Internal/Namespaces/Xmlns.cs | 23 - .../Xml/Internal/Namespaces/Xsd.cs | 26 - .../Xml/Internal/Namespaces/Xsi.cs | 75 - .../Serializers/XmlArraySerializer.cs | 102 -- .../Serializers/XmlCollectionSerializer.cs | 76 - .../Serializers/XmlComponentSerializer.cs | 73 - .../Serializers/XmlCustomSerializer.cs | 60 - .../Serializers/XmlDefaultSerializer.cs | 55 - .../Serializers/XmlDynamicSerializer.cs | 44 - .../Serializers/XmlEnumerationSerializer.cs | 36 - .../Internal/Serializers/XmlListSerializer.cs | 31 - .../Internal/Serializers/XmlSetSerializer.cs | 31 - .../Serializers/XmlSimpleSerializer.cs | 82 - .../Serializers/XmlStringSerializer.cs | 39 - .../Xml/Internal/Serializers/XmlTypeKind.cs | 23 - .../Internal/Serializers/XmlTypeSerializer.cs | 42 - .../Serializers/XmlTypeSerializerCache.cs | 98 -- .../Serializers/XmlXmlNodeSerializer.cs | 49 - .../Xml/Internal/Types/IXmlIdentity.cs | 22 - .../Xml/Internal/Types/IXmlIncludedType.cs | 24 - .../Xml/Internal/Types/IXmlIncludedTypeMap.cs | 38 - .../Xml/Internal/Types/IXmlKnownType.cs | 23 - .../Xml/Internal/Types/IXmlKnownTypeMap.cs | 38 - .../Xml/Internal/Types/XmlIncludedType.cs | 48 - .../Xml/Internal/Types/XmlIncludedTypeSet.cs | 95 - .../Xml/Internal/Types/XmlKnownType.cs | 61 - .../Xml/Internal/Types/XmlKnownTypeSet.cs | 176 -- .../Utilities/DictionaryAdapterExtensions.cs | 90 - .../Xml/Internal/Utilities/Error.cs | 219 --- .../Xml/Internal/Utilities/IConfigurable.cs | 21 - .../Xml/Internal/Utilities/IRealizable.cs | 40 - .../Internal/Utilities/SingletonDispenser.cs | 131 -- .../Internal/Utilities/StringExtensions.cs | 26 - .../Xml/Internal/Utilities/Try.cs | 35 - .../Xml/Internal/Utilities/TypeExtensions.cs | 54 - .../Internal/Utilities/XmlSubtreeReader.cs | 227 --- .../Internal/Utilities/XmlSubtreeWriter.cs | 355 ---- .../Configuration/AbstractConfiguration.cs | 99 -- .../ConfigurationAttributeCollection.cs | 38 - .../Configuration/ConfigurationCollection.cs | 58 - .../Core/Configuration/IConfiguration.cs | 65 - .../Configuration/MutableConfiguration.cs | 75 - .../Xml/XmlConfigurationDeserializer.cs | 80 - Castle.Core/Core/IServiceEnabledComponent.cs | 34 - Castle.Core/Core/IServiceProviderEx.cs | 26 - .../Core/IServiceProviderExAccessor.cs | 31 - Castle.Core/Core/Internal/AttributesUtil.cs | 146 -- .../Core/Internal/InterfaceAttributeUtil.cs | 190 -- Castle.Core/Core/Internal/InternalsVisible.cs | 47 - .../Core/Internal/SynchronizedDictionary.cs | 120 -- Castle.Core/Core/Internal/TypeExtensions.cs | 37 - Castle.Core/Core/Internal/WeakKey.cs | 45 - Castle.Core/Core/Internal/WeakKeyComparer.cs | 71 - .../Core/Internal/WeakKeyDictionary.cs | 246 --- .../Logging/AbstractExtendedLoggerFactory.cs | 111 -- .../Core/Logging/AbstractLoggerFactory.cs | 70 - Castle.Core/Core/Logging/ConsoleFactory.cs | 59 - Castle.Core/Core/Logging/ConsoleLogger.cs | 100 -- Castle.Core/Core/Logging/DiagnosticsLogger.cs | 146 -- .../Core/Logging/DiagnosticsLoggerFactory.cs | 38 - .../Core/Logging/IContextProperties.cs | 43 - Castle.Core/Core/Logging/IContextStack.cs | 29 - Castle.Core/Core/Logging/IContextStacks.cs | 21 - Castle.Core/Core/Logging/IExtendedLogger.cs | 39 - .../Core/Logging/IExtendedLoggerFactory.cs | 45 - Castle.Core/Core/Logging/ILogger.cs | 374 ---- Castle.Core/Core/Logging/ILoggerFactory.cs | 44 - .../Core/Logging/LevelFilteredLogger.cs | 787 --------- Castle.Core/Core/Logging/LoggerException.cs | 39 - Castle.Core/Core/Logging/LoggerLevel.cs | 51 - Castle.Core/Core/Logging/NullLogFactory.cs | 46 - Castle.Core/Core/Logging/NullLogger.cs | 532 ------ Castle.Core/Core/Logging/StreamLogger.cs | 160 -- .../Core/Logging/StreamLoggerFactory.cs | 44 - Castle.Core/Core/Logging/TraceLogger.cs | 227 --- .../Core/Logging/TraceLoggerFactory.cs | 57 - Castle.Core/Core/ProxyServices.cs | 41 - Castle.Core/Core/ReferenceEqualityComparer.cs | 58 - .../Core/ReflectionBasedDictionaryAdapter.cs | 299 ---- Castle.Core/Core/Resource/AbstractResource.cs | 46 - .../Core/Resource/AbstractStreamResource.cs | 54 - .../Core/Resource/AssemblyBundleResource.cs | 72 - Castle.Core/Core/Resource/AssemblyResource.cs | 156 -- .../Core/Resource/AssemblyResourceFactory.cs | 41 - Castle.Core/Core/Resource/ConfigResource.cs | 78 - .../Core/Resource/ConfigResourceFactory.cs | 44 - Castle.Core/Core/Resource/CustomUri.cs | 139 -- Castle.Core/Core/Resource/FileResource.cs | 119 -- .../Core/Resource/FileResourceFactory.cs | 46 - Castle.Core/Core/Resource/IResource.cs | 56 - Castle.Core/Core/Resource/IResourceFactory.cs | 48 - .../Core/Resource/ResourceException.cs | 39 - .../Core/Resource/StaticContentResource.cs | 48 - Castle.Core/Core/Resource/UncResource.cs | 102 -- .../Core/Resource/UncResourceFactory.cs | 40 - Castle.Core/Core/Smtp/DefaultSmtpSender.cs | 250 --- Castle.Core/Core/Smtp/IEmailSender.cs | 46 - .../Core/StringObjectDictionaryAdapter.cs | 227 --- .../DynamicProxy/AbstractInvocation.cs | 211 --- Castle.Core/DynamicProxy/AllMethodsHook.cs | 56 - .../Contributors/ClassMembersCollector.cs | 46 - .../ClassProxySerializableContributor.cs | 247 --- .../ClassProxyTargetContributor.cs | 180 -- .../ClassProxyWithTargetTargetContributor.cs | 180 -- .../Contributors/CompositeTypeContributor.cs | 184 -- .../DelegateTypeMembersCollector.cs | 42 - .../DynamicProxy/Contributors/Delegates.cs | 28 - .../Contributors/FieldReferenceComparer.cs | 37 - .../IInvocationCreationContributor.cs | 33 - .../Contributors/IMembersCollectorSink.cs | 25 - .../Contributors/ITypeContributor.cs | 29 - .../Contributors/InterfaceMembersCollector.cs | 40 - .../InterfaceMembersOnClassCollector.cs | 68 - .../InterfaceProxySerializableContributor.cs | 54 - .../InterfaceProxyTargetContributor.cs | 101 -- ...rfaceProxyWithOptionalTargetContributor.cs | 43 - ...oxyWithTargetInterfaceTargetContributor.cs | 34 - .../InterfaceProxyWithoutTargetContributor.cs | 97 - .../InvocationWithDelegateContributor.cs | 107 -- ...nvocationWithGenericDelegateContributor.cs | 88 - .../Contributors/MembersCollector.cs | 228 --- .../Contributors/MixinContributor.cs | 153 -- .../NonInheritableAttributesContributor.cs | 47 - .../ProxyTargetAccessorContributor.cs | 74 - .../Contributors/SerializableContributor.cs | 153 -- .../WrappedClassMembersCollector.cs | 82 - .../DynamicProxy/CustomAttributeInfo.cs | 347 ---- .../DynamicProxy/DefaultProxyBuilder.cs | 164 -- Castle.Core/DynamicProxy/DynProxy.snk | Bin 596 -> 0 bytes .../DynamicProxy/DynamicProxyException.cs | 39 - .../DynamicProxy/ExceptionMessageBuilder.cs | 87 - .../AttributesToAvoidReplicating.cs | 63 - .../Generators/BaseClassProxyGenerator.cs | 219 --- .../Generators/BaseInterfaceProxyGenerator.cs | 296 ---- .../Generators/BaseProxyGenerator.cs | 409 ----- .../DynamicProxy/Generators/CacheKey.cs | 113 -- .../Generators/ClassProxyGenerator.cs | 58 - .../ClassProxyWithTargetGenerator.cs | 80 - .../CompositionInvocationTypeGenerator.cs | 71 - .../Generators/DelegateTypeGenerator.cs | 109 -- .../Emitters/AbstractTypeEmitter.cs | 374 ---- .../Generators/Emitters/ArgumentsUtil.cs | 105 -- .../Generators/Emitters/ClassEmitter.cs | 109 -- .../Generators/Emitters/CodeBuilder.cs | 68 - .../Generators/Emitters/ConstructorEmitter.cs | 94 - .../Generators/Emitters/EventEmitter.cs | 99 -- .../Generators/Emitters/GenericUtil.cs | 160 -- .../Generators/Emitters/IMemberEmitter.cs | 30 - .../Emitters/LdcOpCodesDictionary.cs | 69 - .../Emitters/LdindOpCodesDictionary.cs | 70 - .../Generators/Emitters/MethodEmitter.cs | 350 ---- .../Generators/Emitters/NestedClassEmitter.cs | 52 - .../Generators/Emitters/OpCodeUtil.cs | 178 -- .../Generators/Emitters/PropertyEmitter.cs | 116 -- .../Emitters/SimpleAST/ArgumentReference.cs | 78 - .../Emitters/SimpleAST/AsTypeReference.cs | 63 - .../SimpleAST/AssignArgumentStatement.cs | 36 - .../SimpleAST/AssignArrayStatement.cs | 43 - .../Emitters/SimpleAST/AssignStatement.cs | 37 - .../Emitters/SimpleAST/BlockStatement.cs | 37 - .../Emitters/SimpleAST/ByRefReference.cs | 48 - .../ConstructorInvocationStatement.cs | 71 - .../Emitters/SimpleAST/ConvertExpression.cs | 116 -- .../SimpleAST/DefaultValueExpression.cs | 84 - .../SimpleAST/EndExceptionBlockStatement.cs | 26 - .../Emitters/SimpleAST/FieldReference.cs | 95 - .../Emitters/SimpleAST/FinallyStatement.cs | 26 - .../Emitters/SimpleAST/IExpression.cs | 20 - .../SimpleAST/IExpressionOrStatement.cs | 23 - .../Emitters/SimpleAST/IStatement.cs | 20 - .../Emitters/SimpleAST/IfNullExpression.cs | 62 - .../Emitters/SimpleAST/IndirectReference.cs | 73 - .../SimpleAST/LiteralBoolExpression.cs | 33 - .../SimpleAST/LiteralIntExpression.cs | 68 - .../SimpleAST/LiteralStringExpression.cs | 33 - .../LoadRefArrayElementExpression.cs | 37 - .../Emitters/SimpleAST/LocalReference.cs | 50 - .../SimpleAST/MethodInvocationExpression.cs | 69 - .../SimpleAST/MethodTokenExpression.cs | 43 - .../Emitters/SimpleAST/NewArrayExpression.cs | 37 - .../SimpleAST/NewInstanceExpression.cs | 51 - .../NullCoalescingOperatorExpression.cs | 52 - .../Emitters/SimpleAST/NullExpression.cs | 32 - .../Emitters/SimpleAST/Reference.cs | 53 - .../ReferencesToObjectArrayExpression.cs | 67 - .../Emitters/SimpleAST/ReturnStatement.cs | 52 - .../Emitters/SimpleAST/SelfReference.cs | 45 - .../Emitters/SimpleAST/ThrowStatement.cs | 44 - .../Emitters/SimpleAST/TryStatement.cs | 26 - .../Emitters/SimpleAST/TypeReference.cs | 37 - .../Emitters/SimpleAST/TypeTokenExpression.cs | 37 - .../Emitters/StindOpCodesDictionary.cs | 70 - .../Generators/Emitters/StrongNameUtil.cs | 61 - .../Emitters/TypeConstructorEmitter.cs | 34 - .../Generators/ForwardingMethodGenerator.cs | 46 - .../DynamicProxy/Generators/GeneratorUtil.cs | 131 -- .../DynamicProxy/Generators/IGenerator.cs | 23 - .../DynamicProxy/Generators/INamingScope.cs | 45 - .../InheritanceInvocationTypeGenerator.cs | 59 - .../InterfaceProxyWithTargetGenerator.cs | 68 - ...erfaceProxyWithTargetInterfaceGenerator.cs | 74 - .../InterfaceProxyWithoutTargetGenerator.cs | 59 - .../Generators/InvocationTypeGenerator.cs | 311 ---- .../DynamicProxy/Generators/MetaEvent.cs | 151 -- .../DynamicProxy/Generators/MetaMethod.cs | 143 -- .../DynamicProxy/Generators/MetaProperty.cs | 199 --- .../DynamicProxy/Generators/MetaType.cs | 64 - .../Generators/MetaTypeElement.cs | 99 -- .../Generators/MetaTypeElementCollection.cs | 68 - .../DynamicProxy/Generators/MethodFinder.cs | 83 - .../Generators/MethodGenerator.cs | 59 - .../Generators/MethodSignatureComparer.cs | 159 -- .../MethodWithInvocationGenerator.cs | 251 --- .../MinimialisticMethodGenerator.cs | 61 - .../DynamicProxy/Generators/NamingScope.cs | 61 - .../OptionallyForwardingMethodGenerator.cs | 93 - .../DynamicProxy/IChangeProxyTarget.cs | 59 - Castle.Core/DynamicProxy/IInterceptor.cs | 24 - .../DynamicProxy/IInterceptorSelector.cs | 42 - Castle.Core/DynamicProxy/IInvocation.cs | 135 -- .../DynamicProxy/IInvocationProceedInfo.cs | 31 - Castle.Core/DynamicProxy/IProxyBuilder.cs | 137 -- .../DynamicProxy/IProxyGenerationHook.cs | 50 - Castle.Core/DynamicProxy/IProxyGenerator.cs | 1033 ----------- .../DynamicProxy/IProxyTargetAccessor.cs | 39 - .../DynamicProxy/Internal/AttributeUtil.cs | 251 --- .../Internal/CompositionInvocation.cs | 86 - .../Internal/InheritanceInvocation.cs | 52 - .../InterfaceMethodWithoutTargetInvocation.cs | 61 - .../DynamicProxy/Internal/InvocationHelper.cs | 132 -- Castle.Core/DynamicProxy/Internal/TypeUtil.cs | 225 --- Castle.Core/DynamicProxy/MixinData.cs | 210 --- Castle.Core/DynamicProxy/ModuleScope.cs | 539 ------ .../DynamicProxy/PersistentProxyBuilder.cs | 49 - .../DynamicProxy/ProxyGenerationOptions.cs | 353 ---- Castle.Core/DynamicProxy/ProxyGenerator.cs | 1564 ----------------- Castle.Core/DynamicProxy/ProxyUtil.cs | 236 --- .../Serialization/CacheMappingsAttribute.cs | 73 - .../Serialization/ProxyObjectReference.cs | 294 ---- .../Serialization/ProxyTypeConstants.cs | 25 - .../DynamicProxy/StandardInterceptor.cs | 44 - .../DynamicProxy/Tokens/DelegateMethods.cs | 25 - .../Tokens/FormatterServicesMethods.cs | 33 - .../Tokens/InterceptorSelectorMethods.cs | 23 - .../DynamicProxy/Tokens/InvocationMethods.cs | 103 -- .../DynamicProxy/Tokens/MethodBaseMethods.cs | 25 - .../Tokens/SerializationInfoMethods.cs | 60 - .../DynamicProxy/Tokens/TypeMethods.cs | 26 - .../DynamicProxy/Tokens/TypeUtilMethods.cs | 26 - .../Properties/InternalsVisibleToTests.cs | 17 - SimpleProxy.sln | 16 - 410 files changed, 42495 deletions(-) delete mode 100644 Castle.Core.AsyncInterceptor/AsyncDeterminationInterceptor.cs delete mode 100644 Castle.Core.AsyncInterceptor/AsyncInterceptorBase.cs delete mode 100644 Castle.Core.AsyncInterceptor/AsyncTimingInterceptor.cs delete mode 100644 Castle.Core.AsyncInterceptor/Castle.Core.AsyncInterceptor.csproj delete mode 100644 Castle.Core.AsyncInterceptor/IAsyncInterceptor.cs delete mode 100644 Castle.Core.AsyncInterceptor/NoCoverage/RethrowHelper.cs delete mode 100644 Castle.Core.AsyncInterceptor/ProcessingAsyncInterceptor.cs delete mode 100644 Castle.Core.AsyncInterceptor/Properties/AssemblyInfo.cs delete mode 100644 Castle.Core.AsyncInterceptor/ProxyGeneratorExtensions.cs delete mode 100644 Castle.Core.AsyncInterceptor/SharedKey.snk delete mode 100644 Castle.Core/Castle.Core.csproj delete mode 100644 Castle.Core/Components.DictionaryAdapter/AbstractDictionaryAdapter.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/AbstractDictionaryAdapterVisitor.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Attributes/ComponentAttribute.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Attributes/DictionaryAdapterAttribute.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Attributes/DictionaryBehaviorAttribute.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Attributes/FetchAttribute.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Attributes/GroupAttribute.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Attributes/IfExistsAttribute.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Attributes/KeyAttribute.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Attributes/KeyPrefixAttribute.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Attributes/KeySubstitutionAttribute.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Attributes/MultiLevelEditAttribute.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Attributes/NewGuidAttribute.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Attributes/OnDemandAttribute.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Attributes/ReferenceAttribute.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Attributes/RemoveIfAttribute.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Attributes/RemoveIfEmptyAttribute.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Attributes/StringFormatAttribute.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Attributes/StringListAttribute.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Attributes/StringStorageAttribute.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Attributes/StringValuesAttribute.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Attributes/SuppressNotificationsAttribute.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Attributes/TypeKeyPrefixAttribute.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Attributes/VolatileAttribute.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Attributes/XPathAttribute.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Attributes/XPathFunctionAttribute.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Attributes/XPathVariableAttribute.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Attributes/XmlDefaultsAttribute.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Attributes/XmlNamespaceAttribute.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/CascadingDictionaryAdapter.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/DefaultPropertyGetter.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/DictionaryAdapterBase.Coerce.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/DictionaryAdapterBase.Copy.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/DictionaryAdapterBase.Create.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/DictionaryAdapterBase.Edit.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/DictionaryAdapterBase.Notify.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/DictionaryAdapterBase.Validate.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/DictionaryAdapterBase.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/DictionaryAdapterExtensions.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/DictionaryAdapterFactory.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/DictionaryAdapterInstance.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/DictionaryAdapterMeta.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/DictionaryValidateGroup.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/DynamicDictionary.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/GenericDictionaryAdapter.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/IDictionaryAdapter.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/IDictionaryAdapterFactory.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/IDictionaryAdapterVisitor.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/IDictionaryBehavior.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/IDictionaryBehaviorBuilder.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/IDictionaryCoerceStrategy.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/IDictionaryCopyStrategy.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/IDictionaryCreate.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/IDictionaryCreateStrategy.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/IDictionaryEdit.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/IDictionaryEqualityHashCodeStrategy.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/IDictionaryInitializer.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/IDictionaryKeyBuilder.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/IDictionaryMetaInitializer.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/IDictionaryNotify.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/IDictionaryPropertyGetter.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/IDictionaryPropertySetter.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/IDictionaryReferenceManager.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/IDictionaryValidate.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/IDictionaryValidator.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/IPropertyDescriptorInitializer.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/MemberwiseEqualityHashCodeStrategy.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/NameValueCollectionAdapter.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/PropertyChangedEventArgsEx.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/PropertyChangingEventArgsEx.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/PropertyDescriptor.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Util/BindingList.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Util/BindingListInitializer.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Util/DynamicValue.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Util/DynamicValueDelegate.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Util/EditableBindingList.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Util/EditableList.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Util/IBindingList.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Util/IBindingListSource.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Util/ICollectionAdapter.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Util/ICollectionAdapterObserver.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Util/ICollectionProjection.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Util/ICondition.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Util/IDynamicValue.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Util/IValueInitializer.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Util/IVirtual.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Util/IVirtualSite.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Util/IVirtualTarget.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Util/ListProjection.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Util/ListProjectionDebugView.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Util/SetProjection.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Util/VirtualObject.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Util/VirtualSite.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Core/DefaultXmlReferenceFormat.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Core/IXmlReferenceFormat.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Core/XmlAdapter.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Core/XmlMetadata.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Core/XmlMetadataBehavior.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Core/XmlReferenceManager.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/IXmlAccessor.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/IXmlBehaviorSemantics.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/IXmlCollectionAccessor.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/IXmlPropertyAccessor.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XPathBehaviorAccessor.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlAccessor.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlAccessorFactory.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlArrayBehaviorAccessor.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlAttributeBehaviorAccessor.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlDefaultBehaviorAccessor.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlElementBehaviorAccessor.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlIgnoreBehaviorAccessor.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlNodeAccessor.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlSelfAccessor.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Collections/XmlCollectionAdapter.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Collections/XmlCollectionItem.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Collections/XmlNodeList.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Collections/XmlNodeSet.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/CursorFlags.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/IXmlContext.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/IXmlCursor.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/IXmlIterator.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/IXmlNamespaceSource.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/IXmlNode.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/IXmlNodeSource.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/XmlContext.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/XmlContextBase.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/XmlExtensions.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/XmlName.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/XmlNameComparer.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/XmlNodeBase.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/XmlPositionComparer.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/XmlSelfCursor.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/SystemXml/SysXmlCursor.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/SystemXml/SysXmlExtensions.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/SystemXml/SysXmlNode.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/SystemXml/SysXmlSubtreeIterator.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/CompiledXPath.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/CompiledXPathNode.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/CompiledXPathStep.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/XPathBufferedNodeIterator.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/XPathCompiler.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/XPathContext.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/XPathExtensions.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/XPathMutableCursor.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/XPathNode.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/XPathReadOnlyCursor.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Namespaces/Wsdl.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Namespaces/XRef.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Namespaces/Xmlns.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Namespaces/Xsd.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Namespaces/Xsi.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlArraySerializer.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlCollectionSerializer.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlComponentSerializer.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlCustomSerializer.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlDefaultSerializer.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlDynamicSerializer.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlEnumerationSerializer.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlListSerializer.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlSetSerializer.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlSimpleSerializer.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlStringSerializer.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlTypeKind.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlTypeSerializer.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlTypeSerializerCache.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlXmlNodeSerializer.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/IXmlIdentity.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/IXmlIncludedType.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/IXmlIncludedTypeMap.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/IXmlKnownType.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/IXmlKnownTypeMap.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/XmlIncludedType.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/XmlIncludedTypeSet.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/XmlKnownType.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/XmlKnownTypeSet.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/DictionaryAdapterExtensions.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/Error.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/IConfigurable.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/IRealizable.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/SingletonDispenser.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/StringExtensions.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/Try.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/TypeExtensions.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/XmlSubtreeReader.cs delete mode 100644 Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/XmlSubtreeWriter.cs delete mode 100644 Castle.Core/Core/Configuration/AbstractConfiguration.cs delete mode 100644 Castle.Core/Core/Configuration/ConfigurationAttributeCollection.cs delete mode 100644 Castle.Core/Core/Configuration/ConfigurationCollection.cs delete mode 100644 Castle.Core/Core/Configuration/IConfiguration.cs delete mode 100644 Castle.Core/Core/Configuration/MutableConfiguration.cs delete mode 100644 Castle.Core/Core/Configuration/Xml/XmlConfigurationDeserializer.cs delete mode 100644 Castle.Core/Core/IServiceEnabledComponent.cs delete mode 100644 Castle.Core/Core/IServiceProviderEx.cs delete mode 100644 Castle.Core/Core/IServiceProviderExAccessor.cs delete mode 100644 Castle.Core/Core/Internal/AttributesUtil.cs delete mode 100644 Castle.Core/Core/Internal/InterfaceAttributeUtil.cs delete mode 100644 Castle.Core/Core/Internal/InternalsVisible.cs delete mode 100644 Castle.Core/Core/Internal/SynchronizedDictionary.cs delete mode 100644 Castle.Core/Core/Internal/TypeExtensions.cs delete mode 100644 Castle.Core/Core/Internal/WeakKey.cs delete mode 100644 Castle.Core/Core/Internal/WeakKeyComparer.cs delete mode 100644 Castle.Core/Core/Internal/WeakKeyDictionary.cs delete mode 100644 Castle.Core/Core/Logging/AbstractExtendedLoggerFactory.cs delete mode 100644 Castle.Core/Core/Logging/AbstractLoggerFactory.cs delete mode 100644 Castle.Core/Core/Logging/ConsoleFactory.cs delete mode 100644 Castle.Core/Core/Logging/ConsoleLogger.cs delete mode 100644 Castle.Core/Core/Logging/DiagnosticsLogger.cs delete mode 100644 Castle.Core/Core/Logging/DiagnosticsLoggerFactory.cs delete mode 100644 Castle.Core/Core/Logging/IContextProperties.cs delete mode 100644 Castle.Core/Core/Logging/IContextStack.cs delete mode 100644 Castle.Core/Core/Logging/IContextStacks.cs delete mode 100644 Castle.Core/Core/Logging/IExtendedLogger.cs delete mode 100644 Castle.Core/Core/Logging/IExtendedLoggerFactory.cs delete mode 100644 Castle.Core/Core/Logging/ILogger.cs delete mode 100644 Castle.Core/Core/Logging/ILoggerFactory.cs delete mode 100644 Castle.Core/Core/Logging/LevelFilteredLogger.cs delete mode 100644 Castle.Core/Core/Logging/LoggerException.cs delete mode 100644 Castle.Core/Core/Logging/LoggerLevel.cs delete mode 100644 Castle.Core/Core/Logging/NullLogFactory.cs delete mode 100644 Castle.Core/Core/Logging/NullLogger.cs delete mode 100644 Castle.Core/Core/Logging/StreamLogger.cs delete mode 100644 Castle.Core/Core/Logging/StreamLoggerFactory.cs delete mode 100644 Castle.Core/Core/Logging/TraceLogger.cs delete mode 100644 Castle.Core/Core/Logging/TraceLoggerFactory.cs delete mode 100644 Castle.Core/Core/ProxyServices.cs delete mode 100644 Castle.Core/Core/ReferenceEqualityComparer.cs delete mode 100644 Castle.Core/Core/ReflectionBasedDictionaryAdapter.cs delete mode 100644 Castle.Core/Core/Resource/AbstractResource.cs delete mode 100644 Castle.Core/Core/Resource/AbstractStreamResource.cs delete mode 100644 Castle.Core/Core/Resource/AssemblyBundleResource.cs delete mode 100644 Castle.Core/Core/Resource/AssemblyResource.cs delete mode 100644 Castle.Core/Core/Resource/AssemblyResourceFactory.cs delete mode 100644 Castle.Core/Core/Resource/ConfigResource.cs delete mode 100644 Castle.Core/Core/Resource/ConfigResourceFactory.cs delete mode 100644 Castle.Core/Core/Resource/CustomUri.cs delete mode 100644 Castle.Core/Core/Resource/FileResource.cs delete mode 100644 Castle.Core/Core/Resource/FileResourceFactory.cs delete mode 100644 Castle.Core/Core/Resource/IResource.cs delete mode 100644 Castle.Core/Core/Resource/IResourceFactory.cs delete mode 100644 Castle.Core/Core/Resource/ResourceException.cs delete mode 100644 Castle.Core/Core/Resource/StaticContentResource.cs delete mode 100644 Castle.Core/Core/Resource/UncResource.cs delete mode 100644 Castle.Core/Core/Resource/UncResourceFactory.cs delete mode 100644 Castle.Core/Core/Smtp/DefaultSmtpSender.cs delete mode 100644 Castle.Core/Core/Smtp/IEmailSender.cs delete mode 100644 Castle.Core/Core/StringObjectDictionaryAdapter.cs delete mode 100644 Castle.Core/DynamicProxy/AbstractInvocation.cs delete mode 100644 Castle.Core/DynamicProxy/AllMethodsHook.cs delete mode 100644 Castle.Core/DynamicProxy/Contributors/ClassMembersCollector.cs delete mode 100644 Castle.Core/DynamicProxy/Contributors/ClassProxySerializableContributor.cs delete mode 100644 Castle.Core/DynamicProxy/Contributors/ClassProxyTargetContributor.cs delete mode 100644 Castle.Core/DynamicProxy/Contributors/ClassProxyWithTargetTargetContributor.cs delete mode 100644 Castle.Core/DynamicProxy/Contributors/CompositeTypeContributor.cs delete mode 100644 Castle.Core/DynamicProxy/Contributors/DelegateTypeMembersCollector.cs delete mode 100644 Castle.Core/DynamicProxy/Contributors/Delegates.cs delete mode 100644 Castle.Core/DynamicProxy/Contributors/FieldReferenceComparer.cs delete mode 100644 Castle.Core/DynamicProxy/Contributors/IInvocationCreationContributor.cs delete mode 100644 Castle.Core/DynamicProxy/Contributors/IMembersCollectorSink.cs delete mode 100644 Castle.Core/DynamicProxy/Contributors/ITypeContributor.cs delete mode 100644 Castle.Core/DynamicProxy/Contributors/InterfaceMembersCollector.cs delete mode 100644 Castle.Core/DynamicProxy/Contributors/InterfaceMembersOnClassCollector.cs delete mode 100644 Castle.Core/DynamicProxy/Contributors/InterfaceProxySerializableContributor.cs delete mode 100644 Castle.Core/DynamicProxy/Contributors/InterfaceProxyTargetContributor.cs delete mode 100644 Castle.Core/DynamicProxy/Contributors/InterfaceProxyWithOptionalTargetContributor.cs delete mode 100644 Castle.Core/DynamicProxy/Contributors/InterfaceProxyWithTargetInterfaceTargetContributor.cs delete mode 100644 Castle.Core/DynamicProxy/Contributors/InterfaceProxyWithoutTargetContributor.cs delete mode 100644 Castle.Core/DynamicProxy/Contributors/InvocationWithDelegateContributor.cs delete mode 100644 Castle.Core/DynamicProxy/Contributors/InvocationWithGenericDelegateContributor.cs delete mode 100644 Castle.Core/DynamicProxy/Contributors/MembersCollector.cs delete mode 100644 Castle.Core/DynamicProxy/Contributors/MixinContributor.cs delete mode 100644 Castle.Core/DynamicProxy/Contributors/NonInheritableAttributesContributor.cs delete mode 100644 Castle.Core/DynamicProxy/Contributors/ProxyTargetAccessorContributor.cs delete mode 100644 Castle.Core/DynamicProxy/Contributors/SerializableContributor.cs delete mode 100644 Castle.Core/DynamicProxy/Contributors/WrappedClassMembersCollector.cs delete mode 100644 Castle.Core/DynamicProxy/CustomAttributeInfo.cs delete mode 100644 Castle.Core/DynamicProxy/DefaultProxyBuilder.cs delete mode 100644 Castle.Core/DynamicProxy/DynProxy.snk delete mode 100644 Castle.Core/DynamicProxy/DynamicProxyException.cs delete mode 100644 Castle.Core/DynamicProxy/ExceptionMessageBuilder.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/AttributesToAvoidReplicating.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/BaseClassProxyGenerator.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/BaseInterfaceProxyGenerator.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/BaseProxyGenerator.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/CacheKey.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/ClassProxyGenerator.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/ClassProxyWithTargetGenerator.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/CompositionInvocationTypeGenerator.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/DelegateTypeGenerator.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/AbstractTypeEmitter.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/ArgumentsUtil.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/ClassEmitter.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/CodeBuilder.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/ConstructorEmitter.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/EventEmitter.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/GenericUtil.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/IMemberEmitter.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/LdcOpCodesDictionary.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/LdindOpCodesDictionary.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/MethodEmitter.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/NestedClassEmitter.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/OpCodeUtil.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/PropertyEmitter.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ArgumentReference.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/AsTypeReference.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/AssignArgumentStatement.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/AssignArrayStatement.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/AssignStatement.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/BlockStatement.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ByRefReference.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ConstructorInvocationStatement.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ConvertExpression.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/DefaultValueExpression.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/EndExceptionBlockStatement.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/FieldReference.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/FinallyStatement.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/IExpression.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/IExpressionOrStatement.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/IStatement.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/IfNullExpression.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/IndirectReference.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/LiteralBoolExpression.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/LiteralIntExpression.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/LiteralStringExpression.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/LoadRefArrayElementExpression.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/LocalReference.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/MethodInvocationExpression.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/MethodTokenExpression.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/NewArrayExpression.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/NewInstanceExpression.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/NullCoalescingOperatorExpression.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/NullExpression.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/Reference.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ReferencesToObjectArrayExpression.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ReturnStatement.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/SelfReference.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ThrowStatement.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/TryStatement.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/TypeReference.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/TypeTokenExpression.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/StindOpCodesDictionary.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/StrongNameUtil.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/Emitters/TypeConstructorEmitter.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/ForwardingMethodGenerator.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/GeneratorUtil.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/IGenerator.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/INamingScope.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/InheritanceInvocationTypeGenerator.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/InterfaceProxyWithTargetGenerator.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/InterfaceProxyWithTargetInterfaceGenerator.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/InterfaceProxyWithoutTargetGenerator.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/InvocationTypeGenerator.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/MetaEvent.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/MetaMethod.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/MetaProperty.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/MetaType.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/MetaTypeElement.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/MetaTypeElementCollection.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/MethodFinder.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/MethodGenerator.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/MethodSignatureComparer.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/MethodWithInvocationGenerator.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/MinimialisticMethodGenerator.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/NamingScope.cs delete mode 100644 Castle.Core/DynamicProxy/Generators/OptionallyForwardingMethodGenerator.cs delete mode 100644 Castle.Core/DynamicProxy/IChangeProxyTarget.cs delete mode 100644 Castle.Core/DynamicProxy/IInterceptor.cs delete mode 100644 Castle.Core/DynamicProxy/IInterceptorSelector.cs delete mode 100644 Castle.Core/DynamicProxy/IInvocation.cs delete mode 100644 Castle.Core/DynamicProxy/IInvocationProceedInfo.cs delete mode 100644 Castle.Core/DynamicProxy/IProxyBuilder.cs delete mode 100644 Castle.Core/DynamicProxy/IProxyGenerationHook.cs delete mode 100644 Castle.Core/DynamicProxy/IProxyGenerator.cs delete mode 100644 Castle.Core/DynamicProxy/IProxyTargetAccessor.cs delete mode 100644 Castle.Core/DynamicProxy/Internal/AttributeUtil.cs delete mode 100644 Castle.Core/DynamicProxy/Internal/CompositionInvocation.cs delete mode 100644 Castle.Core/DynamicProxy/Internal/InheritanceInvocation.cs delete mode 100644 Castle.Core/DynamicProxy/Internal/InterfaceMethodWithoutTargetInvocation.cs delete mode 100644 Castle.Core/DynamicProxy/Internal/InvocationHelper.cs delete mode 100644 Castle.Core/DynamicProxy/Internal/TypeUtil.cs delete mode 100644 Castle.Core/DynamicProxy/MixinData.cs delete mode 100644 Castle.Core/DynamicProxy/ModuleScope.cs delete mode 100644 Castle.Core/DynamicProxy/PersistentProxyBuilder.cs delete mode 100644 Castle.Core/DynamicProxy/ProxyGenerationOptions.cs delete mode 100644 Castle.Core/DynamicProxy/ProxyGenerator.cs delete mode 100644 Castle.Core/DynamicProxy/ProxyUtil.cs delete mode 100644 Castle.Core/DynamicProxy/Serialization/CacheMappingsAttribute.cs delete mode 100644 Castle.Core/DynamicProxy/Serialization/ProxyObjectReference.cs delete mode 100644 Castle.Core/DynamicProxy/Serialization/ProxyTypeConstants.cs delete mode 100644 Castle.Core/DynamicProxy/StandardInterceptor.cs delete mode 100644 Castle.Core/DynamicProxy/Tokens/DelegateMethods.cs delete mode 100644 Castle.Core/DynamicProxy/Tokens/FormatterServicesMethods.cs delete mode 100644 Castle.Core/DynamicProxy/Tokens/InterceptorSelectorMethods.cs delete mode 100644 Castle.Core/DynamicProxy/Tokens/InvocationMethods.cs delete mode 100644 Castle.Core/DynamicProxy/Tokens/MethodBaseMethods.cs delete mode 100644 Castle.Core/DynamicProxy/Tokens/SerializationInfoMethods.cs delete mode 100644 Castle.Core/DynamicProxy/Tokens/TypeMethods.cs delete mode 100644 Castle.Core/DynamicProxy/Tokens/TypeUtilMethods.cs delete mode 100644 Castle.Core/Properties/InternalsVisibleToTests.cs diff --git a/Castle.Core.AsyncInterceptor/AsyncDeterminationInterceptor.cs b/Castle.Core.AsyncInterceptor/AsyncDeterminationInterceptor.cs deleted file mode 100644 index 6323070..0000000 --- a/Castle.Core.AsyncInterceptor/AsyncDeterminationInterceptor.cs +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright (c) 2016-2021 James Skimming. All rights reserved. -// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. - -namespace Castle.DynamicProxy -{ - using System; - using System.Collections.Concurrent; - using System.Collections.Generic; - using System.Diagnostics; - using System.Linq; - using System.Reflection; - using System.Threading.Tasks; - - /// - /// Intercepts method invocations and determines if is an asynchronous method. - /// - public class AsyncDeterminationInterceptor : IInterceptor - { - private static readonly MethodInfo HandleAsyncMethodInfo = - typeof(AsyncDeterminationInterceptor) - .GetMethod(nameof(HandleAsyncWithResult), BindingFlags.Static | BindingFlags.NonPublic)!; - - private static readonly ConcurrentDictionary GenericAsyncHandlers = - new ConcurrentDictionary(); - - /// - /// Initializes a new instance of the class. - /// - /// The underlying . - public AsyncDeterminationInterceptor(IAsyncInterceptor asyncInterceptor) - { - AsyncInterceptor = asyncInterceptor; - } - - private delegate void GenericAsyncHandler(IInvocation invocation, IAsyncInterceptor asyncInterceptor); - - private enum MethodType - { - Synchronous, - AsyncAction, - AsyncFunction, - } - - /// - /// Gets the underlying async interceptor. - /// - public IAsyncInterceptor AsyncInterceptor { get; } - - /// - /// Intercepts a method . - /// - /// The method invocation. - [DebuggerStepThrough] - public virtual void Intercept(IInvocation invocation) - { - MethodType methodType = GetMethodType(invocation.Method.ReturnType); - - switch (methodType) - { - case MethodType.AsyncAction: - AsyncInterceptor.InterceptAsynchronous(invocation); - return; - case MethodType.AsyncFunction: - GetHandler(invocation.Method.ReturnType).Invoke(invocation, AsyncInterceptor); - return; - default: - AsyncInterceptor.InterceptSynchronous(invocation); - return; - } - } - - /// - /// Gets the based upon the of the method invocation. - /// - private static MethodType GetMethodType(Type returnType) - { - // If there's no return type, or it's not a task, then assume it's a synchronous method. - if (returnType == typeof(void) || !typeof(Task).IsAssignableFrom(returnType)) - return MethodType.Synchronous; - - // The return type is a task of some sort, so assume it's asynchronous - return returnType.GetTypeInfo().IsGenericType ? MethodType.AsyncFunction : MethodType.AsyncAction; - } - - /// - /// Gets the for the method invocation . - /// - private static GenericAsyncHandler GetHandler(Type returnType) - { - GenericAsyncHandler handler = GenericAsyncHandlers.GetOrAdd(returnType, CreateHandler); - return handler; - } - - /// - /// Creates the generic delegate for the method invocation. - /// - private static GenericAsyncHandler CreateHandler(Type returnType) - { - Type taskReturnType = returnType.GetGenericArguments()[0]; - MethodInfo method = HandleAsyncMethodInfo.MakeGenericMethod(taskReturnType); - return (GenericAsyncHandler)method.CreateDelegate(typeof(GenericAsyncHandler)); - } - - /// - /// This method is created as a delegate and used to make the call to the generic - /// method. - /// - /// The type of the of the method - /// . - private static void HandleAsyncWithResult(IInvocation invocation, IAsyncInterceptor asyncInterceptor) - { - asyncInterceptor.InterceptAsynchronous(invocation); - } - } -} diff --git a/Castle.Core.AsyncInterceptor/AsyncInterceptorBase.cs b/Castle.Core.AsyncInterceptor/AsyncInterceptorBase.cs deleted file mode 100644 index 33c9735..0000000 --- a/Castle.Core.AsyncInterceptor/AsyncInterceptorBase.cs +++ /dev/null @@ -1,205 +0,0 @@ -// Copyright (c) 2016-2021 James Skimming. All rights reserved. -// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. - -namespace Castle.DynamicProxy -{ - using System; - using System.Collections.Concurrent; - using System.Diagnostics.CodeAnalysis; - using System.Reflection; - using System.Threading.Tasks; - using Castle.DynamicProxy.NoCoverage; - - /// - /// A base type for an to provided a simplified solution of method - /// by enforcing only two types of interception, both asynchronous. - /// - [SuppressMessage( - "Design", - "CA1031:Do not catch general exception types", - Justification = "Must propagate the same exceptions.")] - public abstract class AsyncInterceptorBase : IAsyncInterceptor - { -#if !NETSTANDARD2_0 && !NET5_0 - /// - /// A completed . - /// - private static readonly Task CompletedTask = Task.FromResult(0); -#endif - - private static readonly MethodInfo InterceptSynchronousMethodInfo = - typeof(AsyncInterceptorBase).GetMethod( - nameof(InterceptSynchronousResult), BindingFlags.Static | BindingFlags.NonPublic)!; - - private static readonly ConcurrentDictionary GenericSynchronousHandlers = - new ConcurrentDictionary - { - [typeof(void)] = InterceptSynchronousVoid, - }; - - private delegate void GenericSynchronousHandler(AsyncInterceptorBase me, IInvocation invocation); - - /// - /// Intercepts a synchronous method . - /// - /// The method invocation. - public void InterceptSynchronous(IInvocation invocation) - { - Type returnType = invocation.Method.ReturnType; - GenericSynchronousHandler handler = GenericSynchronousHandlers.GetOrAdd(returnType, CreateHandler); - handler(this, invocation); - } - - /// - /// Intercepts an asynchronous method with return type of . - /// - /// The method invocation. - public void InterceptAsynchronous(IInvocation invocation) - { - invocation.ReturnValue = InterceptAsync(invocation, invocation.CaptureProceedInfo(), ProceedAsynchronous); - } - - /// - /// Intercepts an asynchronous method with return type of . - /// - /// The type of the . - /// The method invocation. - public void InterceptAsynchronous(IInvocation invocation) - { - invocation.ReturnValue = - InterceptAsync(invocation, invocation.CaptureProceedInfo(), ProceedAsynchronous); - } - - /// - /// Override in derived classes to intercept method invocations. - /// - /// The method invocation. - /// The . - /// The function to proceed the . - /// A object that represents the asynchronous operation. - protected abstract Task InterceptAsync( - IInvocation invocation, - IInvocationProceedInfo proceedInfo, - Func proceed); - - /// - /// Override in derived classes to intercept method invocations. - /// - /// The type of the . - /// The method invocation. - /// The . - /// The function to proceed the . - /// A object that represents the asynchronous operation. - protected abstract Task InterceptAsync( - IInvocation invocation, - IInvocationProceedInfo proceedInfo, - Func> proceed); - - private static GenericSynchronousHandler CreateHandler(Type returnType) - { - MethodInfo method = InterceptSynchronousMethodInfo.MakeGenericMethod(returnType); - return (GenericSynchronousHandler)method.CreateDelegate(typeof(GenericSynchronousHandler)); - } - - private static void InterceptSynchronousVoid(AsyncInterceptorBase me, IInvocation invocation) - { - Task task = me.InterceptAsync(invocation, invocation.CaptureProceedInfo(), ProceedSynchronous); - - // If the intercept task has yet to complete, wait for it. - if (!task.IsCompleted) - { - // Need to use Task.Run() to prevent deadlock in .NET Framework ASP.NET requests. - // GetAwaiter().GetResult() prevents a thrown exception being wrapped in a AggregateException. - // See https://stackoverflow.com/a/17284612 - Task.Run(() => task).GetAwaiter().GetResult(); - } - - task.RethrowIfFaulted(); - } - - private static void InterceptSynchronousResult(AsyncInterceptorBase me, IInvocation invocation) - { - Task task = me.InterceptAsync(invocation, invocation.CaptureProceedInfo(), ProceedSynchronous); - - // If the intercept task has yet to complete, wait for it. - if (!task.IsCompleted) - { - // Need to use Task.Run() to prevent deadlock in .NET Framework ASP.NET requests. - // GetAwaiter().GetResult() prevents a thrown exception being wrapped in a AggregateException. - // See https://stackoverflow.com/a/17284612 - Task.Run(() => task).GetAwaiter().GetResult(); - } - - task.RethrowIfFaulted(); - } - - private static Task ProceedSynchronous(IInvocation invocation, IInvocationProceedInfo proceedInfo) - { - try - { - proceedInfo.Invoke(); -#if NETSTANDARD2_0 || NET5_0 - return Task.CompletedTask; -#else - return CompletedTask; -#endif - } - catch (Exception e) - { -#if NETSTANDARD2_0 || NET5_0 - return Task.FromException(e); -#else - var tcs = new TaskCompletionSource(); - tcs.SetException(e); - return tcs.Task; -#endif - } - } - - private static Task ProceedSynchronous( - IInvocation invocation, - IInvocationProceedInfo proceedInfo) - { - try - { - proceedInfo.Invoke(); - return Task.FromResult((TResult)invocation.ReturnValue); - } - catch (Exception e) - { -#if NETSTANDARD2_0 || NET5_0 - return Task.FromException(e); -#else - var tcs = new TaskCompletionSource(); - tcs.SetException(e); - return tcs.Task; -#endif - } - } - - [SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "The name explicitly says Asynchronous.")] - private static async Task ProceedAsynchronous(IInvocation invocation, IInvocationProceedInfo proceedInfo) - { - proceedInfo.Invoke(); - - // Get the task to await. - var originalReturnValue = (Task)invocation.ReturnValue; - - await originalReturnValue.ConfigureAwait(false); - } - - [SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "The name explicitly says Asynchronous.")] - private static async Task ProceedAsynchronous( - IInvocation invocation, - IInvocationProceedInfo proceedInfo) - { - proceedInfo.Invoke(); - - // Get the task to await. - var originalReturnValue = (Task)invocation.ReturnValue; - - TResult result = await originalReturnValue.ConfigureAwait(false); - return result; - } - } -} diff --git a/Castle.Core.AsyncInterceptor/AsyncTimingInterceptor.cs b/Castle.Core.AsyncInterceptor/AsyncTimingInterceptor.cs deleted file mode 100644 index 2087a2f..0000000 --- a/Castle.Core.AsyncInterceptor/AsyncTimingInterceptor.cs +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) 2016-2021 James Skimming. All rights reserved. -// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. - -namespace Castle.DynamicProxy -{ - using System.Diagnostics; - - /// - /// A base type for an which only wants timings for a method - /// . - /// - public abstract class AsyncTimingInterceptor : ProcessingAsyncInterceptor - { - /// - /// Signals before starting a to time the method - /// . - /// - /// The method invocation. - /// The to time the method . - protected sealed override Stopwatch StartingInvocation(IInvocation invocation) - { - StartingTiming(invocation); - var stopwatch = new Stopwatch(); - stopwatch.Start(); - return stopwatch; - } - - /// - /// Signals after stopping a to time the method - /// . - /// - /// The method invocation. - /// The returned by to time - /// the method . - protected sealed override void CompletedInvocation(IInvocation invocation, Stopwatch state) - { - state.Stop(); - CompletedTiming(invocation, state); - } - - /// - /// Override in derived classes to receive signals prior method timing. - /// - /// The method invocation. - protected abstract void StartingTiming(IInvocation invocation); - - /// - /// Override in derived classes to receive signals after method timing. - /// - /// The method invocation. - /// A used to time the method . - /// - protected abstract void CompletedTiming(IInvocation invocation, Stopwatch stopwatch); - } -} diff --git a/Castle.Core.AsyncInterceptor/Castle.Core.AsyncInterceptor.csproj b/Castle.Core.AsyncInterceptor/Castle.Core.AsyncInterceptor.csproj deleted file mode 100644 index f22605c..0000000 --- a/Castle.Core.AsyncInterceptor/Castle.Core.AsyncInterceptor.csproj +++ /dev/null @@ -1,56 +0,0 @@ - - - - netcoreapp3.1 - Castle.DynamicProxy - latest - true - false - enable - AllEnabledByDefault - false - James Skimming - AsyncInterceptor is an extension to Castle DynamicProxy to simplify the development of interceptors for asynchronous methods. - Copyright © 2016-2021 James Skimming - Apache-2.0 - https://github.com/JSkimming/Castle.Core.AsyncInterceptor - true - true - https://github.com/JSkimming/Castle.Core.AsyncInterceptor - git - true - snupkg - async asynchronous-methods castle castle-core dynamic dynamicproxy dynamic-proxy dynamicproxy2 intercept-methods proxy - true - 0.0.0.2 - 0.0.0.2 - 0.0.0.2 - - - - - false - $(MSBuildThisFileDirectory)SharedKey.snk - - true - false - Castle.Core.AsyncInterceptor_NL - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - - - - diff --git a/Castle.Core.AsyncInterceptor/IAsyncInterceptor.cs b/Castle.Core.AsyncInterceptor/IAsyncInterceptor.cs deleted file mode 100644 index 45c581a..0000000 --- a/Castle.Core.AsyncInterceptor/IAsyncInterceptor.cs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) 2016-2021 James Skimming. All rights reserved. -// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. - -namespace Castle.DynamicProxy -{ - using System.Threading.Tasks; - - /// - /// Implement this interface to intercept method invocations with DynamicProxy2. - /// - public interface IAsyncInterceptor - { - /// - /// Intercepts a synchronous method . - /// - /// The method invocation. - void InterceptSynchronous(IInvocation invocation); - - /// - /// Intercepts an asynchronous method with return type of . - /// - /// The method invocation. - void InterceptAsynchronous(IInvocation invocation); - - /// - /// Intercepts an asynchronous method with return type of . - /// - /// The type of the . - /// The method invocation. - void InterceptAsynchronous(IInvocation invocation); - } -} diff --git a/Castle.Core.AsyncInterceptor/NoCoverage/RethrowHelper.cs b/Castle.Core.AsyncInterceptor/NoCoverage/RethrowHelper.cs deleted file mode 100644 index 21bfbd5..0000000 --- a/Castle.Core.AsyncInterceptor/NoCoverage/RethrowHelper.cs +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) 2016-2021 James Skimming. All rights reserved. -// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. - -namespace Castle.DynamicProxy.NoCoverage -{ - using System; - using System.Collections.Generic; - using System.Linq; - using System.Runtime.ExceptionServices; - using System.Threading.Tasks; - - /// - /// A helper class to re-throw exceptions and retain the stack trace. - /// - internal static class RethrowHelper - { - /// - /// Re-throws the supplied exception without losing its stack trace. - /// Prefer throw; where possible, this method is useful for re-throwing - /// which cannot be done with the throw; semantics. - /// - /// The exception. - public static void Rethrow(this Exception? exception) - { - if (exception == null) - throw new ArgumentNullException(nameof(exception)); - - ExceptionDispatchInfo.Capture(exception).Throw(); - } - - /// - /// If the is an the - /// . is re-thrown; otherwise the - /// is re-thrown. - /// - /// The exception. - public static void RethrowInnerIfAggregate(this Exception? exception) - { - if (exception == null) - throw new ArgumentNullException(nameof(exception)); - - switch (exception) - { - case AggregateException aggregate: - Rethrow(aggregate.InnerException); - break; - default: - Rethrow(exception); - break; - } - } - - /// - /// If the the inner exception is re-thrown; otherwise the - /// method is a no-op. - /// - /// The task. - public static void RethrowIfFaulted(this Task task) - { - if (task == null) - throw new ArgumentNullException(nameof(task)); - - if (task.IsFaulted) - RethrowInnerIfAggregate(task.Exception); - } - } -} diff --git a/Castle.Core.AsyncInterceptor/ProcessingAsyncInterceptor.cs b/Castle.Core.AsyncInterceptor/ProcessingAsyncInterceptor.cs deleted file mode 100644 index eb3857c..0000000 --- a/Castle.Core.AsyncInterceptor/ProcessingAsyncInterceptor.cs +++ /dev/null @@ -1,147 +0,0 @@ -// Copyright (c) 2016-2021 James Skimming. All rights reserved. -// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. - -namespace Castle.DynamicProxy -{ - using System.Diagnostics.CodeAnalysis; - using System.Threading.Tasks; - - /// - /// A base type for an which executes only minimal processing when intercepting a - /// method . - /// - /// - /// The type of the custom object used to maintain state between and - /// . - /// - public abstract class ProcessingAsyncInterceptor : IAsyncInterceptor - where TState : class - { - /// - /// Intercepts a synchronous method . - /// - /// The method invocation. - public void InterceptSynchronous(IInvocation invocation) - { - TState state = Proceed(invocation); - - // Signal that the invocation has been completed. - CompletedInvocation(invocation, state, invocation.ReturnValue); - } - - /// - /// Intercepts an asynchronous method with return type of . - /// - /// The method invocation. - public void InterceptAsynchronous(IInvocation invocation) - { - TState state = Proceed(invocation); - invocation.ReturnValue = SignalWhenCompleteAsync(invocation, state); - } - - /// - /// Intercepts an asynchronous method with return type of . - /// - /// The type of the . - /// The method invocation. - public void InterceptAsynchronous(IInvocation invocation) - { - TState state = Proceed(invocation); - invocation.ReturnValue = SignalWhenCompleteAsync(invocation, state); - } - - /// - /// Override in derived classes to receive signals prior method . - /// - /// The method invocation. - /// The custom object used to maintain state between and - /// . - protected abstract TState StartingInvocation(IInvocation invocation); - - /// - /// Override in derived classes to receive signals after method . - /// - /// The method invocation. - /// The custom object used to maintain state between - /// and - /// . - protected virtual void CompletedInvocation(IInvocation invocation, TState state) - { - } - - /// - /// Override in derived classes to receive signals after method . - /// - /// The method invocation. - /// The custom object used to maintain state between - /// and - /// . - /// - /// The underlying return value of the ; or if the - /// invocation did not return a value. - /// - protected virtual void CompletedInvocation(IInvocation invocation, TState state, object? returnValue) - { - CompletedInvocation(invocation, state); - } - - /// - /// Signals the then on the - /// . - /// - /// The method invocation. - /// The returned by . - private TState Proceed(IInvocation invocation) - { - // Signal that the invocation is about to be started. - TState state = StartingInvocation(invocation); - - // Execute the invocation. - invocation.Proceed(); - - return state; - } - - /// - /// Returns a that replaces the - /// , that only completes after - /// has been signaled. - /// - /// The method invocation. - /// - /// The returned by . - /// - private async Task SignalWhenCompleteAsync(IInvocation invocation, TState state) - { - // Get the task to await. - var returnValue = (Task)invocation.ReturnValue; - - await returnValue.ConfigureAwait(false); - - // Signal that the invocation has been completed. - CompletedInvocation(invocation, state, null); - } - - /// - /// Returns a that replaces the - /// , that only completes after - /// has been signaled. - /// - /// The method invocation. - /// - /// The returned by . - /// - private async Task SignalWhenCompleteAsync(IInvocation invocation, TState state) - { - // Get the task to await. - var returnValue = (Task)invocation.ReturnValue; - - TResult result = await returnValue.ConfigureAwait(false); - - // Signal that the invocation has been completed. - CompletedInvocation(invocation, state, result); - - return result; - } - } -} diff --git a/Castle.Core.AsyncInterceptor/Properties/AssemblyInfo.cs b/Castle.Core.AsyncInterceptor/Properties/AssemblyInfo.cs deleted file mode 100644 index b7b2e8b..0000000 --- a/Castle.Core.AsyncInterceptor/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) 2016-2021 James Skimming. All rights reserved. -// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. - -using System; -using System.Reflection; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -#if NET45 -[assembly: AssemblyTitle("Castle.Core.AsyncInterceptor .NET Framework")] -#elif NET5_0 -[assembly: AssemblyTitle("Castle.Core.AsyncInterceptor .NET 5.0")] -#else -[assembly: AssemblyTitle("Castle.Core.AsyncInterceptor .NET Standard")] -#endif - -[assembly: AssemblyDescription("AsyncInterceptor is an extension to Castle DynamicProxy to simplify the development of interceptors for asynchronous methods.")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("Castle.Core.AsyncInterceptor")] -[assembly: AssemblyCopyright("Copyright (c) 2016-2021 James Skimming. All rights reserved.")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] -[assembly: CLSCompliant(true)] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -[assembly: AssemblyVersion("0.0.0.1")] -[assembly: AssemblyFileVersion("0.0.0.1")] -[assembly: AssemblyInformationalVersion("0.0.0.1")] diff --git a/Castle.Core.AsyncInterceptor/ProxyGeneratorExtensions.cs b/Castle.Core.AsyncInterceptor/ProxyGeneratorExtensions.cs deleted file mode 100644 index 655190e..0000000 --- a/Castle.Core.AsyncInterceptor/ProxyGeneratorExtensions.cs +++ /dev/null @@ -1,444 +0,0 @@ -// Copyright (c) 2016-2021 James Skimming. All rights reserved. -// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. - -namespace Castle.DynamicProxy -{ - using System; - using System.Collections.Generic; - using System.Diagnostics.CodeAnalysis; - using System.Linq; - - /// - /// Extension methods to . - /// - public static class ProxyGeneratorExtensions - { - /// - /// Creates an for the supplied . - /// - /// The interceptor for asynchronous operations. - /// The for the supplied . - public static IInterceptor ToInterceptor(this IAsyncInterceptor interceptor) - { - return new AsyncDeterminationInterceptor(interceptor); - } - - /// - /// Creates an array of objects for the supplied . - /// - /// The interceptors for asynchronous operations. - /// The array for the supplied . - public static IInterceptor[] ToInterceptors(this IEnumerable interceptors) - { - return interceptors.Select(ToInterceptor).ToArray(); - } - - /// - public static TInterface CreateInterfaceProxyWithTarget( - this IProxyGenerator proxyGenerator, - TInterface target, - params IAsyncInterceptor[] interceptors) - where TInterface : class - { - return proxyGenerator.CreateInterfaceProxyWithTarget(target, interceptors.ToInterceptors()); - } - - /// - public static TInterface CreateInterfaceProxyWithTarget( - this IProxyGenerator proxyGenerator, - TInterface target, - ProxyGenerationOptions options, - params IAsyncInterceptor[] interceptors) - where TInterface : class - { - return proxyGenerator.CreateInterfaceProxyWithTarget(target, options, interceptors.ToInterceptors()); - } - - /// - public static object CreateInterfaceProxyWithTarget( - this IProxyGenerator proxyGenerator, - Type interfaceToProxy, - object target, - params IAsyncInterceptor[] interceptors) - { - return proxyGenerator.CreateInterfaceProxyWithTarget( - interfaceToProxy, - target, - interceptors.ToInterceptors()); - } - - /// - public static object CreateInterfaceProxyWithTarget( - this IProxyGenerator proxyGenerator, - Type interfaceToProxy, - object target, - ProxyGenerationOptions options, - params IAsyncInterceptor[] interceptors) - { - return proxyGenerator.CreateInterfaceProxyWithTarget( - interfaceToProxy, - target, - options, - interceptors.ToInterceptors()); - } - - /// - public static object CreateInterfaceProxyWithTarget( - this IProxyGenerator proxyGenerator, - Type interfaceToProxy, - Type[] additionalInterfacesToProxy, - object target, - params IAsyncInterceptor[] interceptors) - { - return proxyGenerator.CreateInterfaceProxyWithTarget( - interfaceToProxy, - additionalInterfacesToProxy, - target, - interceptors.ToInterceptors()); - } - - /// - public static object CreateInterfaceProxyWithTarget( - this IProxyGenerator proxyGenerator, - Type interfaceToProxy, - Type[] additionalInterfacesToProxy, - object target, - ProxyGenerationOptions options, - params IAsyncInterceptor[] interceptors) - { - return proxyGenerator.CreateInterfaceProxyWithTarget( - interfaceToProxy, - additionalInterfacesToProxy, - target, - options, - interceptors.ToInterceptors()); - } - - /// - public static object CreateInterfaceProxyWithTargetInterface( - this IProxyGenerator proxyGenerator, - Type interfaceToProxy, - object target, - params IAsyncInterceptor[] interceptors) - { - return proxyGenerator.CreateInterfaceProxyWithTargetInterface( - interfaceToProxy, - target, - interceptors.ToInterceptors()); - } - - /// - public static TInterface CreateInterfaceProxyWithTargetInterface( - this IProxyGenerator proxyGenerator, - TInterface target, - params IAsyncInterceptor[] interceptors) - where TInterface : class - { - return proxyGenerator.CreateInterfaceProxyWithTargetInterface(target, interceptors.ToInterceptors()); - } - - /// - public static TInterface CreateInterfaceProxyWithTargetInterface( - this IProxyGenerator proxyGenerator, - TInterface target, - ProxyGenerationOptions options, - params IAsyncInterceptor[] interceptors) - where TInterface : class - { - return proxyGenerator.CreateInterfaceProxyWithTargetInterface( - target, - options, - interceptors.ToInterceptors()); - } - - /// - public static object CreateInterfaceProxyWithTargetInterface( - this IProxyGenerator proxyGenerator, - Type interfaceToProxy, - Type[] additionalInterfacesToProxy, - object target, - params IAsyncInterceptor[] interceptors) - { - return proxyGenerator.CreateInterfaceProxyWithTargetInterface( - interfaceToProxy, - additionalInterfacesToProxy, - target, - interceptors.ToInterceptors()); - } - - /// - public static object CreateInterfaceProxyWithTargetInterface( - this IProxyGenerator proxyGenerator, - Type interfaceToProxy, - object target, - ProxyGenerationOptions options, - params IAsyncInterceptor[] interceptors) - { - return proxyGenerator.CreateInterfaceProxyWithTargetInterface( - interfaceToProxy, - target, - options, - interceptors.ToInterceptors()); - } - - /// - public static object CreateInterfaceProxyWithTargetInterface( - this IProxyGenerator proxyGenerator, - Type interfaceToProxy, - Type[] additionalInterfacesToProxy, - object target, - ProxyGenerationOptions options, - params IAsyncInterceptor[] interceptors) - { - return proxyGenerator.CreateInterfaceProxyWithTargetInterface( - interfaceToProxy, - additionalInterfacesToProxy, - target, - options, - interceptors.ToInterceptors()); - } - - /// - public static TClass CreateClassProxyWithTarget( - this IProxyGenerator proxyGenerator, - TClass target, - params IAsyncInterceptor[] interceptors) - where TClass : class - { - return proxyGenerator.CreateClassProxyWithTarget(target, interceptors.ToInterceptors()); - } - - /// - public static TClass CreateClassProxyWithTarget( - this IProxyGenerator proxyGenerator, - TClass target, - ProxyGenerationOptions options, - params IAsyncInterceptor[] interceptors) - where TClass : class - { - return proxyGenerator.CreateClassProxyWithTarget(target, options, interceptors.ToInterceptors()); - } - - /// - public static object CreateClassProxyWithTarget( - this IProxyGenerator proxyGenerator, - Type classToProxy, - Type[] additionalInterfacesToProxy, - object target, - params IAsyncInterceptor[] interceptors) - { - return proxyGenerator.CreateClassProxyWithTarget( - classToProxy, - additionalInterfacesToProxy, - target, - interceptors.ToInterceptors()); - } - - /// - public static object CreateClassProxyWithTarget( - this IProxyGenerator proxyGenerator, - Type classToProxy, - object target, - ProxyGenerationOptions options, - object[] constructorArguments, - params IAsyncInterceptor[] interceptors) - { - return proxyGenerator.CreateClassProxyWithTarget( - classToProxy, - target, - options, - constructorArguments, - interceptors.ToInterceptors()); - } - - /// - public static object CreateClassProxyWithTarget( - this IProxyGenerator proxyGenerator, - Type classToProxy, - object target, - object[] constructorArguments, - params IAsyncInterceptor[] interceptors) - { - return proxyGenerator.CreateClassProxyWithTarget( - classToProxy, - target, - constructorArguments, - interceptors.ToInterceptors()); - } - - /// - public static object CreateClassProxyWithTarget( - this IProxyGenerator proxyGenerator, - Type classToProxy, - object target, - params IAsyncInterceptor[] interceptors) - { - return proxyGenerator.CreateClassProxyWithTarget(classToProxy, target, interceptors.ToInterceptors()); - } - - /// - public static object CreateClassProxyWithTarget( - this IProxyGenerator proxyGenerator, - Type classToProxy, - object target, - ProxyGenerationOptions options, - params IAsyncInterceptor[] interceptors) - { - return proxyGenerator.CreateClassProxyWithTarget( - classToProxy, - target, - options, - interceptors.ToInterceptors()); - } - - /// - public static object CreateClassProxyWithTarget( - this IProxyGenerator proxyGenerator, - Type classToProxy, - Type[] additionalInterfacesToProxy, - object target, - ProxyGenerationOptions options, - params IAsyncInterceptor[] interceptors) - { - return proxyGenerator.CreateClassProxyWithTarget( - classToProxy, - additionalInterfacesToProxy, - target, - options, - interceptors.ToInterceptors()); - } - - /// - public static object CreateClassProxyWithTarget( - this IProxyGenerator proxyGenerator, - Type classToProxy, - Type[] additionalInterfacesToProxy, - object target, - ProxyGenerationOptions options, - object[] constructorArguments, - params IAsyncInterceptor[] interceptors) - { - return proxyGenerator.CreateClassProxyWithTarget( - classToProxy, - additionalInterfacesToProxy, - target, - options, - constructorArguments, - interceptors.ToInterceptors()); - } - - /// - public static TClass CreateClassProxy( - this IProxyGenerator proxyGenerator, - params IAsyncInterceptor[] interceptors) - where TClass : class - { - return proxyGenerator.CreateClassProxy(interceptors.ToInterceptors()); - } - - /// - public static TClass CreateClassProxy( - this IProxyGenerator proxyGenerator, - ProxyGenerationOptions options, - params IAsyncInterceptor[] interceptors) - where TClass : class - { - return proxyGenerator.CreateClassProxy(options, interceptors.ToInterceptors()); - } - - /// - public static object CreateClassProxy( - this IProxyGenerator proxyGenerator, - Type classToProxy, - Type[] additionalInterfacesToProxy, - params IAsyncInterceptor[] interceptors) - { - return proxyGenerator.CreateClassProxy( - classToProxy, - additionalInterfacesToProxy, - interceptors.ToInterceptors()); - } - - /// - public static object CreateClassProxy( - this IProxyGenerator proxyGenerator, - Type classToProxy, - ProxyGenerationOptions options, - object[] constructorArguments, - params IAsyncInterceptor[] interceptors) - { - return proxyGenerator.CreateClassProxy( - classToProxy, - options, - constructorArguments, - interceptors.ToInterceptors()); - } - - /// - public static object CreateClassProxy( - this IProxyGenerator proxyGenerator, - Type classToProxy, - object[] constructorArguments, - params IAsyncInterceptor[] interceptors) - { - return proxyGenerator.CreateClassProxy( - classToProxy, - constructorArguments, - interceptors.ToInterceptors()); - } - - /// - public static object CreateClassProxy( - this IProxyGenerator proxyGenerator, - Type classToProxy, - params IAsyncInterceptor[] interceptors) - { - return proxyGenerator.CreateClassProxy(classToProxy, interceptors.ToInterceptors()); - } - - /// - public static object CreateClassProxy( - this IProxyGenerator proxyGenerator, - Type classToProxy, - ProxyGenerationOptions options, - params IAsyncInterceptor[] interceptors) - { - return proxyGenerator.CreateClassProxy( - classToProxy, - options, - interceptors.ToInterceptors()); - } - - /// - public static object CreateClassProxy( - this IProxyGenerator proxyGenerator, - Type classToProxy, - Type[] additionalInterfacesToProxy, - ProxyGenerationOptions options, - params IAsyncInterceptor[] interceptors) - { - return proxyGenerator.CreateClassProxy( - classToProxy, - additionalInterfacesToProxy, - options, - interceptors.ToInterceptors()); - } - - /// - public static object CreateClassProxy( - this IProxyGenerator proxyGenerator, - Type classToProxy, - Type[] additionalInterfacesToProxy, - ProxyGenerationOptions options, - object[] constructorArguments, - params IAsyncInterceptor[] interceptors) - { - return proxyGenerator.CreateClassProxy( - classToProxy, - additionalInterfacesToProxy, - options, - constructorArguments, - interceptors.ToInterceptors()); - } - } -} diff --git a/Castle.Core.AsyncInterceptor/SharedKey.snk b/Castle.Core.AsyncInterceptor/SharedKey.snk deleted file mode 100644 index 8ef35290f70882ffcdfe3e4db0cd425832e0fd2b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50098ezcQRec3tOl|7B?nY+t{O`?_AR?qfqz zTg`25$E5JsQB zJRp8`?TC}{t8$l5UG=>w1=I;@A^7D|SNYLgOB*is_*w*I{|iVO32xkP*UZl;`iOrL#GXD6sm~YB*tT}+b8gxL<;xWK(q}a2&&E5Va-_tNFM=eCDbYE}yv(ht?3{+Q`-mF&|KzP`)l0~vQ`T8QKP-u z6(r}`-?LrwOdpoDjOTE(<{wMp(IyPhw(g8AoZ`XkLDY4p#`BPDtE@t&0Xu_BHgDV@ z9hmU!d*9MKa>=pP#;VglXF!9LOz#}^UEU+w7&BL!u|$T|;v0j$e`BxP2AHoc1c`?P zh)elLmuS*)a+jqB%kUcHgpVa&k+t4RAYly6+*^q^p;EBd@>T5Ll1S=>dG9S+AO|4x i7ctP*Zg^_QO&p>l1Pr@n(i@(E`g;6SxCX@g>?axzl_&H7 diff --git a/Castle.Core/Castle.Core.csproj b/Castle.Core/Castle.Core.csproj deleted file mode 100644 index 86cbd14..0000000 --- a/Castle.Core/Castle.Core.csproj +++ /dev/null @@ -1,31 +0,0 @@ - - - - netcoreapp3.1 - - - - Castle.Core_NL - True - ../../build/ - Castle.Core - Castle - Castle Core - Castle Core, including DynamicProxy(with limited logging), Logging Abstractions and DictionaryAdapter - false - true - castle dynamicproxy dynamic proxy dynamicproxy2 dictionaryadapter emailsender - 4.4.1.1 - 4.4.1.1 - 4.4.1.1 - - - - - - - - - - - \ No newline at end of file diff --git a/Castle.Core/Components.DictionaryAdapter/AbstractDictionaryAdapter.cs b/Castle.Core/Components.DictionaryAdapter/AbstractDictionaryAdapter.cs deleted file mode 100644 index 3de0aad..0000000 --- a/Castle.Core/Components.DictionaryAdapter/AbstractDictionaryAdapter.cs +++ /dev/null @@ -1,170 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"; -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System; - using System.Collections; - - /// - /// Abstract adapter for the support - /// needed by the - /// - public abstract class AbstractDictionaryAdapter : IDictionary - { - /// - /// Adds an element with the provided key and value to the object. - /// - /// The to use as the key of the element to add. - /// The to use as the value of the element to add. - /// An element with the same key already exists in the object. - /// key is null. - /// The is read-only.-or- The has a fixed size. - public void Add(object key, object value) - { - throw new NotSupportedException(); - } - - /// - /// Removes all elements from the object. - /// - /// The object is read-only. - public void Clear() - { - throw new NotSupportedException(); - } - - /// - /// Determines whether the object contains an element with the specified key. - /// - /// The key to locate in the object. - /// - /// true if the contains an element with the key; otherwise, false. - /// - /// key is null. - public abstract bool Contains(object key); - - /// - /// Returns an object for the object. - /// - /// - /// An object for the object. - /// - public IDictionaryEnumerator GetEnumerator() - { - throw new NotSupportedException(); - } - - /// - /// Gets a value indicating whether the object has a fixed size. - /// - /// true if the object has a fixed size; otherwise, false. - public bool IsFixedSize - { - get { throw new NotSupportedException(); } - } - - /// - /// Gets a value indicating whether the object is read-only. - /// - /// true if the object is read-only; otherwise, false. - public abstract bool IsReadOnly { get; } - - /// - /// Gets an object containing the keys of the object. - /// - /// An object containing the keys of the object. - public ICollection Keys - { - get { throw new NotSupportedException(); } - } - - /// - /// Removes the element with the specified key from the object. - /// - /// The key of the element to remove. - /// The object is read-only.-or- The has a fixed size. - /// key is null. - public void Remove(object key) - { - throw new NotSupportedException(); - } - - /// - /// Gets an object containing the values in the object. - /// - /// An object containing the values in the object. - public ICollection Values - { - get { throw new NotSupportedException(); } - } - - /// - /// Gets or sets the with the specified key. - /// - public abstract object this[object key] { get; set; } - - /// - /// Copies the elements of the to an , starting at a particular index. - /// - /// The one-dimensional that is the destination of the elements copied from . The must have zero-based indexing. - /// The zero-based index in array at which copying begins. - /// array is null. - /// The type of the source cannot be cast automatically to the type of the destination array. - /// index is less than zero. - /// array is multidimensional.-or- index is equal to or greater than the length of array.-or- The number of elements in the source is greater than the available space from index to the end of the destination array. - public void CopyTo(Array array, int index) - { - throw new NotSupportedException(); - } - - /// - /// Gets the number of elements contained in the . - /// - /// The number of elements contained in the . - public int Count - { - get { throw new NotSupportedException(); } - } - - /// - /// Gets a value indicating whether access to the is synchronized (thread safe). - /// - /// true if access to the is synchronized (thread safe); otherwise, false. - public virtual bool IsSynchronized - { - get { return false; } - } - - /// - /// Gets an object that can be used to synchronize access to the . - /// - /// An object that can be used to synchronize access to the . - public virtual object SyncRoot - { - get { return this; } - } - - /// - /// Returns an enumerator that iterates through a collection. - /// - /// - /// An object that can be used to iterate through the collection. - /// - IEnumerator IEnumerable.GetEnumerator() - { - throw new NotSupportedException(); - } - } -} \ No newline at end of file diff --git a/Castle.Core/Components.DictionaryAdapter/AbstractDictionaryAdapterVisitor.cs b/Castle.Core/Components.DictionaryAdapter/AbstractDictionaryAdapterVisitor.cs deleted file mode 100644 index 4363e4d..0000000 --- a/Castle.Core/Components.DictionaryAdapter/AbstractDictionaryAdapterVisitor.cs +++ /dev/null @@ -1,159 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System; - using System.Linq; - using System.Collections; - using System.Collections.Generic; - using System.Reflection; - - using Castle.Core; - - /// - /// Abstract implementation of . - /// - public abstract class AbstractDictionaryAdapterVisitor : IDictionaryAdapterVisitor - { - private readonly Dictionary scopes; - - protected AbstractDictionaryAdapterVisitor() - { - scopes = new Dictionary(ReferenceEqualityComparer.Instance); - } - - protected AbstractDictionaryAdapterVisitor(AbstractDictionaryAdapterVisitor parent) - { - scopes = parent.scopes; - } - - protected bool Cancelled { get; set; } - - public virtual bool VisitDictionaryAdapter(IDictionaryAdapter dictionaryAdapter, object state) - { - return VisitDictionaryAdapter(dictionaryAdapter, null, null); - } - - public virtual bool VisitDictionaryAdapter(IDictionaryAdapter dictionaryAdapter, Func selector, object state) - { - if (PushScope(dictionaryAdapter) == false) - { - return false; - } - - try - { - foreach (var property in dictionaryAdapter.This.Properties.Values) - { - if (Cancelled) break; - - if (selector != null && selector(property) == false) - { - continue; - } - - Type collectionItemType; - if (IsCollection(property, out collectionItemType)) - { - VisitCollection(dictionaryAdapter, property, collectionItemType, state); - } - else if (property.PropertyType.IsInterface) - { - VisitInterface(dictionaryAdapter, property, state); - } - else - { - VisitProperty(dictionaryAdapter, property, state); - } - } - } - finally - { - PopScope(dictionaryAdapter); - } - - return true; - } - - void IDictionaryAdapterVisitor.VisitProperty(IDictionaryAdapter dictionaryAdapter, PropertyDescriptor property, object state) - { - VisitProperty(dictionaryAdapter, property, state); - } - - protected virtual void VisitProperty(IDictionaryAdapter dictionaryAdapter, PropertyDescriptor property, object state) - { - } - - void IDictionaryAdapterVisitor.VisitInterface(IDictionaryAdapter dictionaryAdapter, PropertyDescriptor property, object state) - { - - VisitInterface(dictionaryAdapter, property, state); - } - - protected virtual void VisitInterface(IDictionaryAdapter dictionaryAdapter, PropertyDescriptor property, object state) - { - VisitProperty(dictionaryAdapter, property, state); - } - - void IDictionaryAdapterVisitor.VisitCollection(IDictionaryAdapter dictionaryAdapter, PropertyDescriptor property, Type collectionItemType, object state) - { - VisitCollection(dictionaryAdapter, property, collectionItemType, state); - } - - protected virtual void VisitCollection(IDictionaryAdapter dictionaryAdapter, PropertyDescriptor property, Type collectionItemType, object state) - { - VisitProperty(dictionaryAdapter, property, state); - } - - private bool PushScope(IDictionaryAdapter dictionaryAdapter) - { - if (scopes.ContainsKey(dictionaryAdapter)) - { - return false; - } - scopes.Add(dictionaryAdapter, 0); - return true; - } - - private void PopScope(IDictionaryAdapter dictionaryAdapter) - { - scopes.Remove(dictionaryAdapter); - } - - private static bool IsCollection(PropertyDescriptor property, out Type collectionItemType) - { - collectionItemType = null; - var propertyType = property.PropertyType; - if (propertyType != typeof(string) && typeof(IEnumerable).IsAssignableFrom(propertyType)) - { - if (propertyType.IsArray) - { - collectionItemType = propertyType.GetElementType(); - } - else if (propertyType.IsGenericType) - { - var arguments = propertyType.GetGenericArguments(); - collectionItemType = arguments[0]; - } - else - { - collectionItemType = typeof(object); - } - return true; - } - return false; - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Attributes/ComponentAttribute.cs b/Castle.Core/Components.DictionaryAdapter/Attributes/ComponentAttribute.cs deleted file mode 100644 index b1e8220..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Attributes/ComponentAttribute.cs +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System; - - /// - /// Identifies a property should be represented as a nested component. - /// - [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)] - public class ComponentAttribute : DictionaryBehaviorAttribute, IDictionaryKeyBuilder, - IDictionaryPropertyGetter, IDictionaryPropertySetter - { - /// - /// Applies no prefix. - /// - public bool NoPrefix - { - get { return Prefix == ""; } - set - { - if (value) - { - Prefix = ""; - } - } - } - - /// - /// Gets or sets the prefix. - /// - /// The prefix. - public string Prefix { get; set; } - - #region IDictionaryKeyBuilder Members - - string IDictionaryKeyBuilder.GetKey(IDictionaryAdapter dictionaryAdapter, string key, - PropertyDescriptor property) - { - return Prefix ?? key + "_"; - } - - #endregion - - #region IDictionaryPropertyGetter - - object IDictionaryPropertyGetter.GetPropertyValue(IDictionaryAdapter dictionaryAdapter, - string key, object storedValue, PropertyDescriptor property, bool ifExists) - { - if (storedValue == null) - { - var component = dictionaryAdapter.This.ExtendedProperties[property.PropertyName]; - - if (component == null) - { - var descriptor = new PropertyDescriptor(property.Property, null); - descriptor.AddBehavior(new KeyPrefixAttribute(key)); - component = dictionaryAdapter.This.Factory.GetAdapter( - property.Property.PropertyType, dictionaryAdapter.This.Dictionary, descriptor); - dictionaryAdapter.This.ExtendedProperties[property.PropertyName] = component; - } - - return component; - } - - return storedValue; - } - - #endregion - - #region IDictionaryPropertySetter Members - - public bool SetPropertyValue(IDictionaryAdapter dictionaryAdapter, - string key, ref object value, PropertyDescriptor property) - { - dictionaryAdapter.This.ExtendedProperties.Remove(property.PropertyName); - return false; - } - - #endregion - } -} \ No newline at end of file diff --git a/Castle.Core/Components.DictionaryAdapter/Attributes/DictionaryAdapterAttribute.cs b/Castle.Core/Components.DictionaryAdapter/Attributes/DictionaryAdapterAttribute.cs deleted file mode 100644 index 5d62f08..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Attributes/DictionaryAdapterAttribute.cs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System; - - /// - /// Identifies the dictionary adapter types. - /// - [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] - public class DictionaryAdapterAttribute : Attribute - { - public DictionaryAdapterAttribute(Type interfaceType) - { - InterfaceType = interfaceType; - } - - public Type InterfaceType { get; private set; } - } -} \ No newline at end of file diff --git a/Castle.Core/Components.DictionaryAdapter/Attributes/DictionaryBehaviorAttribute.cs b/Castle.Core/Components.DictionaryAdapter/Attributes/DictionaryBehaviorAttribute.cs deleted file mode 100644 index 4d2d4e0..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Attributes/DictionaryBehaviorAttribute.cs +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System; - - /// - /// Assigns a specific dictionary key. - /// - public abstract class DictionaryBehaviorAttribute : Attribute, IDictionaryBehavior - { - public const int FirstExecutionOrder = 0; - public const int DefaultExecutionOrder = int.MaxValue / 2; - public const int LastExecutionOrder = int.MaxValue; - - public DictionaryBehaviorAttribute() - { - ExecutionOrder = DefaultExecutionOrder; - } - - public int ExecutionOrder { get; set; } - - public virtual IDictionaryBehavior Copy() - { - return this; - } - } -} \ No newline at end of file diff --git a/Castle.Core/Components.DictionaryAdapter/Attributes/FetchAttribute.cs b/Castle.Core/Components.DictionaryAdapter/Attributes/FetchAttribute.cs deleted file mode 100644 index 975773c..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Attributes/FetchAttribute.cs +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System; - - /// - /// Identifies an interface or property to be pre-fetched. - /// - [AttributeUsage(AttributeTargets.Interface | AttributeTargets.Property, AllowMultiple = false)] - public class FetchAttribute : Attribute - { - /// - /// Instructs fetching to occur. - /// - public FetchAttribute() : this(true) - { - } - - /// - /// Instructs fetching according to - /// - public FetchAttribute(bool fetch) - { - Fetch = fetch; - } - - /// - /// Gets whether or not fetching should occur. - /// - public bool Fetch { get; private set; } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Attributes/GroupAttribute.cs b/Castle.Core/Components.DictionaryAdapter/Attributes/GroupAttribute.cs deleted file mode 100644 index 7180a07..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Attributes/GroupAttribute.cs +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System; - - /// - /// Assigns a property to a group. - /// - [AttributeUsage(AttributeTargets.Property, AllowMultiple = true)] - public class GroupAttribute : Attribute - { - /// - /// Constructs a group assignment. - /// - /// The group name. - public GroupAttribute(object group) - { - Group = new [] { group }; - } - - /// - /// Constructs a group assignment. - /// - /// The group name. - public GroupAttribute(params object[] group) - { - Group = group; - } - - /// - /// Gets the group the property is assigned to. - /// - public object[] Group { get; private set; } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Attributes/IfExistsAttribute.cs b/Castle.Core/Components.DictionaryAdapter/Attributes/IfExistsAttribute.cs deleted file mode 100644 index 2e26950..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Attributes/IfExistsAttribute.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System; - - /// - /// Suppresses any on-demand behaviors. - /// - [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] - public class IfExistsAttribute : Attribute - { - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Attributes/KeyAttribute.cs b/Castle.Core/Components.DictionaryAdapter/Attributes/KeyAttribute.cs deleted file mode 100644 index 6fde21a..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Attributes/KeyAttribute.cs +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System; - - /// - /// Assigns a specific dictionary key. - /// - [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)] - public class KeyAttribute : DictionaryBehaviorAttribute, IDictionaryKeyBuilder - { - /// - /// Initializes a new instance of the class. - /// - /// The key. - public KeyAttribute(string key) - { - Key = key; - } - - /// - /// Initializes a new instance of the class. - /// - /// The compound key. - public KeyAttribute(string[] keys) - { - Key = string.Join(",", keys); - } - - public string Key { get; private set; } - - string IDictionaryKeyBuilder.GetKey(IDictionaryAdapter dictionaryAdapter, string key, PropertyDescriptor property) - { - return Key; - } - } -} \ No newline at end of file diff --git a/Castle.Core/Components.DictionaryAdapter/Attributes/KeyPrefixAttribute.cs b/Castle.Core/Components.DictionaryAdapter/Attributes/KeyPrefixAttribute.cs deleted file mode 100644 index 7f24cc0..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Attributes/KeyPrefixAttribute.cs +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System; - - /// - /// Assigns a prefix to the keyed properties of an interface. - /// - /// - /// Key prefixes are not inherited by sub-interfaces. - /// - [AttributeUsage(AttributeTargets.Interface, AllowMultiple = false, Inherited = false)] - public class KeyPrefixAttribute : DictionaryBehaviorAttribute, IDictionaryKeyBuilder - { - /// - /// Initializes a default instance of the class. - /// - public KeyPrefixAttribute() - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The prefix for the keyed properties of the interface. - public KeyPrefixAttribute(string keyPrefix) - { - this.KeyPrefix = keyPrefix; - } - - /// - /// Gets the prefix key added to the properties of the interface. - /// - public string KeyPrefix { get; set; } - - string IDictionaryKeyBuilder.GetKey(IDictionaryAdapter dictionaryAdapter, string key, PropertyDescriptor property) - { - return KeyPrefix + key; - } - } -} \ No newline at end of file diff --git a/Castle.Core/Components.DictionaryAdapter/Attributes/KeySubstitutionAttribute.cs b/Castle.Core/Components.DictionaryAdapter/Attributes/KeySubstitutionAttribute.cs deleted file mode 100644 index c13fa6e..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Attributes/KeySubstitutionAttribute.cs +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System; - - /// - /// Substitutes part of key with another string. - /// - [AttributeUsage(AttributeTargets.Interface | AttributeTargets.Property, AllowMultiple = true, Inherited = true)] - public class KeySubstitutionAttribute : DictionaryBehaviorAttribute, IDictionaryKeyBuilder - { - private readonly string oldValue; - private readonly string newValue; - - /// - /// Initializes a new instance of the class. - /// - /// The old value. - /// The new value. - public KeySubstitutionAttribute(string oldValue, string newValue) - { - this.oldValue = oldValue; - this.newValue = newValue; - } - - string IDictionaryKeyBuilder.GetKey(IDictionaryAdapter dictionaryAdapter, string key, PropertyDescriptor property) - { - return key.Replace(oldValue, newValue); - } - } -} \ No newline at end of file diff --git a/Castle.Core/Components.DictionaryAdapter/Attributes/MultiLevelEditAttribute.cs b/Castle.Core/Components.DictionaryAdapter/Attributes/MultiLevelEditAttribute.cs deleted file mode 100644 index 88520b6..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Attributes/MultiLevelEditAttribute.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System; - - /// - /// Requests support for multi-level editing. - /// - [AttributeUsage(AttributeTargets.Interface, AllowMultiple = false)] - public class MultiLevelEditAttribute : DictionaryBehaviorAttribute, IDictionaryInitializer - { - public void Initialize(IDictionaryAdapter dictionaryAdapter, object[] behaviors) - { - dictionaryAdapter.SupportsMultiLevelEdit = true; - } - } -} \ No newline at end of file diff --git a/Castle.Core/Components.DictionaryAdapter/Attributes/NewGuidAttribute.cs b/Castle.Core/Components.DictionaryAdapter/Attributes/NewGuidAttribute.cs deleted file mode 100644 index 25e3ad2..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Attributes/NewGuidAttribute.cs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System; - - /// - /// Generates a new GUID on demand. - /// - [AttributeUsage(AttributeTargets.Interface | AttributeTargets.Property, AllowMultiple = false)] - public class NewGuidAttribute : DictionaryBehaviorAttribute, IDictionaryPropertyGetter - { - private static readonly Guid UnassignedGuid = new Guid(); - - public object GetPropertyValue(IDictionaryAdapter dictionaryAdapter, - string key, object storedValue, PropertyDescriptor property, bool ifExists) - { - if (storedValue == null || storedValue.Equals(UnassignedGuid)) - { - storedValue = Guid.NewGuid(); - property.SetPropertyValue(dictionaryAdapter, key, ref storedValue, dictionaryAdapter.This.Descriptor); - } - - return storedValue; - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Attributes/OnDemandAttribute.cs b/Castle.Core/Components.DictionaryAdapter/Attributes/OnDemandAttribute.cs deleted file mode 100644 index acdad16..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Attributes/OnDemandAttribute.cs +++ /dev/null @@ -1,198 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System; - using System.Collections; - using System.Collections.Generic; - using System.ComponentModel; - using System.Linq; - using System.Reflection; - - /// - /// Support for on-demand value resolution. - /// - [AttributeUsage(AttributeTargets.Interface | AttributeTargets.Property, AllowMultiple = false)] - public class OnDemandAttribute : DictionaryBehaviorAttribute, IDictionaryPropertyGetter - { - public OnDemandAttribute() - { - } - - public OnDemandAttribute(Type type) - { - if (type.GetConstructor(Type.EmptyTypes) == null) - { - throw new ArgumentException("On-demand values must have a parameterless constructor"); - } - - Type = type; - } - - public OnDemandAttribute(object value) - { - Value = value; - } - - public Type Type { get; private set; } - - public object Value { get; private set; } - - public object GetPropertyValue(IDictionaryAdapter dictionaryAdapter, string key, - object storedValue, PropertyDescriptor property, bool ifExists) - { - if (storedValue == null && ifExists == false) - { - IValueInitializer initializer = null; - - if (Value != null) - { - storedValue = Value; - } - else - { - var type = Type ?? GetInferredType(dictionaryAdapter, property, out initializer); - - if (IsAcceptedType(type)) - { - if (type.IsInterface) - { - if (property.IsDynamicProperty == false) - { - if (storedValue == null) - { - storedValue = dictionaryAdapter.Create(property.PropertyType); - } - } - } - else if (type.IsArray) - { - storedValue = Array.CreateInstance(type.GetElementType(), 0); - } - else - { - if (storedValue == null) - { - object[] args = null; - ConstructorInfo constructor = null; - - if (property.IsDynamicProperty) - { - constructor = - (from ctor in type.GetConstructors() - let parms = ctor.GetParameters() - where parms.Length == 1 && - parms[0].ParameterType.IsAssignableFrom(dictionaryAdapter.Meta.Type) - select ctor).FirstOrDefault(); - - if (constructor != null) args = new[] { dictionaryAdapter }; - } - - if (constructor == null) - { - constructor = type.GetConstructor(Type.EmptyTypes); - } - - if (constructor != null) - { - storedValue = constructor.Invoke(args); - } - } - } - } - } - - if (storedValue != null) - { - using (dictionaryAdapter.SuppressNotificationsBlock()) - { - if (storedValue is ISupportInitialize) - { - ((ISupportInitialize)storedValue).BeginInit(); - ((ISupportInitialize)storedValue).EndInit(); - } - if (initializer != null) - { - initializer.Initialize(dictionaryAdapter, storedValue); - } - - property.SetPropertyValue(dictionaryAdapter, property.PropertyName, - ref storedValue, dictionaryAdapter.This.Descriptor); - } - } - } - - return storedValue; - } - - private static bool IsAcceptedType(Type type) - { - return type != null && type != typeof(string) && !type.IsPrimitive && !type.IsEnum; - } - - private static Type GetInferredType(IDictionaryAdapter dictionaryAdapter, PropertyDescriptor property, out IValueInitializer initializer) - { - Type type = null; - initializer = null; - - type = property.PropertyType; - if (typeof(IEnumerable).IsAssignableFrom(type) == false) - { - return type; - } - - Type collectionType = null; - - if (type.IsGenericType) - { - var genericDef = type.GetGenericTypeDefinition(); - var genericArg = type.GetGenericArguments()[0]; - bool isBindingList = - genericDef == typeof(System.ComponentModel.BindingList<>); - - if (isBindingList || genericDef == typeof(List<>)) - { - if (dictionaryAdapter.CanEdit) - { - collectionType = isBindingList ? typeof(EditableBindingList<>) : typeof(EditableList<>); - } - - if (isBindingList && genericArg.IsInterface) - { - Func addNew = () => dictionaryAdapter.Create(genericArg); - initializer = (IValueInitializer)Activator.CreateInstance( - typeof(BindingListInitializer<>).MakeGenericType(genericArg), - null, addNew, null, null, null); - } - } - else if (genericDef == typeof(IList<>) || genericDef == typeof(ICollection<>)) - { - collectionType = dictionaryAdapter.CanEdit ? typeof(EditableList<>) : typeof(List<>); - } - - if (collectionType != null) - { - return collectionType.MakeGenericType(genericArg); - } - } - else if (type == typeof(IList) || type == typeof(ICollection)) - { - return dictionaryAdapter.CanEdit ? typeof(EditableList) : typeof(List); - } - - return type; - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Attributes/ReferenceAttribute.cs b/Castle.Core/Components.DictionaryAdapter/Attributes/ReferenceAttribute.cs deleted file mode 100644 index 7aa0d54..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Attributes/ReferenceAttribute.cs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System; - - /// - /// Specifies assignment by reference rather than by copying. - /// - [AttributeUsage(AttributeTargets.Property | AttributeTargets.Interface)] - public class ReferenceAttribute : Attribute - { - // Marker attribute; no functionality - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Attributes/RemoveIfAttribute.cs b/Castle.Core/Components.DictionaryAdapter/Attributes/RemoveIfAttribute.cs deleted file mode 100644 index cf8da72..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Attributes/RemoveIfAttribute.cs +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System; - using System.Linq; - using System.Collections; - using System.Reflection; - - /// - /// Removes a property if matches value. - /// - [AttributeUsage(AttributeTargets.Interface | AttributeTargets.Property, AllowMultiple = true)] - public class RemoveIfAttribute : DictionaryBehaviorAttribute, IDictionaryPropertySetter - { - private ICondition condition; - - public RemoveIfAttribute() - { - ExecutionOrder += 10; - } - - public RemoveIfAttribute(params object[] values) : this() - { - values = values ?? new object[] { null }; - condition = new ValueCondition(values, null); - } - - public RemoveIfAttribute(object[] values, Type comparerType) : this() - { - var comparer = Construct(comparerType, nameof(comparerType)); - condition = new ValueCondition(values, comparer); - } - - protected RemoveIfAttribute(ICondition condition) : this() - { - this.condition = condition; - } - - public Type Condition - { - set { condition = Construct(value, nameof(value)); } - } - - bool IDictionaryPropertySetter.SetPropertyValue(IDictionaryAdapter dictionaryAdapter, - string key, ref object value, PropertyDescriptor property) - { - if (ShouldRemove(value)) - { - dictionaryAdapter.ClearProperty(property, key); - return false; - } - return true; - } - - internal bool ShouldRemove(object value) - { - return condition != null && condition.SatisfiedBy(value); - } - - private static TBase Construct(Type type, string paramName) - where TBase : class - { - if (type == null) - { - throw new ArgumentNullException(paramName); - } - - if (type.IsAbstract == false && typeof(TBase).IsAssignableFrom(type)) - { - var constructor = type.GetConstructor(Type.EmptyTypes); - if (constructor != null) - { - return (TBase)constructor.Invoke(new object[0]); - } - } - - throw new ArgumentException(string.Format( - "{0} is not a concrete type implementing {1} with a default constructor", - type.FullName, typeof(TBase).FullName)); - } - - #region Nested Class: ValueCondition - - class ValueCondition : ICondition - { - private readonly object[] values; - private readonly IEqualityComparer comparer; - - public ValueCondition(object[] values, IEqualityComparer comparer) - { - this.values = values; - this.comparer = comparer; - } - - public bool SatisfiedBy(object value) - { - return values.Any(valueToMatch => - { - if (comparer == null) - { - return Equals(value, valueToMatch); - } - return comparer.Equals(value, valueToMatch); - }); - } - } - - #endregion - } -} \ No newline at end of file diff --git a/Castle.Core/Components.DictionaryAdapter/Attributes/RemoveIfEmptyAttribute.cs b/Castle.Core/Components.DictionaryAdapter/Attributes/RemoveIfEmptyAttribute.cs deleted file mode 100644 index a1343ae..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Attributes/RemoveIfEmptyAttribute.cs +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System; - using System.Collections; - - /// - /// Removes a property if null or empty string, guid or collection. - /// - public class RemoveIfEmptyAttribute : RemoveIfAttribute - { - public RemoveIfEmptyAttribute() - : base(RemoveIfEmptyCondition.Instance) - { - } - - private new Type Condition { get; set; } - - class RemoveIfEmptyCondition : ICondition - { - public static readonly RemoveIfEmptyCondition Instance = new RemoveIfEmptyCondition(); - - public bool SatisfiedBy(object value) - { - return value == null || - IsEmptyString(value) || - IsEmptyGuid(value) || - IsEmptyCollection(value); - } - - private static bool IsEmptyString(object value) - { - return (value is string && ((string)value).Length == 0); - } - - private static bool IsEmptyGuid(object value) - { - return (value is Guid && ((Guid)value) == Guid.Empty); - } - - private static bool IsEmptyCollection(object value) - { - return (value is IEnumerable && ((IEnumerable)value).GetEnumerator().MoveNext() == false); - } - } - } -} \ No newline at end of file diff --git a/Castle.Core/Components.DictionaryAdapter/Attributes/StringFormatAttribute.cs b/Castle.Core/Components.DictionaryAdapter/Attributes/StringFormatAttribute.cs deleted file mode 100644 index 309e7cd..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Attributes/StringFormatAttribute.cs +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System; - - /// - /// Provides simple string formatting from existing properties. - /// - [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)] - public class StringFormatAttribute : DictionaryBehaviorAttribute, IDictionaryPropertyGetter - { - private static readonly char[] PropertyDelimeters = new[] { ',', ' ' }; - - public StringFormatAttribute(string format, string properties) - { - if (format == null) - { - throw new ArgumentNullException(nameof(format)); - } - - Format = format; - Properties = properties; - } - - /// - /// Gets the string format. - /// - public string Format { get; private set; } - - /// - /// Gets the format properties. - /// - public string Properties { get; private set; } - - #region IDictionaryPropertyGetter - - object IDictionaryPropertyGetter.GetPropertyValue(IDictionaryAdapter dictionaryAdapter, - string key, object storedValue, PropertyDescriptor property, bool ifExists) - { - return string.Format(Format, GetFormatArguments(dictionaryAdapter, property.Property.Name)).Trim(); - } - - #endregion - - private object[] GetFormatArguments(IDictionaryAdapter dictionaryAdapter, string formattedPropertyName) - { - var properties = Properties.Split(PropertyDelimeters, StringSplitOptions.RemoveEmptyEntries); - var arguments = new object[properties.Length]; - for (int i = 0; i < properties.Length; ++i) - { - var propertyName = properties[i]; - if (propertyName != formattedPropertyName) - { - arguments[i] = dictionaryAdapter.GetProperty(propertyName, false); - } - else - { - arguments[i] = "(recursive)"; - } - } - return arguments; - } - } -} \ No newline at end of file diff --git a/Castle.Core/Components.DictionaryAdapter/Attributes/StringListAttribute.cs b/Castle.Core/Components.DictionaryAdapter/Attributes/StringListAttribute.cs deleted file mode 100644 index bd8e99b..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Attributes/StringListAttribute.cs +++ /dev/null @@ -1,245 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System; - using System.Collections; - using System.Collections.Generic; - using System.ComponentModel; - using System.Reflection; - using System.Text; - - /// - /// Identifies a property should be represented as a delimited string value. - /// - [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)] - public class StringListAttribute : DictionaryBehaviorAttribute, IDictionaryPropertyGetter, IDictionaryPropertySetter - { - public StringListAttribute() - { - Separator = ','; - } - - /// - /// Gets the separator. - /// - public char Separator { get; set; } - - #region IDictionaryPropertyGetter - - object IDictionaryPropertyGetter.GetPropertyValue(IDictionaryAdapter dictionaryAdapter, - string key, object storedValue, PropertyDescriptor property, bool ifExists) - { - var propertyType = property.PropertyType; - - if (storedValue == null || !storedValue.GetType().IsInstanceOfType(propertyType)) - { - if (propertyType.IsGenericType) - { - var genericDef = propertyType.GetGenericTypeDefinition(); - - if (genericDef == typeof(IList<>) || genericDef == typeof(ICollection<>) || - genericDef == typeof(List<>) || genericDef == typeof(IEnumerable<>)) - { - var paramType = propertyType.GetGenericArguments()[0]; - var converter = TypeDescriptor.GetConverter(paramType); - - if (converter != null && converter.CanConvertFrom(typeof(string))) - { - var genericList = typeof(StringListWrapper<>).MakeGenericType(new[] { paramType }); - return Activator.CreateInstance(genericList, key, storedValue, Separator, dictionaryAdapter.This.Dictionary); - } - } - } - } - - return storedValue; - } - - #endregion - - #region IDictionaryPropertySetter Members - - bool IDictionaryPropertySetter.SetPropertyValue(IDictionaryAdapter dictionaryAdapter, - string key, ref object value, PropertyDescriptor property) - { - var enumerable = value as IEnumerable; - if (enumerable != null) - { - value = BuildString(enumerable, Separator); - } - return true; - } - - #endregion - - internal static string BuildString(IEnumerable enumerable, char separator) - { - bool first = true; - var builder = new StringBuilder(); - - foreach (object item in enumerable) - { - if (first) - { - first = false; - } - else - { - builder.Append(separator); - } - - builder.Append(item.ToString()); - } - - return builder.ToString(); - } - - #region Nested Class: StringList - - class StringListWrapper : IList - { - private readonly string key; - private readonly char separator; - private readonly IDictionary dictionary; - private readonly List inner; - - public StringListWrapper(string key, string list, char separator, IDictionary dictionary) - { - this.key = key; - this.separator = separator; - this.dictionary = dictionary; - inner = new List(); - - ParseList(list); - } - - #region IList Members - - public int IndexOf(T item) - { - return inner.IndexOf(item); - } - - public void Insert(int index, T item) - { - inner.Insert(index, item); - SynchronizeDictionary(); - } - - public void RemoveAt(int index) - { - inner.RemoveAt(index); - SynchronizeDictionary(); - } - - public T this[int index] - { - get { return inner[index]; } - set - { - inner[index] = value; - SynchronizeDictionary(); - } - } - - #endregion - - #region ICollection Members - - public void Add(T item) - { - inner.Add(item); - SynchronizeDictionary(); - } - - public void Clear() - { - inner.Clear(); - SynchronizeDictionary(); - } - - public bool Contains(T item) - { - return inner.Contains(item); - } - - public void CopyTo(T[] array, int arrayIndex) - { - inner.CopyTo(array, arrayIndex); - } - - public int Count - { - get { return inner.Count; } - } - - public bool IsReadOnly - { - get { return false; } - } - - public bool Remove(T item) - { - if (inner.Remove(item)) - { - SynchronizeDictionary(); - return true; - } - return false; - } - - #endregion - - #region IEnumerable Members - - public IEnumerator GetEnumerator() - { - return inner.GetEnumerator(); - } - - #endregion - - #region IEnumerable Members - - IEnumerator IEnumerable.GetEnumerator() - { - return inner.GetEnumerator(); - } - - #endregion - - private void ParseList(string list) - { - if (list != null) - { - var converter = TypeDescriptor.GetConverter(typeof(T)); - - foreach (var item in list.Split(separator)) - { - inner.Add((T)converter.ConvertFrom(item)); - } - } - } - - private void SynchronizeDictionary() - { - dictionary[key] = StringListAttribute.BuildString(inner, separator); - } - } - } - - #endregion -} \ No newline at end of file diff --git a/Castle.Core/Components.DictionaryAdapter/Attributes/StringStorageAttribute.cs b/Castle.Core/Components.DictionaryAdapter/Attributes/StringStorageAttribute.cs deleted file mode 100644 index 32b77c6..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Attributes/StringStorageAttribute.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"; -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System; - - [AttributeUsage(AttributeTargets.Interface | AttributeTargets.Property, AllowMultiple = false)] - public class StringStorageAttribute : DictionaryBehaviorAttribute, IDictionaryPropertySetter - { - public bool SetPropertyValue(IDictionaryAdapter dictionaryAdapter, string key, ref object value, PropertyDescriptor property) - { - value = (value != null) ? value.ToString() : null; - return true; - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Attributes/StringValuesAttribute.cs b/Castle.Core/Components.DictionaryAdapter/Attributes/StringValuesAttribute.cs deleted file mode 100644 index 84bb3d6..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Attributes/StringValuesAttribute.cs +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System; - - /// - /// Converts all properties to strings. - /// - [AttributeUsage(AttributeTargets.Interface | AttributeTargets.Property, AllowMultiple = false, Inherited = true)] - public class StringValuesAttribute : DictionaryBehaviorAttribute, IDictionaryPropertySetter - { - /// - /// Gets or sets the format. - /// - /// The format. - public string Format { get; set; } - - bool IDictionaryPropertySetter.SetPropertyValue(IDictionaryAdapter dictionaryAdapter, - string key, ref object value, PropertyDescriptor property) - { - if (value != null) - { - value = GetPropertyAsString(property, value); - } - return true; - } - - private string GetPropertyAsString(PropertyDescriptor property, object value) - { - if (string.IsNullOrEmpty(Format) == false) - { - return string.Format(Format, value); - } - - var converter = property.TypeConverter; - - if (converter != null && converter.CanConvertTo(typeof(string))) - { - return (string) converter.ConvertTo(value, typeof(string)); - } - - return value.ToString(); - } - } -} \ No newline at end of file diff --git a/Castle.Core/Components.DictionaryAdapter/Attributes/SuppressNotificationsAttribute.cs b/Castle.Core/Components.DictionaryAdapter/Attributes/SuppressNotificationsAttribute.cs deleted file mode 100644 index 3b9d78f..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Attributes/SuppressNotificationsAttribute.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System; - - /// - /// Suppress property change notifications. - /// - [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] - public class SuppressNotificationsAttribute : DictionaryBehaviorAttribute, IPropertyDescriptorInitializer - { - public void Initialize(PropertyDescriptor propertyDescriptor, object[] behaviors) - { - propertyDescriptor.SuppressNotifications = true; - } - } -} \ No newline at end of file diff --git a/Castle.Core/Components.DictionaryAdapter/Attributes/TypeKeyPrefixAttribute.cs b/Castle.Core/Components.DictionaryAdapter/Attributes/TypeKeyPrefixAttribute.cs deleted file mode 100644 index a0452a2..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Attributes/TypeKeyPrefixAttribute.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System; - - /// - /// Assigns a prefix to the keyed properties using the interface name. - /// - [AttributeUsage(AttributeTargets.Interface, AllowMultiple = false, Inherited = true)] - public class TypeKeyPrefixAttribute : DictionaryBehaviorAttribute, IDictionaryKeyBuilder - { - string IDictionaryKeyBuilder.GetKey(IDictionaryAdapter dictionaryAdapter, string key, PropertyDescriptor property) - { - return string.Format("{0}#{1}", property.Property.DeclaringType.FullName, key); - } - } -} \ No newline at end of file diff --git a/Castle.Core/Components.DictionaryAdapter/Attributes/VolatileAttribute.cs b/Castle.Core/Components.DictionaryAdapter/Attributes/VolatileAttribute.cs deleted file mode 100644 index a7e96ff..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Attributes/VolatileAttribute.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System; - - /// - /// Indicates that underlying values are changeable and should not be cached. - /// - [AttributeUsage(AttributeTargets.Interface | AttributeTargets.Property, AllowMultiple = false)] - public class VolatileAttribute : Attribute - { - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Attributes/XPathAttribute.cs b/Castle.Core/Components.DictionaryAdapter/Attributes/XPathAttribute.cs deleted file mode 100644 index c85ce5c..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Attributes/XPathAttribute.cs +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - - [AttributeUsage(AttributeTargets.Interface | AttributeTargets.Property, AllowMultiple = true)] - public class XPathAttribute : Attribute - { - private readonly CompiledXPath getPath; - private readonly CompiledXPath setPath; - - public XPathAttribute(string path) - { - if (path == null) - throw Error.ArgumentNull(nameof(path)); - - this.getPath = XPathCompiler.Compile(path); - this.setPath = this.getPath; - } - - public XPathAttribute(string get, string set) - { - if (get == null) - throw Error.ArgumentNull(nameof(get)); - if (set == null) - throw Error.ArgumentNull(nameof(set)); - - this.getPath = XPathCompiler.Compile(get); - this.setPath = XPathCompiler.Compile(set); - } - - public CompiledXPath GetPath - { - get { return getPath; } - } - - public CompiledXPath SetPath - { - get { return setPath; } - } - - public bool Nullable { get; set; } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Attributes/XPathFunctionAttribute.cs b/Castle.Core/Components.DictionaryAdapter/Attributes/XPathFunctionAttribute.cs deleted file mode 100644 index 19bf1a4..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Attributes/XPathFunctionAttribute.cs +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - using System.Xml.XPath; - using System.Xml.Xsl; - - [AttributeUsage(AttributeTargets.Interface | AttributeTargets.Property, AllowMultiple = true)] - public abstract class XPathFunctionAttribute : Attribute, IXsltContextFunction - { - protected XPathFunctionAttribute() { } - - public abstract XmlName Name { get; } - public abstract XPathResultType ReturnType { get; } - - public virtual XPathResultType[] ArgTypes { get { return NoArgs; } } - public virtual int Maxargs { get { return ArgTypes.Length; } } - public virtual int Minargs { get { return ArgTypes.Length; } } - - public static readonly XPathResultType[] - NoArgs = new XPathResultType[0]; - - public abstract object Invoke(XsltContext context, object[] args, XPathNavigator node); - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Attributes/XPathVariableAttribute.cs b/Castle.Core/Components.DictionaryAdapter/Attributes/XPathVariableAttribute.cs deleted file mode 100644 index b64a53e..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Attributes/XPathVariableAttribute.cs +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - using System.Xml.XPath; - using System.Xml.Xsl; - - [AttributeUsage(AttributeTargets.Interface | AttributeTargets.Property, AllowMultiple = true)] - public abstract class XPathVariableAttribute : Attribute, IXsltContextVariable - { - protected XPathVariableAttribute() { } - - public abstract XmlName Name { get; } - public abstract XPathResultType VariableType { get; } - - bool IXsltContextVariable.IsLocal { get { return false; } } - bool IXsltContextVariable.IsParam { get { return false; } } - - public abstract object Evaluate(XsltContext context); - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Attributes/XmlDefaultsAttribute.cs b/Castle.Core/Components.DictionaryAdapter/Attributes/XmlDefaultsAttribute.cs deleted file mode 100644 index ce5f74f..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Attributes/XmlDefaultsAttribute.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System; - - [AttributeUsage(AttributeTargets.Interface)] - public class XmlDefaultsAttribute : Attribute - { - public bool Qualified { get; set; } - - public bool IsNullable { get; set; } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Attributes/XmlNamespaceAttribute.cs b/Castle.Core/Components.DictionaryAdapter/Attributes/XmlNamespaceAttribute.cs deleted file mode 100644 index 5e70e63..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Attributes/XmlNamespaceAttribute.cs +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System; - - [AttributeUsage(AttributeTargets.Interface | AttributeTargets.Property, AllowMultiple = true)] - public class XmlNamespaceAttribute : Attribute - { - public XmlNamespaceAttribute(string namespaceUri, string prefix) - { - NamespaceUri = namespaceUri; - Prefix = prefix; - } - - public bool Root { get; set; } - - public bool Default { get; set; } - - public string NamespaceUri { get; private set; } - - public string Prefix { get; private set; } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/CascadingDictionaryAdapter.cs b/Castle.Core/Components.DictionaryAdapter/CascadingDictionaryAdapter.cs deleted file mode 100644 index d077ca2..0000000 --- a/Castle.Core/Components.DictionaryAdapter/CascadingDictionaryAdapter.cs +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System.Collections; - - public class CascadingDictionaryAdapter : AbstractDictionaryAdapter - { - private readonly IDictionary primary; - private readonly IDictionary secondary; - - public CascadingDictionaryAdapter(IDictionary primary, IDictionary secondary) - { - this.primary = primary; - this.secondary = secondary; - } - - public IDictionary Primary - { - get { return primary; } - } - - public IDictionary Secondary - { - get { return secondary; } - } - - public override bool IsReadOnly - { - get { return primary.IsReadOnly; } - } - - public override bool Contains(object key) - { - return primary.Contains(key) || secondary.Contains(key); - } - - public override object this[object key] - { - get { return primary[key] ?? secondary[key]; } - set { primary[key] = value; } - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/DefaultPropertyGetter.cs b/Castle.Core/Components.DictionaryAdapter/DefaultPropertyGetter.cs deleted file mode 100644 index 9153123..0000000 --- a/Castle.Core/Components.DictionaryAdapter/DefaultPropertyGetter.cs +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System.ComponentModel; - using System.Reflection; - - /// - /// Manages conversion between property values. - /// - public class DefaultPropertyGetter : IDictionaryPropertyGetter - { - private readonly TypeConverter converter; - - /// - /// Initializes a new instance of the class. - /// - /// The converter. - public DefaultPropertyGetter(TypeConverter converter) - { - this.converter = converter; - } - - /// - /// - /// - public int ExecutionOrder - { - get { return DictionaryBehaviorAttribute.LastExecutionOrder; } - } - - /// - /// Gets the effective dictionary value. - /// - /// The dictionary adapter. - /// The key. - /// The stored value. - /// The property. - /// true if return only existing. - /// The effective property value. - public object GetPropertyValue(IDictionaryAdapter dictionaryAdapter, - string key, object storedValue, PropertyDescriptor property, bool ifExists) - { - var propertyType = property.PropertyType; - - if (storedValue != null && propertyType.IsInstanceOfType(storedValue) == false) - { - if (converter != null && converter.CanConvertFrom(storedValue.GetType())) - { - return converter.ConvertFrom(storedValue); - } - } - - return storedValue; - } - - public IDictionaryBehavior Copy() - { - return this; - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterBase.Coerce.cs b/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterBase.Coerce.cs deleted file mode 100644 index 3dc6c92..0000000 --- a/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterBase.Coerce.cs +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System; - using System.Reflection; - - public abstract partial class DictionaryAdapterBase - { - public T Coerce() where T : class - { - return (T)Coerce(typeof(T)); - } - - public object Coerce(Type type) - { - if (type.IsAssignableFrom(Meta.Type)) - return this; - - if (This.CoerceStrategy != null) - { - var coerced = This.CoerceStrategy.Coerce(this, type); - if (coerced != null) return coerced; - } - return This.Factory.GetAdapter(type, This.Dictionary, This.Descriptor); - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterBase.Copy.cs b/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterBase.Copy.cs deleted file mode 100644 index 9ce75f8..0000000 --- a/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterBase.Copy.cs +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System; - using System.Linq; - using System.Reflection; - - public abstract partial class DictionaryAdapterBase - { - public void CopyTo(IDictionaryAdapter other) - { - CopyTo(other, null); - } - - public void CopyTo(IDictionaryAdapter other, Func selector) - { - if (ReferenceEquals(this, other)) - { - return; - } - - if (other.Meta.Type.IsAssignableFrom(Meta.Type) == false) - { - throw new ArgumentException(string.Format( - "Unable to copy to {0}. The type must be assignable from {1}.", - other.Meta.Type.FullName, Meta.Type.FullName)); - } - - if (This.CopyStrategies.Aggregate(false, (copied, s) => copied | s.Copy(this, other, ref selector))) - { - return; - } - - selector = selector ?? (property => true); - - foreach (var property in This.Properties.Values.Where(property => selector(property))) - { - var propertyValue = GetProperty(property.PropertyName, true); - other.SetProperty(property.PropertyName, ref propertyValue); - } - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterBase.Create.cs b/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterBase.Create.cs deleted file mode 100644 index 026689a..0000000 --- a/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterBase.Create.cs +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System; - using System.Collections; - using System.Collections.Specialized; - - public abstract partial class DictionaryAdapterBase : IDictionaryCreate - { - public T Create() - { - return Create(new HybridDictionary()); - } - - public object Create(Type type) - { - return Create(type, new HybridDictionary()); - } - - public T Create(IDictionary dictionary) - { - return (T)Create(typeof(T), dictionary ?? new HybridDictionary()); - } - - public object Create(Type type, IDictionary dictionary) - { - if (This.CreateStrategy != null) - { - var created = This.CreateStrategy.Create(this, type, dictionary); - if (created != null) return created; - } - dictionary = dictionary ?? new HybridDictionary(); - return This.Factory.GetAdapter(type, dictionary, This.Descriptor); - } - - public T Create(Action init) - { - return Create(new HybridDictionary(), init); - } - - public T Create(IDictionary dictionary, Action init) - { - var adapter = Create(dictionary ?? new HybridDictionary()); - if (init != null) init(adapter); - return adapter; - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterBase.Edit.cs b/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterBase.Edit.cs deleted file mode 100644 index 7286aa1..0000000 --- a/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterBase.Edit.cs +++ /dev/null @@ -1,244 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System; - using System.Collections.Generic; - using System.ComponentModel; - using System.Linq; - using System.Reflection; - - public abstract partial class DictionaryAdapterBase - { - private int suppressEditingCount = 0; - private Stack> updates; - private HashSet editDependencies; - - struct Edit - { - public Edit(PropertyDescriptor property, object propertyValue) - { - Property = property; - PropertyValue = propertyValue; - } - public readonly PropertyDescriptor Property; - public object PropertyValue; - } - - public bool CanEdit - { - get { return suppressEditingCount == 0 && updates != null; } - set { updates = value ? new Stack>() : null; } - } - - public bool IsEditing - { - get { return CanEdit && updates != null && updates.Count > 0; } - } - - public bool SupportsMultiLevelEdit { get; set; } - - public bool IsChanged - { - get - { - if (IsEditing && updates.Any(level => level.Count > 0)) - return true; - - return This.Properties.Values - .Where(prop => typeof(IChangeTracking).IsAssignableFrom(prop.PropertyType)) - .Select(prop => GetProperty(prop.PropertyName, true)) - .Cast().Any(track => track != null && track.IsChanged); - } - } - - public void BeginEdit() - { - if (CanEdit && (IsEditing == false || SupportsMultiLevelEdit)) - { - updates.Push(new Dictionary()); - } - } - - public void CancelEdit() - { - if (IsEditing) - { - if (editDependencies != null) - { - foreach (var editDependency in editDependencies.ToArray()) - { - editDependency.CancelEdit(); - } - editDependencies.Clear(); - } - - using (SuppressEditingBlock()) - { - using (TrackReadonlyPropertyChanges()) - { - var top = updates.Peek(); - - if (top.Count > 0) - { - foreach (var update in top.Values) - { - var existing = update; - existing.PropertyValue = GetProperty(existing.Property.PropertyName, true); - } - - updates.Pop(); - - foreach (var update in top.Values.ToArray()) - { - var oldValue = update.PropertyValue; - var newValue = GetProperty(update.Property.PropertyName, true); - - if (!object.Equals(oldValue, newValue)) - { - - NotifyPropertyChanging(update.Property, oldValue, newValue); - NotifyPropertyChanged(update.Property, oldValue, newValue); - - } - } - } - } - } - } - } - - public void EndEdit() - { - if (IsEditing) - { - using (SuppressEditingBlock()) - { - var top = updates.Pop(); - - if (top.Count > 0) foreach (var update in top.ToArray()) - { - StoreProperty(null, update.Key, update.Value.PropertyValue); - } - } - - if (editDependencies != null) - { - foreach (var editDependency in editDependencies.ToArray()) - { - editDependency.EndEdit(); - } - editDependencies.Clear(); - } - } - } - - public void RejectChanges() - { - CancelEdit(); - } - - public void AcceptChanges() - { - EndEdit(); - } - - public IDisposable SuppressEditingBlock() - { - return new SuppressEditingScope(this); - } - - public void SuppressEditing() - { - ++suppressEditingCount; - } - - public void ResumeEditing() - { - --suppressEditingCount; - } - - protected bool GetEditedProperty(string propertyName, out object propertyValue) - { - if (updates != null) foreach (var level in updates.ToArray()) - { - Edit edit; - if (level.TryGetValue(propertyName, out edit)) - { - propertyValue = edit.PropertyValue; - return true; - } - } - propertyValue = null; - return false; - } - - protected bool EditProperty(PropertyDescriptor property, string key, object propertyValue) - { - if (IsEditing) - { - updates.Peek()[key] = new Edit(property, propertyValue); - return true; - } - return false; - } - - protected bool ClearEditProperty(PropertyDescriptor property, string key) - { - if (IsEditing) - { - updates.Peek().Remove(key); - return true; - } - return false; - } - - protected void AddEditDependency(IEditableObject editDependency) - { - if (IsEditing) - { - if (editDependencies == null) - { - editDependencies = new HashSet(); - } - - if (editDependencies.Add(editDependency)) - { - editDependency.BeginEdit(); - } - } - } - - #region Nested Class: SuppressEditingScope - - class SuppressEditingScope : IDisposable - { - private readonly DictionaryAdapterBase adapter; - - public SuppressEditingScope(DictionaryAdapterBase adapter) - { - this.adapter = adapter; - this.adapter.SuppressEditing(); - } - - public void Dispose() - { - adapter.ResumeEditing(); - } - } - - #endregion - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterBase.Notify.cs b/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterBase.Notify.cs deleted file mode 100644 index 2b0262a..0000000 --- a/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterBase.Notify.cs +++ /dev/null @@ -1,215 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System; - using System.Collections.Generic; - using System.ComponentModel; - using System.Linq; - - public abstract partial class DictionaryAdapterBase - { - [ThreadStatic] - private static TrackPropertyChangeScope readOnlyTrackingScope; - - private int suppressNotificationCount = 0; - - public event PropertyChangingEventHandler PropertyChanging; - public event PropertyChangedEventHandler PropertyChanged; - - public bool CanNotify { get; set; } - - public bool ShouldNotify - { - get { return CanNotify && suppressNotificationCount == 0; } - } - - public IDisposable SuppressNotificationsBlock() - { - return new NotificationSuppressionScope(this); - } - - public void SuppressNotifications() - { - ++suppressNotificationCount; - } - - public void ResumeNotifications() - { - --suppressNotificationCount; - } - - protected bool NotifyPropertyChanging(PropertyDescriptor property, object oldValue, object newValue) - { - if (property.SuppressNotifications || !ShouldNotify) - return true; - - var propertyChanging = PropertyChanging; - if (propertyChanging == null) - return true; - - var args = new PropertyChangingEventArgsEx(property.PropertyName, oldValue, newValue); - propertyChanging(this, args); - return !args.Cancel; - } - - protected void NotifyPropertyChanged(PropertyDescriptor property, object oldValue, object newValue) - { - if (property.SuppressNotifications || !ShouldNotify) - return; - - var propertyChanged = PropertyChanged; - if (propertyChanged == null) - return; - - propertyChanged(this, new PropertyChangedEventArgsEx(property.PropertyName, oldValue, newValue)); - } - - protected void NotifyPropertyChanged(string propertyName) - { - if (!ShouldNotify) - return; - - var propertyChanged = PropertyChanged; - if (propertyChanged == null) - return; - - propertyChanged(this, new PropertyChangedEventArgs(propertyName)); - } - - protected TrackPropertyChangeScope TrackPropertyChange(PropertyDescriptor property, - object oldValue, object newValue) - { - if (!ShouldNotify || property.SuppressNotifications) - return null; - - return new TrackPropertyChangeScope(this, property, oldValue); - } - - protected TrackPropertyChangeScope TrackReadonlyPropertyChanges() - { - if (!ShouldNotify || readOnlyTrackingScope != null) - return null; - - return readOnlyTrackingScope = new TrackPropertyChangeScope(this); - } - - private class NotificationSuppressionScope : IDisposable - { - private readonly DictionaryAdapterBase adapter; - - public NotificationSuppressionScope(DictionaryAdapterBase adapter) - { - this.adapter = adapter; - this.adapter.SuppressNotifications(); - } - - public void Dispose() - { - this.adapter.ResumeNotifications(); - } - } - - public class TrackPropertyChangeScope : IDisposable - { - private readonly DictionaryAdapterBase adapter; - private readonly PropertyDescriptor property; - private readonly object existingValue; - private Dictionary readOnlyProperties; - - public TrackPropertyChangeScope(DictionaryAdapterBase adapter) - { - this.adapter = adapter; - this.readOnlyProperties = adapter.This.Properties.Values - .Where( - pd => !pd.Property.CanWrite || pd.IsDynamicProperty - ) - .ToDictionary( - pd => pd, - pd => GetEffectivePropertyValue(pd) - ); - } - - public TrackPropertyChangeScope(DictionaryAdapterBase adapter, PropertyDescriptor property, object existingValue) - : this(adapter) - { - this.property = property; - this.existingValue = existingValue; - existingValue = adapter.GetProperty(property.PropertyName, true); // TODO: This looks unnecessary - } - - public void Dispose() - { - Notify(); - } - - public bool Notify() - { - if (readOnlyTrackingScope == this) - { - readOnlyTrackingScope = null; - return NotifyReadonly(); - } - - var newValue = GetEffectivePropertyValue(property); - - if (!NotifyIfChanged(property, existingValue, newValue)) - return false; - - if (readOnlyTrackingScope == null) - NotifyReadonly(); - - return true; - } - - private bool NotifyReadonly() - { - var changed = false; - - foreach (var readOnlyProperty in readOnlyProperties) - { - var descriptor = readOnlyProperty.Key; - var currentValue = GetEffectivePropertyValue(descriptor); - changed |= NotifyIfChanged(descriptor, readOnlyProperty.Value, currentValue); - } - - adapter.Invalidate(); - return changed; - } - - private bool NotifyIfChanged(PropertyDescriptor descriptor, object oldValue, object newValue) - { - if (Equals(oldValue, newValue)) - return false; - - adapter.NotifyPropertyChanged(descriptor, oldValue, newValue); - return true; - } - - private object GetEffectivePropertyValue(PropertyDescriptor property) - { - var value = adapter.GetProperty(property.PropertyName, true); - if (value == null || !property.IsDynamicProperty) - return value; - - var dynamicValue = value as IDynamicValue; - if (dynamicValue == null) - return value; - - return dynamicValue.GetValue(); - } - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterBase.Validate.cs b/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterBase.Validate.cs deleted file mode 100644 index e8fb683..0000000 --- a/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterBase.Validate.cs +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System; - using System.Collections.Generic; - using System.Linq; - - public partial class DictionaryAdapterBase : IDictionaryValidate - { - private ICollection validators; - - public bool CanValidate { get; set; } - - public bool IsValid - { - get - { - if (CanValidate && validators != null) - { - return !validators.Any(v => !v.IsValid(this)); - } - return !CanValidate; - } - } - - public string Error - { - get - { - if (CanValidate && validators != null) - { - return string.Join(Environment.NewLine, validators.Select( - v => v.Validate(this)).Where(e => !string.IsNullOrEmpty(e)).ToArray()); - } - return string.Empty; - } - } - - public string this[string columnName] - { - get - { - if (CanValidate && validators != null) - { - PropertyDescriptor property; - if (This.Properties.TryGetValue(columnName, out property)) - { - return string.Join(Environment.NewLine, validators.Select( - v => v.Validate(this, property)).Where(e => !string.IsNullOrEmpty(e)) - .ToArray()); - } - } - return string.Empty; - } - } - - public DictionaryValidateGroup ValidateGroups(params object[] groups) - { - return new DictionaryValidateGroup(groups, this); - } - - public IEnumerable Validators - { - get - { - return validators ?? Enumerable.Empty(); - } - } - - public void AddValidator(IDictionaryValidator validator) - { - if (validators == null) - { - validators = new HashSet(); - } - validators.Add(validator); - } - - protected internal void Invalidate() - { - if (CanValidate) - { - if (validators != null) foreach (var validator in validators) - { - validator.Invalidate(this); - } - - NotifyPropertyChanged("IsValid"); - } - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterBase.cs b/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterBase.cs deleted file mode 100644 index 184f4e6..0000000 --- a/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterBase.cs +++ /dev/null @@ -1,216 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System.Collections; - using System.ComponentModel; - using System.Linq; - using System.Reflection; - - public abstract partial class DictionaryAdapterBase : IDictionaryAdapter - { - public DictionaryAdapterBase(DictionaryAdapterInstance instance) - { - This = instance; - - CanEdit = typeof(IEditableObject).IsAssignableFrom(Meta.Type); - CanNotify = typeof(INotifyPropertyChanged).IsAssignableFrom(Meta.Type); - CanValidate = typeof(IDataErrorInfo).IsAssignableFrom(Meta.Type); - - Initialize(); - } - - public abstract DictionaryAdapterMeta Meta { get; } - - public DictionaryAdapterInstance This { get; private set; } - - public string GetKey(string propertyName) - { - PropertyDescriptor descriptor; - if (This.Properties.TryGetValue(propertyName, out descriptor)) - { - return descriptor.GetKey(this, propertyName, This.Descriptor); - } - return null; - } - - public virtual object GetProperty(string propertyName, bool ifExists) - { - PropertyDescriptor descriptor; - if (This.Properties.TryGetValue(propertyName, out descriptor)) - { - var propertyValue = descriptor.GetPropertyValue(this, propertyName, null, This.Descriptor, ifExists); - if (propertyValue is IEditableObject) - { - AddEditDependency((IEditableObject)propertyValue); - } - return propertyValue; - } - return null; - } - - public T GetPropertyOfType(string propertyName) - { - var propertyValue = GetProperty(propertyName, false); - return propertyValue != null ? (T)propertyValue : default(T); - } - - public object ReadProperty(string key) - { - object propertyValue = null; - if (GetEditedProperty(key, out propertyValue) == false) - { - var dictionary = GetDictionary(This.Dictionary, ref key); - if (dictionary != null) propertyValue = dictionary[key]; - } - return propertyValue; - } - - public virtual bool SetProperty(string propertyName, ref object value) - { - bool stored = false; - - PropertyDescriptor descriptor; - if (This.Properties.TryGetValue(propertyName, out descriptor)) - { - if (ShouldNotify == false) - { - stored = descriptor.SetPropertyValue(this, propertyName, ref value, This.Descriptor); - Invalidate(); - return stored; - } - - var existingValue = GetProperty(propertyName, true); - if (NotifyPropertyChanging(descriptor, existingValue, value) == false) - { - return false; - } - - var trackPropertyChange = TrackPropertyChange(descriptor, existingValue, value); - - stored = descriptor.SetPropertyValue(this, propertyName, ref value, This.Descriptor); - - if (stored && trackPropertyChange != null) - { - trackPropertyChange.Notify(); - } - } - - return stored; - } - - public void StoreProperty(PropertyDescriptor property, string key, object value) - { - if (property == null || EditProperty(property, key, value) == false) - { - var dictionary = GetDictionary(This.Dictionary, ref key); - if (dictionary != null) dictionary[key] = value; - } - } - - public void ClearProperty(PropertyDescriptor property, string key) - { - key = key ?? GetKey(property.PropertyName); - if (property == null || ClearEditProperty(property, key) == false) - { - var dictionary = GetDictionary(This.Dictionary, ref key); - if (dictionary != null) dictionary.Remove(key); - } - } - - public bool ShouldClearProperty(PropertyDescriptor property, object value) - { - return property == null || - property.Setters.OfType().Where(remove => remove.ShouldRemove(value)).Any(); - } - - public override bool Equals(object obj) - { - var other = obj as IDictionaryAdapter; - - if (other == null) - { - return false; - } - - if (ReferenceEquals(this, obj)) - { - return true; - } - - if (Meta.Type != other.Meta.Type) - { - return false; - } - - if (This.EqualityHashCodeStrategy != null) - { - return This.EqualityHashCodeStrategy.Equals(this, other); - } - - return base.Equals(obj); - } - - public override int GetHashCode() - { - if (This.OldHashCode.HasValue) - { - return This.OldHashCode.Value; - } - - int hashCode; - if (This.EqualityHashCodeStrategy == null || - This.EqualityHashCodeStrategy.GetHashCode(this, out hashCode) == false) - { - hashCode = base.GetHashCode(); - } - - This.OldHashCode = hashCode; - return hashCode; - } - - protected void Initialize() - { - var metaBehaviors = Meta.Behaviors; - var initializers = This.Initializers; - - foreach (var initializer in initializers) - { - initializer.Initialize(this, metaBehaviors); - } - - foreach (var property in This.Properties.Values) - { - if (property.Fetch) - GetProperty(property.PropertyName, false); - } - } - - private static IDictionary GetDictionary(IDictionary dictionary, ref string key) - { - if (key.StartsWith("!") == false) - { - var parts = key.Split(','); - for (var i = 0; i < parts.Length - 1; ++i) - { - dictionary = dictionary[parts[i]] as IDictionary; - if (dictionary == null) return null; - } - key = parts[parts.Length - 1]; - } - return dictionary; - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterExtensions.cs b/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterExtensions.cs deleted file mode 100644 index 3a977fb..0000000 --- a/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterExtensions.cs +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System.Linq; - - public static class DictionaryAdapterExtensions - { - public static IVirtual AsVirtual(this IDictionaryAdapter dictionaryAdapter) - { - var descriptor = dictionaryAdapter.This.Descriptor; - return descriptor != null - ? descriptor.Getters.OfType().FirstOrDefault() - : null; - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterFactory.cs b/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterFactory.cs deleted file mode 100644 index a2cb08a..0000000 --- a/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterFactory.cs +++ /dev/null @@ -1,495 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System; - using System.Collections; - using System.Collections.Generic; - using System.Collections.Specialized; - using System.ComponentModel; - using System.Linq; - using System.Reflection; - using System.Reflection.Emit; - using System.Threading; - using System.Diagnostics; - - using Castle.Components.DictionaryAdapter.Xml; - using Castle.Core.Internal; - - /// - /// Uses Reflection.Emit to expose the properties of a dictionary - /// through a dynamic implementation of a typed interface. - /// - public class DictionaryAdapterFactory : IDictionaryAdapterFactory - { - private readonly SynchronizedDictionary interfaceToMeta = - new SynchronizedDictionary(); - - #region IDictionaryAdapterFactory - - /// - public T GetAdapter(IDictionary dictionary) - { - return (T) GetAdapter(typeof(T), dictionary); - } - - /// - public object GetAdapter(Type type, IDictionary dictionary) - { - return InternalGetAdapter(type, dictionary, null); - } - - /// - public object GetAdapter(Type type, IDictionary dictionary, PropertyDescriptor descriptor) - { - return InternalGetAdapter(type, dictionary, descriptor); - } - - /// - public T GetAdapter(IDictionary dictionary) - { - return (T) GetAdapter(typeof(T), dictionary); - } - - /// - public object GetAdapter(Type type, IDictionary dictionary) - { - var adapter = new GenericDictionaryAdapter(dictionary); - return InternalGetAdapter(type, adapter, null); - } - - /// - public T GetAdapter(NameValueCollection nameValues) - { - return GetAdapter(new NameValueCollectionAdapter(nameValues)); - } - - /// - public object GetAdapter(Type type, NameValueCollection nameValues) - { - return GetAdapter(type, new NameValueCollectionAdapter(nameValues)); - } - - /// - public T GetAdapter(System.Xml.XmlNode xmlNode) - { - return (T)GetAdapter(typeof(T), xmlNode); - } - - /// - public object GetAdapter(Type type, System.Xml.XmlNode xmlNode) - { - var xml = new XmlAdapter(xmlNode); - return GetAdapter(type, new Hashtable(), new PropertyDescriptor() - .AddBehavior(XmlMetadataBehavior.Default) - .AddBehavior(xml)); - } - - /// - public DictionaryAdapterMeta GetAdapterMeta(Type type) - { - return GetAdapterMeta(type, null as PropertyDescriptor); - } - - /// - public DictionaryAdapterMeta GetAdapterMeta(Type type, PropertyDescriptor descriptor) - { - return InternalGetAdapterMeta(type, descriptor, null); - } - - /// - public DictionaryAdapterMeta GetAdapterMeta(Type type, DictionaryAdapterMeta other) - { - return InternalGetAdapterMeta(type, null, other); - } - - #endregion - - private DictionaryAdapterMeta InternalGetAdapterMeta(Type type, - PropertyDescriptor descriptor, DictionaryAdapterMeta other) - { - if (type == null) - throw new ArgumentNullException(nameof(type)); - if (type.IsInterface == false) - throw new ArgumentException("Only interfaces can be adapted to a dictionary", nameof(type)); - - return interfaceToMeta.GetOrAdd(type, t => - { - if (descriptor == null && other != null) - { - descriptor = other.CreateDescriptor(); - } - - var typeBuilder = CreateTypeBuilder(type); - return CreateAdapterMeta(type, typeBuilder, descriptor); - }); - } - - private object InternalGetAdapter(Type type, IDictionary dictionary, PropertyDescriptor descriptor) - { - var meta = InternalGetAdapterMeta(type, descriptor, null); - return meta.CreateInstance(dictionary, descriptor); - } - - #region Type Builders - - private static TypeBuilder CreateTypeBuilder(Type type) - { - var assemblyName = new AssemblyName("CastleDictionaryAdapterAssembly"); - var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); - var moduleBuilder = assemblyBuilder.DefineDynamicModule("CastleDictionaryAdapterModule"); - return CreateAdapterType(type, moduleBuilder); - } - - private static TypeBuilder CreateAdapterType(Type type, ModuleBuilder moduleBuilder) - { - var typeBuilder = moduleBuilder.DefineType("CastleDictionaryAdapterType", - TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.BeforeFieldInit); - typeBuilder.AddInterfaceImplementation(type); - typeBuilder.SetParent(typeof(DictionaryAdapterBase)); - - var attribCtorParams = new[] { typeof(Type) }; - var attribCtorInfo = typeof(DictionaryAdapterAttribute).GetConstructor(attribCtorParams); - var attribBuilder = new CustomAttributeBuilder(attribCtorInfo, new[] { type }); - typeBuilder.SetCustomAttribute(attribBuilder); - - var debugAttribCtorParams = new[] { typeof(string) }; - var debugAttribCtorInfo = typeof(DebuggerDisplayAttribute).GetConstructor(debugAttribCtorParams); - var debugAttribBuilder = new CustomAttributeBuilder(debugAttribCtorInfo, new[] { "Type: {Meta.Type.FullName,nq}" }); - typeBuilder.SetCustomAttribute(debugAttribBuilder); - return typeBuilder; - } - - private DictionaryAdapterMeta CreateAdapterMeta(Type type, TypeBuilder typeBuilder, PropertyDescriptor descriptor) - { - var binding = FieldAttributes.Public | FieldAttributes.Static; - var metaField = typeBuilder.DefineField("__meta", typeof(DictionaryAdapterMeta), binding); - var constructor = CreateAdapterConstructor(typeBuilder); - CreateAdapterFactoryMethod(typeBuilder, constructor); - - object[] typeBehaviors; - var initializers = new PropertyDescriptor(); - var propertyMap = GetPropertyDescriptors(type, initializers, out typeBehaviors); - - if (descriptor != null) - { - initializers.AddBehaviors(descriptor.MetaInitializers); - typeBehaviors = typeBehaviors.Union(descriptor.Annotations).ToArray(); - } - - CreateMetaProperty(typeBuilder, AdapterGetMeta, metaField); - - foreach (var property in propertyMap) - { - CreateAdapterProperty(typeBuilder, property.Value); - } - - var implementation = typeBuilder.CreateTypeInfo(); - var creator = (Func)implementation - .GetDeclaredMethod("__Create") - .CreateDelegate(typeof(Func)); - - var meta = new DictionaryAdapterMeta(type, implementation, typeBehaviors, - initializers.MetaInitializers.ToArray(), initializers.Initializers.ToArray(), - propertyMap, this, creator); - - const BindingFlags metaBindings = BindingFlags.Public | BindingFlags.Static; - var field = implementation.GetField("__meta", metaBindings); - field.SetValue(implementation, meta); - return meta; - } - - private static readonly PropertyInfo AdapterGetMeta = typeof(IDictionaryAdapter).GetProperty("Meta"); - - #endregion - - #region Constructors - - private static ConstructorInfo CreateAdapterConstructor(TypeBuilder typeBuilder) - { - var constructorBuilder = typeBuilder.DefineConstructor( - MethodAttributes.Public | MethodAttributes.HideBySig, CallingConventions.Standard, - ConstructorParameterTypes - ); - - var ilGenerator = constructorBuilder.GetILGenerator(); - - ilGenerator.Emit(OpCodes.Ldarg_0); - ilGenerator.Emit(OpCodes.Ldarg_1); - ilGenerator.Emit(OpCodes.Call, BaseCtor); - ilGenerator.Emit(OpCodes.Ret); - - return constructorBuilder; - } - - private static void CreateAdapterFactoryMethod(TypeBuilder typeBuilder, ConstructorInfo constructor) - { - var factoryBuilder = typeBuilder.DefineMethod - ( - "__Create", - MethodAttributes.Public | MethodAttributes.Static | MethodAttributes.HideBySig, - typeof(IDictionaryAdapter), - ConstructorParameterTypes - ); - - var ilGenerator = factoryBuilder.GetILGenerator(); - ilGenerator.Emit(OpCodes.Ldarg_0); - ilGenerator.Emit(OpCodes.Newobj, constructor); - ilGenerator.Emit(OpCodes.Ret); - } - - private static readonly ConstructorInfo BaseCtor = typeof(DictionaryAdapterBase).GetConstructors()[0]; - private static readonly Type[] ConstructorParameterTypes = { typeof(DictionaryAdapterInstance) }; - - #endregion - - #region Properties - - private static void CreateMetaProperty(TypeBuilder typeBuilder, PropertyInfo prop, FieldInfo field) - { - const MethodAttributes propAttribs = MethodAttributes.Public | MethodAttributes.SpecialName | - MethodAttributes.HideBySig | MethodAttributes.ReuseSlot | - MethodAttributes.Virtual | MethodAttributes.Final; - - var getMethodBuilder = typeBuilder.DefineMethod("get_" + prop.Name, propAttribs, prop.PropertyType, null); - - var getILGenerator = getMethodBuilder.GetILGenerator(); - if (field.IsStatic) - { - getILGenerator.Emit(OpCodes.Ldsfld, field); - } - else - { - getILGenerator.Emit(OpCodes.Ldarg_0); - getILGenerator.Emit(OpCodes.Ldfld, field); - } - getILGenerator.Emit(OpCodes.Ret); - - typeBuilder.DefineMethodOverride(getMethodBuilder, prop.GetGetMethod()); - } - - private static void CreateAdapterProperty(TypeBuilder typeBuilder, PropertyDescriptor descriptor) - { - var property = descriptor.Property; - var propertyBuilder = typeBuilder.DefineProperty(property.Name, property.Attributes, property.PropertyType, null); - const MethodAttributes propAttribs = MethodAttributes.Public | MethodAttributes.SpecialName | - MethodAttributes.HideBySig | MethodAttributes.Virtual; - - if (property.CanRead) - { - CreatePropertyGetMethod(typeBuilder, propertyBuilder, descriptor, propAttribs); - } - - if (property.CanWrite) - { - CreatePropertySetMethod(typeBuilder, propertyBuilder, descriptor, propAttribs); - } - } - - private static void PreparePropertyMethod(PropertyDescriptor descriptor, ILGenerator propILGenerator) - { - propILGenerator.DeclareLocal(typeof(string)); - propILGenerator.DeclareLocal(typeof(object)); - - // key = propertyInfo.Name - propILGenerator.Emit(OpCodes.Ldstr, descriptor.PropertyName); - propILGenerator.Emit(OpCodes.Stloc_0); - } - - #endregion - - #region Getters - - private static void CreatePropertyGetMethod(TypeBuilder typeBuilder, PropertyBuilder propertyBuilder, - PropertyDescriptor descriptor, MethodAttributes propAttribs) - { - var getMethodBuilder = typeBuilder.DefineMethod("get_" + descriptor.PropertyName, propAttribs, descriptor.PropertyType, null); - var getILGenerator = getMethodBuilder.GetILGenerator(); - var returnDefault = getILGenerator.DefineLabel(); - var storeResult = getILGenerator.DefineLabel(); - var loadResult = getILGenerator.DefineLabel(); - - PreparePropertyMethod(descriptor, getILGenerator); - - var result = getILGenerator.DeclareLocal(descriptor.PropertyType); - - // value = GetProperty(key, false) - getILGenerator.Emit(OpCodes.Ldarg_0); - getILGenerator.Emit(OpCodes.Ldloc_0); - getILGenerator.Emit(OpCodes.Ldc_I4_0); - getILGenerator.Emit(OpCodes.Callvirt, AdapterGetProperty); - getILGenerator.Emit(OpCodes.Stloc_1); - - // if (value == null) return null - getILGenerator.Emit(OpCodes.Ldloc_1); - getILGenerator.Emit(OpCodes.Brfalse_S, returnDefault); - - // return (propertyInfo.PropertyType) value - getILGenerator.Emit(OpCodes.Ldloc_1); - getILGenerator.Emit(OpCodes.Unbox_Any, descriptor.PropertyType); - getILGenerator.Emit(OpCodes.Br_S, storeResult); - - getILGenerator.MarkLabel(returnDefault); - getILGenerator.Emit(OpCodes.Ldloca_S, result); - getILGenerator.Emit(OpCodes.Initobj, descriptor.PropertyType); - getILGenerator.Emit(OpCodes.Br_S, loadResult); - - getILGenerator.MarkLabel(storeResult); - getILGenerator.Emit(OpCodes.Stloc_S, result); - - getILGenerator.MarkLabel(loadResult); - getILGenerator.Emit(OpCodes.Ldloc_S, result); - getILGenerator.Emit(OpCodes.Ret); - - propertyBuilder.SetGetMethod(getMethodBuilder); - } - - private static readonly MethodInfo AdapterGetProperty = typeof(IDictionaryAdapter).GetMethod("GetProperty"); - - #endregion - - #region Setters - - private static void CreatePropertySetMethod(TypeBuilder typeBuilder, PropertyBuilder propertyBuilder, - PropertyDescriptor descriptor, MethodAttributes propAttribs) - { - var setMethodBuilder = typeBuilder.DefineMethod("set_" + descriptor.PropertyName, propAttribs, null, new[] {descriptor.PropertyType}); - var setILGenerator = setMethodBuilder.GetILGenerator(); - PreparePropertyMethod(descriptor, setILGenerator); - - setILGenerator.Emit(OpCodes.Ldarg_1); - if (descriptor.PropertyType.IsValueType) - { - setILGenerator.Emit(OpCodes.Box, descriptor.PropertyType); - } - setILGenerator.Emit(OpCodes.Stloc_1); - - // ignore = SetProperty(key, ref value) - setILGenerator.Emit(OpCodes.Ldarg_0); - setILGenerator.Emit(OpCodes.Ldloc_0); - setILGenerator.Emit(OpCodes.Ldloca_S, 1); - setILGenerator.Emit(OpCodes.Callvirt, AdapterSetProperty); - setILGenerator.Emit(OpCodes.Pop); - setILGenerator.Emit(OpCodes.Ret); - - propertyBuilder.SetSetMethod(setMethodBuilder); - } - - private static readonly MethodInfo AdapterSetProperty = typeof(IDictionaryAdapter).GetMethod("SetProperty"); - - #endregion - - #region Descriptors - - private static Dictionary GetPropertyDescriptors(Type type, PropertyDescriptor initializers, out object[] typeBehaviors) - { - var propertyMap = new Dictionary(); - var interfaceBehaviors = typeBehaviors = ExpandBehaviors(InterfaceAttributeUtil.GetAttributes(type, true)).ToArray(); - var defaultFetch = typeBehaviors.OfType().Select(b => (bool?)b.Fetch).FirstOrDefault().GetValueOrDefault(); - - initializers.AddBehaviors(typeBehaviors.OfType()) - .AddBehaviors(typeBehaviors.OfType()); - - CollectProperties(type, (property, reflectedType) => - { - var propertyBehaviors = ExpandBehaviors(property.GetCustomAttributes(false)).ToArray(); - var propertyDescriptor = new PropertyDescriptor(property, propertyBehaviors) - .AddBehaviors(propertyBehaviors.OfType()) - .AddBehaviors(interfaceBehaviors.OfType().Where(b => b is IDictionaryKeyBuilder == false)); - var expandedBehaviors = ExpandBehaviors(InterfaceAttributeUtil - .GetAttributes(reflectedType, true)) - .OfType(); - propertyDescriptor = propertyDescriptor.AddBehaviors(expandedBehaviors); - - AddDefaultGetter(propertyDescriptor); - - var propertyFetch = propertyBehaviors.OfType().Select(b => (bool?)b.Fetch).FirstOrDefault(); - propertyDescriptor.IfExists = propertyBehaviors.OfType().Any(); - propertyDescriptor.Fetch = propertyFetch.GetValueOrDefault(defaultFetch); - - foreach (var descriptorInitializer in propertyDescriptor.Behaviors.OfType()) - { - descriptorInitializer.Initialize(propertyDescriptor, propertyBehaviors); - } - - initializers.AddBehaviors(propertyBehaviors.OfType()); - - PropertyDescriptor existingDescriptor; - if (propertyMap.TryGetValue(property.Name, out existingDescriptor)) - { - var existingProperty = existingDescriptor.Property; - if (existingProperty.PropertyType == property.PropertyType) - { - if (property.CanRead && property.CanWrite) - { - propertyMap[property.Name] = propertyDescriptor; - } - return; - } - } - - propertyMap.Add(property.Name, propertyDescriptor); - }); - - return propertyMap; - } - - private static IEnumerable ExpandBehaviors(IEnumerable behaviors) - { - foreach (var behavior in behaviors) - { - if (behavior is IDictionaryBehaviorBuilder) - { - foreach (var build in ((IDictionaryBehaviorBuilder)behavior).BuildBehaviors()) - yield return build; - } - else - { - yield return behavior; - } - } - } - - private static void CollectProperties(Type currentType, Action onProperty) - { - var types = new List(); - types.Add(currentType); - types.AddRange(currentType.GetInterfaces()); - const BindingFlags publicBindings = BindingFlags.Public | BindingFlags.Instance; - - foreach (var reflectedType in types.Where(t => InfrastructureTypes.Contains(t) == false)) - foreach (var property in reflectedType.GetProperties(publicBindings)) - { - onProperty(property, reflectedType); - } - } - - private static void AddDefaultGetter(PropertyDescriptor descriptor) - { - if (descriptor.TypeConverter != null) - descriptor.AddBehavior(new DefaultPropertyGetter(descriptor.TypeConverter)); - } - - private static readonly HashSet InfrastructureTypes = new HashSet - { - typeof (IEditableObject), typeof (IDictionaryEdit), typeof (IChangeTracking), - typeof (IRevertibleChangeTracking), typeof (IDictionaryNotify), - typeof (IDataErrorInfo), - typeof (IDictionaryValidate), typeof (IDictionaryAdapter) - }; - - #endregion - } -} \ No newline at end of file diff --git a/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterInstance.cs b/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterInstance.cs deleted file mode 100644 index e97b08a..0000000 --- a/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterInstance.cs +++ /dev/null @@ -1,154 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System; - using System.Collections; - using System.Collections.Generic; - using System.Linq; - using Castle.Core; - - public class DictionaryAdapterInstance - { - private IDictionary extendedProperties; - private List copyStrategies; - - public DictionaryAdapterInstance(IDictionary dictionary, DictionaryAdapterMeta meta, - PropertyDescriptor descriptor, IDictionaryAdapterFactory factory) - { - Dictionary = dictionary; - Descriptor = descriptor; - Factory = factory; - - List behaviors; - - if (null == descriptor || null == (behaviors = descriptor.BehaviorsInternal)) - { - Initializers = meta.Initializers; - Properties = MergeProperties(meta.Properties); - } - else - { - Initializers = MergeInitializers(meta.Initializers, behaviors); - Properties = MergeProperties(meta.Properties, behaviors); - } - } - - internal int? OldHashCode { get; set; } - - public IDictionary Dictionary { get; private set; } - - public PropertyDescriptor Descriptor { get; private set; } - - public IDictionaryAdapterFactory Factory { get; private set; } - - public IDictionaryInitializer[] Initializers { get; private set; } - - public IDictionary Properties { get; private set; } - - public IDictionaryEqualityHashCodeStrategy EqualityHashCodeStrategy { get; set; } - - public IDictionaryCreateStrategy CreateStrategy { get; set; } - - public IDictionaryCoerceStrategy CoerceStrategy { get; set; } - - public IEnumerable CopyStrategies - { - get - { - return copyStrategies ?? Enumerable.Empty(); - } - } - - public void AddCopyStrategy(IDictionaryCopyStrategy copyStrategy) - { - if (copyStrategy == null) - throw new ArgumentNullException(nameof(copyStrategy)); - - if (copyStrategies == null) - copyStrategies = new List(); - - copyStrategies.Add(copyStrategy); - } - - public IDictionary ExtendedProperties - { - get - { - if (extendedProperties == null) - { - extendedProperties = new Dictionary(); - } - return extendedProperties; - } - } - - private static IDictionaryInitializer[] MergeInitializers( - IDictionaryInitializer[] source, List behaviors) - { - int index, count; - IDictionaryInitializer initializer; - var result = null as List; - - count = source.Length; - for (index = 0; index < count; index++) - PropertyDescriptor.MergeBehavior(ref result, source[index]); - - count = behaviors.Count; - for (index = 0; index < count; index++) - if (null != (initializer = behaviors[index] as IDictionaryInitializer)) - PropertyDescriptor.MergeBehavior(ref result, initializer); - - return result == null - ? NoInitializers - : result.ToArray(); - } - - private static IDictionary MergeProperties( - IDictionary source) - { - var properties = new Dictionary(); - - foreach (var sourceProperty in source) - { - properties[sourceProperty.Key] = new PropertyDescriptor(sourceProperty.Value, true); - } - - return properties; - } - - private static IDictionary MergeProperties( - IDictionary source, List behaviors) - { - int index, count = behaviors.Count; - var properties = new Dictionary(); - - foreach (var sourceProperty in source) - { - var property = new PropertyDescriptor(sourceProperty.Value, true); - - for (index = 0; index < count; index++) - property.AddBehavior(behaviors[index]); - - properties[sourceProperty.Key] = property; - } - - return properties; - } - - private static readonly IDictionaryInitializer[] - NoInitializers = { }; - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterMeta.cs b/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterMeta.cs deleted file mode 100644 index 1953393..0000000 --- a/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterMeta.cs +++ /dev/null @@ -1,130 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System; - using System.Collections; - using System.Collections.Generic; - using System.Linq; - using System.Diagnostics; - - [DebuggerDisplay("Type: {Type.FullName,nq}")] - public class DictionaryAdapterMeta - { - private IDictionary extendedProperties; - private readonly Func creator; - - public DictionaryAdapterMeta(Type type, Type implementation, object[] behaviors, IDictionaryMetaInitializer[] metaInitializers, - IDictionaryInitializer[] initializers, IDictionary properties, - IDictionaryAdapterFactory factory, Func creator) - { - Type = type; - Implementation = implementation; - Behaviors = behaviors; - MetaInitializers = metaInitializers; - Initializers = initializers; - Properties = properties; - Factory = factory; - this.creator = creator; - - InitializeMeta(); - } - - public Type Type { get; private set; } - - public Type Implementation { get; private set; } - - public object[] Behaviors { get; private set; } - - public IDictionaryAdapterFactory Factory { get; private set; } - - public IDictionary Properties { get; private set; } - - public IDictionaryMetaInitializer[] MetaInitializers { get; private set; } - - public IDictionaryInitializer[] Initializers { get; private set; } - - public IDictionary ExtendedProperties - { - get - { - if (extendedProperties == null) - { - extendedProperties = new Dictionary(); - } - return extendedProperties; - } - } - - public PropertyDescriptor CreateDescriptor() - { - var metaInitializers = MetaInitializers; - var sharedAnnotations = CollectSharedBehaviors(Behaviors, metaInitializers); - var sharedInitializers = CollectSharedBehaviors(Initializers, metaInitializers); - - var descriptor = (sharedAnnotations != null) - ? new PropertyDescriptor(sharedAnnotations.ToArray()) - : new PropertyDescriptor(); - - descriptor.AddBehaviors(metaInitializers); - - if (sharedInitializers != null) - descriptor.AddBehaviors(sharedInitializers); - - return descriptor; - } - - private static List CollectSharedBehaviors(T[] source, IDictionaryMetaInitializer[] predicates) - { - var results = null as List; - - foreach (var candidate in source) - { - foreach (var predicate in predicates) - { - if (predicate.ShouldHaveBehavior(candidate)) - { - if (results == null) - results = new List(source.Length); - - results.Add(candidate); - break; // next candidate - } - } - } - - return results; - } - - public DictionaryAdapterMeta GetAdapterMeta(Type type) - { - return Factory.GetAdapterMeta(type, this); - } - - public object CreateInstance(IDictionary dictionary, PropertyDescriptor descriptor) - { - var instance = new DictionaryAdapterInstance(dictionary, this, descriptor, Factory); - return creator(instance); - } - - private void InitializeMeta() - { - foreach (var metaInitializer in MetaInitializers) - { - metaInitializer.Initialize(Factory, this); - } - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/DictionaryValidateGroup.cs b/Castle.Core/Components.DictionaryAdapter/DictionaryValidateGroup.cs deleted file mode 100644 index 14d71a2..0000000 --- a/Castle.Core/Components.DictionaryAdapter/DictionaryValidateGroup.cs +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System; - using System.Collections.Generic; - using System.ComponentModel; - using System.Linq; - - public class DictionaryValidateGroup : IDictionaryValidate, INotifyPropertyChanged, IDisposable - { - private readonly object[] groups; - private readonly IDictionaryAdapter adapter; - private readonly string[] propertyNames; - private readonly PropertyChangedEventHandler propertyChanged; - - public DictionaryValidateGroup(object[] groups, IDictionaryAdapter adapter) - { - this.groups = groups; - this.adapter = adapter; - - propertyNames = (from property in this.adapter.This.Properties.Values - from groupings in property.Annotations.OfType() - where this.groups.Intersect(groupings.Group).Any() - select property.PropertyName).Distinct().ToArray(); - - if (propertyNames.Length > 0 && adapter.CanNotify) - { - propertyChanged += (sender, args) => - { - if (PropertyChanged != null) - PropertyChanged(this, args); - }; - this.adapter.PropertyChanged += propertyChanged; - } - } - - public event PropertyChangedEventHandler PropertyChanged; - - public bool CanValidate - { - get { return adapter.CanValidate; } - set { adapter.CanValidate = value; } - } - - public bool IsValid - { - get { return string.IsNullOrEmpty(Error); } - } - - public string Error - { - get - { - return string.Join(Environment.NewLine, - propertyNames.Select(propertyName => adapter[propertyName]) - .Where(errors => !string.IsNullOrEmpty(errors)).ToArray()); - } - } - - public string this[string columnName] - { - get - { - if (Array.IndexOf(propertyNames, columnName) >= 0) - { - return adapter[columnName]; - } - return string.Empty; - } - } - - public DictionaryValidateGroup ValidateGroups(params object[] groups) - { - groups = this.groups.Union(groups).ToArray(); - return new DictionaryValidateGroup(groups, adapter); - } - - public IEnumerable Validators - { - get { return adapter.Validators; } - } - - public void AddValidator(IDictionaryValidator validator) - { - throw new NotSupportedException(); - } - - public void Dispose() - { - adapter.PropertyChanged -= propertyChanged; - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/DynamicDictionary.cs b/Castle.Core/Components.DictionaryAdapter/DynamicDictionary.cs deleted file mode 100644 index c88cff9..0000000 --- a/Castle.Core/Components.DictionaryAdapter/DynamicDictionary.cs +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System.Collections; - using System.Collections.Generic; - using System.Dynamic; - using System.Linq; - - /// - /// Wraps a with a dynamic object to expose a bit better looking API. - /// The implementation is trivial and assumes keys are s. - /// - public class DynamicDictionary : DynamicObject - { - private readonly IDictionary dictionary; - - public DynamicDictionary(IDictionary dictionary) - { - this.dictionary = dictionary; - } - - public override IEnumerable GetDynamicMemberNames() - { - return from object key in dictionary.Keys select key.ToString(); - } - - public override bool TryGetMember(GetMemberBinder binder, out object result) - { - result = dictionary[binder.Name]; - return true; - } - - public override bool TrySetMember(SetMemberBinder binder, object value) - { - dictionary[binder.Name] = value; - return true; - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/GenericDictionaryAdapter.cs b/Castle.Core/Components.DictionaryAdapter/GenericDictionaryAdapter.cs deleted file mode 100644 index 9780395..0000000 --- a/Castle.Core/Components.DictionaryAdapter/GenericDictionaryAdapter.cs +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"; -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System; - using System.Collections.Generic; - - public class GenericDictionaryAdapter : AbstractDictionaryAdapter - { - private readonly IDictionary dictionary; - - public GenericDictionaryAdapter(IDictionary dictionary) - { - this.dictionary = dictionary; - } - - public override bool IsReadOnly - { - get { return dictionary.IsReadOnly; } - } - - public override bool Contains(object key) - { - return dictionary.Keys.Contains(GetKey(key)); - } - - public override object this[object key] - { - get - { - TValue value; - return dictionary.TryGetValue(GetKey(key), out value) ? value : default(TValue); - } - set { dictionary[GetKey(key)] = (TValue)value; } - } - - private static string GetKey(object key) - { - if (key == null) - { - throw new ArgumentNullException(nameof(key)); - } - return key.ToString(); - } - } - - public static class GenericDictionaryAdapter - { - public static GenericDictionaryAdapter ForDictionaryAdapter(this IDictionary dictionary) - { - return new GenericDictionaryAdapter(dictionary); - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/IDictionaryAdapter.cs b/Castle.Core/Components.DictionaryAdapter/IDictionaryAdapter.cs deleted file mode 100644 index 4dc2619..0000000 --- a/Castle.Core/Components.DictionaryAdapter/IDictionaryAdapter.cs +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System; - - /// - /// Contract for manipulating the Dictionary adapter. - /// - public interface IDictionaryAdapter : IDictionaryEdit, IDictionaryNotify, IDictionaryValidate, IDictionaryCreate - { - DictionaryAdapterMeta Meta { get; } - - DictionaryAdapterInstance This { get; } - - string GetKey(string propertyName); - - object GetProperty(string propertyName, bool ifExists); - - object ReadProperty(string key); - - T GetPropertyOfType(string propertyName); - - bool SetProperty(string propertyName, ref object value); - - void StoreProperty(PropertyDescriptor property, string key, object value); - - void ClearProperty(PropertyDescriptor property, string key); - - bool ShouldClearProperty(PropertyDescriptor property, object value); - - void CopyTo(IDictionaryAdapter other); - - void CopyTo(IDictionaryAdapter other, Func selector); - - T Coerce() where T : class; - - object Coerce(Type type); - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/IDictionaryAdapterFactory.cs b/Castle.Core/Components.DictionaryAdapter/IDictionaryAdapterFactory.cs deleted file mode 100644 index bed7883..0000000 --- a/Castle.Core/Components.DictionaryAdapter/IDictionaryAdapterFactory.cs +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - - -namespace Castle.Components.DictionaryAdapter -{ - using System; - using System.Collections; - using System.Collections.Specialized; - - /// - /// Defines the contract for building typed dictionary adapters. - /// - public interface IDictionaryAdapterFactory - { - /// - /// Gets a typed adapter bound to the . - /// - /// The typed interface. - /// The underlying source of properties. - /// An implementation of the typed interface bound to the dictionary. - /// - /// The type represented by T must be an interface with properties. - /// - T GetAdapter(IDictionary dictionary); - - /// - /// Gets a typed adapter bound to the . - /// - /// The typed interface. - /// The underlying source of properties. - /// An implementation of the typed interface bound to the dictionary. - /// - /// The type represented by T must be an interface with properties. - /// - object GetAdapter(Type type, IDictionary dictionary); - - /// - /// Gets a typed adapter bound to the . - /// - /// The typed interface. - /// The underlying source of properties. - /// The property descriptor. - /// An implementation of the typed interface bound to the dictionary. - /// - /// The type represented by T must be an interface with properties. - /// - object GetAdapter(Type type, IDictionary dictionary, PropertyDescriptor descriptor); - - /// - /// Gets a typed adapter bound to the . - /// - /// The typed interface. - /// The underlying source of properties. - /// An implementation of the typed interface bound to the namedValues. - /// - /// The type represented by T must be an interface with properties. - /// - T GetAdapter(NameValueCollection nameValues); - - /// - /// Gets a typed adapter bound to the . - /// - /// The typed interface. - /// The underlying source of properties. - /// An implementation of the typed interface bound to the namedValues. - /// - /// The type represented by T must be an interface with properties. - /// - object GetAdapter(Type type, NameValueCollection nameValues); - - /// - /// Gets a typed adapter bound to the . - /// - /// The typed interface. - /// The underlying source of properties. - /// An implementation of the typed interface bound to the . - /// - /// The type represented by T must be an interface with properties. - /// - T GetAdapter(System.Xml.XmlNode xmlNode); - - /// - /// Gets a typed adapter bound to the . - /// - /// The typed interface. - /// The underlying source of properties. - /// An implementation of the typed interface bound to the . - /// - /// The type represented by T must be an interface with properties. - /// - object GetAdapter(Type type, System.Xml.XmlNode xmlNode); - - /// - /// Gets the associated with the type. - /// - /// The typed interface. - /// The adapter meta-data. - DictionaryAdapterMeta GetAdapterMeta(Type type); - - /// - /// Gets the associated with the type. - /// - /// The typed interface. - /// The property descriptor. - /// The adapter meta-data. - DictionaryAdapterMeta GetAdapterMeta(Type type, PropertyDescriptor descriptor); - - /// - /// Gets the associated with the type. - /// - /// The typed interface. - /// Another from which to copy behaviors. - /// The adapter meta-data. - DictionaryAdapterMeta GetAdapterMeta(Type type, DictionaryAdapterMeta other); - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/IDictionaryAdapterVisitor.cs b/Castle.Core/Components.DictionaryAdapter/IDictionaryAdapterVisitor.cs deleted file mode 100644 index 99d547d..0000000 --- a/Castle.Core/Components.DictionaryAdapter/IDictionaryAdapterVisitor.cs +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System; - - /// - /// Contract for traversing a . - /// - public interface IDictionaryAdapterVisitor - { - bool VisitDictionaryAdapter(IDictionaryAdapter dictionaryAdapter, object state); - - bool VisitDictionaryAdapter(IDictionaryAdapter dictionaryAdapter, Func selector, object state); - - void VisitProperty(IDictionaryAdapter dictionaryAdapter, PropertyDescriptor property, object state); - - void VisitInterface(IDictionaryAdapter dictionaryAdapter, PropertyDescriptor property, object state); - - void VisitCollection(IDictionaryAdapter dictionaryAdapter, PropertyDescriptor property, Type collectionItemType, object state); - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/IDictionaryBehavior.cs b/Castle.Core/Components.DictionaryAdapter/IDictionaryBehavior.cs deleted file mode 100644 index 770fd41..0000000 --- a/Castle.Core/Components.DictionaryAdapter/IDictionaryBehavior.cs +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - /// - /// Defines the contract for customizing dictionary access. - /// - public interface IDictionaryBehavior - { - /// - /// Determines relative order to apply related behaviors. - /// - int ExecutionOrder { get; } - - /// - /// Copies the dictionary behavior. - /// - /// null if should not be copied. Otherwise copy. - IDictionaryBehavior Copy(); - } -} \ No newline at end of file diff --git a/Castle.Core/Components.DictionaryAdapter/IDictionaryBehaviorBuilder.cs b/Castle.Core/Components.DictionaryAdapter/IDictionaryBehaviorBuilder.cs deleted file mode 100644 index 4d53162..0000000 --- a/Castle.Core/Components.DictionaryAdapter/IDictionaryBehaviorBuilder.cs +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System.Collections.Generic; - - /// - /// Defines the contract for building s. - /// - public interface IDictionaryBehaviorBuilder - { - /// - /// Builds the dictionary behaviors. - /// - object[] BuildBehaviors(); - } -} \ No newline at end of file diff --git a/Castle.Core/Components.DictionaryAdapter/IDictionaryCoerceStrategy.cs b/Castle.Core/Components.DictionaryAdapter/IDictionaryCoerceStrategy.cs deleted file mode 100644 index 57c5cea..0000000 --- a/Castle.Core/Components.DictionaryAdapter/IDictionaryCoerceStrategy.cs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System; - - public interface IDictionaryCoerceStrategy - { - object Coerce(IDictionaryAdapter adapter, Type type); - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/IDictionaryCopyStrategy.cs b/Castle.Core/Components.DictionaryAdapter/IDictionaryCopyStrategy.cs deleted file mode 100644 index 54898a2..0000000 --- a/Castle.Core/Components.DictionaryAdapter/IDictionaryCopyStrategy.cs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System; - - public interface IDictionaryCopyStrategy - { - bool Copy(IDictionaryAdapter source, IDictionaryAdapter target, ref Func selector); - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/IDictionaryCreate.cs b/Castle.Core/Components.DictionaryAdapter/IDictionaryCreate.cs deleted file mode 100644 index 17544a8..0000000 --- a/Castle.Core/Components.DictionaryAdapter/IDictionaryCreate.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System; - using System.Collections; - - /// - /// Contract for creating additional Dictionary adapters. - /// - public interface IDictionaryCreate - { - T Create(); - - object Create(Type type); - - T Create(IDictionary dictionary); - - object Create(Type type, IDictionary dictionary); - - T Create(Action init); - - T Create(IDictionary dictionary, Action init); - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/IDictionaryCreateStrategy.cs b/Castle.Core/Components.DictionaryAdapter/IDictionaryCreateStrategy.cs deleted file mode 100644 index f84f187..0000000 --- a/Castle.Core/Components.DictionaryAdapter/IDictionaryCreateStrategy.cs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System; - using System.Collections; - - public interface IDictionaryCreateStrategy - { - object Create(IDictionaryAdapter adapter, Type type, IDictionary dictionary); - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/IDictionaryEdit.cs b/Castle.Core/Components.DictionaryAdapter/IDictionaryEdit.cs deleted file mode 100644 index fc0c1d9..0000000 --- a/Castle.Core/Components.DictionaryAdapter/IDictionaryEdit.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System; - using System.ComponentModel; - - /// - /// Contract for editing the Dictionary adapter. - /// - public interface IDictionaryEdit : IEditableObject, IRevertibleChangeTracking - { - bool CanEdit { get; } - - bool IsEditing { get; } - - bool SupportsMultiLevelEdit { get; set; } - - IDisposable SuppressEditingBlock(); - - void SuppressEditing(); - - void ResumeEditing(); - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/IDictionaryEqualityHashCodeStrategy.cs b/Castle.Core/Components.DictionaryAdapter/IDictionaryEqualityHashCodeStrategy.cs deleted file mode 100644 index 3937c0e..0000000 --- a/Castle.Core/Components.DictionaryAdapter/IDictionaryEqualityHashCodeStrategy.cs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - public interface IDictionaryEqualityHashCodeStrategy - { - bool Equals(IDictionaryAdapter adapter1, IDictionaryAdapter adapter2); - - bool GetHashCode(IDictionaryAdapter adapter, out int hashCode); - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/IDictionaryInitializer.cs b/Castle.Core/Components.DictionaryAdapter/IDictionaryInitializer.cs deleted file mode 100644 index 8bb0d21..0000000 --- a/Castle.Core/Components.DictionaryAdapter/IDictionaryInitializer.cs +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - /// - /// Contract for dictionary initialization. - /// - public interface IDictionaryInitializer : IDictionaryBehavior - { - /// - /// Performs any initialization of the - /// - /// The dictionary adapter. - /// The dictionary behaviors. - void Initialize(IDictionaryAdapter dictionaryAdapter, object[] behaviors); - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/IDictionaryKeyBuilder.cs b/Castle.Core/Components.DictionaryAdapter/IDictionaryKeyBuilder.cs deleted file mode 100644 index 2132739..0000000 --- a/Castle.Core/Components.DictionaryAdapter/IDictionaryKeyBuilder.cs +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System; - using System.Collections; - - /// - /// Defines the contract for building typed dictionary keys. - /// - public interface IDictionaryKeyBuilder : IDictionaryBehavior - { - /// - /// Builds the specified key. - /// - /// The dictionary adapter. - /// The current key. - /// The property. - /// The updated key - string GetKey(IDictionaryAdapter dictionaryAdapter, string key, PropertyDescriptor property); - } -} \ No newline at end of file diff --git a/Castle.Core/Components.DictionaryAdapter/IDictionaryMetaInitializer.cs b/Castle.Core/Components.DictionaryAdapter/IDictionaryMetaInitializer.cs deleted file mode 100644 index 479ec91..0000000 --- a/Castle.Core/Components.DictionaryAdapter/IDictionaryMetaInitializer.cs +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - /// - /// Contract for dictionary meta-data initialization. - /// - public interface IDictionaryMetaInitializer : IDictionaryBehavior - { - /// - /// Initializes the given object. - /// - /// The dictionary adapter factory. - /// The dictionary adapter meta. - /// - void Initialize(IDictionaryAdapterFactory factory, DictionaryAdapterMeta dictionaryMeta); - - /// - /// Determines whether the given behavior should be included in a new - /// object. - /// - /// A dictionary behavior or annotation. - /// True if the behavior should be included; otherwise, false. - /// - /// behaviors are always included, - /// regardless of the result of this method. - /// - /// - bool ShouldHaveBehavior(object behavior); - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/IDictionaryNotify.cs b/Castle.Core/Components.DictionaryAdapter/IDictionaryNotify.cs deleted file mode 100644 index 06a2ecf..0000000 --- a/Castle.Core/Components.DictionaryAdapter/IDictionaryNotify.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System; - using System.ComponentModel; - - /// - /// Contract for managing Dictionary adapter notifications. - /// - public interface IDictionaryNotify : - INotifyPropertyChanging, - INotifyPropertyChanged - { - bool CanNotify { get; } - - bool ShouldNotify { get; } - - IDisposable SuppressNotificationsBlock(); - - void SuppressNotifications(); - - void ResumeNotifications(); - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/IDictionaryPropertyGetter.cs b/Castle.Core/Components.DictionaryAdapter/IDictionaryPropertyGetter.cs deleted file mode 100644 index 1ab17b6..0000000 --- a/Castle.Core/Components.DictionaryAdapter/IDictionaryPropertyGetter.cs +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System.Collections; - - /// - /// Defines the contract for retrieving dictionary values. - /// - public interface IDictionaryPropertyGetter : IDictionaryBehavior - { - /// - /// Gets the effective dictionary value. - /// - /// The dictionary adapter. - /// The key. - /// The stored value. - /// The property. - /// true if return only existing. - /// The effective property value. - object GetPropertyValue(IDictionaryAdapter dictionaryAdapter, string key, - object storedValue, PropertyDescriptor property, bool ifExists); - } -} \ No newline at end of file diff --git a/Castle.Core/Components.DictionaryAdapter/IDictionaryPropertySetter.cs b/Castle.Core/Components.DictionaryAdapter/IDictionaryPropertySetter.cs deleted file mode 100644 index bbdbd94..0000000 --- a/Castle.Core/Components.DictionaryAdapter/IDictionaryPropertySetter.cs +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - - /// - /// Defines the contract for updating dictionary values. - /// - public interface IDictionaryPropertySetter : IDictionaryBehavior - { - /// - /// Sets the stored dictionary value. - /// - /// The dictionary adapter. - /// The key. - /// The stored value. - /// The property. - /// true if the property should be stored. - bool SetPropertyValue(IDictionaryAdapter dictionaryAdapter, string key, ref object value, - PropertyDescriptor property); - } -} \ No newline at end of file diff --git a/Castle.Core/Components.DictionaryAdapter/IDictionaryReferenceManager.cs b/Castle.Core/Components.DictionaryAdapter/IDictionaryReferenceManager.cs deleted file mode 100644 index ef37790..0000000 --- a/Castle.Core/Components.DictionaryAdapter/IDictionaryReferenceManager.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System; - - public interface IDictionaryReferenceManager - { - bool IsReferenceProperty(IDictionaryAdapter dictionaryAdapter, string propertyName); - - bool TryGetReference(object keyObject, out object inGraphObject); - void AddReference(object keyObject, object relatedObject, bool isInGraph); - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/IDictionaryValidate.cs b/Castle.Core/Components.DictionaryAdapter/IDictionaryValidate.cs deleted file mode 100644 index b6eabc0..0000000 --- a/Castle.Core/Components.DictionaryAdapter/IDictionaryValidate.cs +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System.Collections.Generic; - using System.ComponentModel; - - /// - /// Contract for validating Dictionary adapter. - /// - public interface IDictionaryValidate : IDataErrorInfo - { - bool CanValidate { get; set; } - - bool IsValid { get; } - - DictionaryValidateGroup ValidateGroups(params object[] groups); - - IEnumerable Validators { get; } - - void AddValidator(IDictionaryValidator validator); - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/IDictionaryValidator.cs b/Castle.Core/Components.DictionaryAdapter/IDictionaryValidator.cs deleted file mode 100644 index f8dfa2e..0000000 --- a/Castle.Core/Components.DictionaryAdapter/IDictionaryValidator.cs +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - /// - /// Contract for dictionary validation. - /// - public interface IDictionaryValidator - { - /// - /// Determines if is valid. - /// - /// The dictionary adapter. - /// true if valid. - bool IsValid(IDictionaryAdapter dictionaryAdapter); - - /// - /// Validates the . - /// - /// The dictionary adapter. - /// The error summary information. - string Validate(IDictionaryAdapter dictionaryAdapter); - - /// - /// Validates the for a property. - /// - /// The dictionary adapter. - /// The property to validate. - /// The property summary information. - string Validate(IDictionaryAdapter dictionaryAdapter, PropertyDescriptor property); - - /// - /// Invalidates any results cached by the validator. - /// - /// The dictionary adapter. - void Invalidate(IDictionaryAdapter dictionaryAdapter); - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/IPropertyDescriptorInitializer.cs b/Castle.Core/Components.DictionaryAdapter/IPropertyDescriptorInitializer.cs deleted file mode 100644 index 1175673..0000000 --- a/Castle.Core/Components.DictionaryAdapter/IPropertyDescriptorInitializer.cs +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - /// - /// Contract for property descriptor initialization. - /// - public interface IPropertyDescriptorInitializer : IDictionaryBehavior - { - /// - /// Performs any initialization of the - /// - /// The property descriptor. - /// The property behaviors. - void Initialize(PropertyDescriptor propertyDescriptor, object[] behaviors); - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/MemberwiseEqualityHashCodeStrategy.cs b/Castle.Core/Components.DictionaryAdapter/MemberwiseEqualityHashCodeStrategy.cs deleted file mode 100644 index ebfe611..0000000 --- a/Castle.Core/Components.DictionaryAdapter/MemberwiseEqualityHashCodeStrategy.cs +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System; - using System.Collections; - using System.Collections.Generic; - - public class MemberwiseEqualityHashCodeStrategy : DictionaryBehaviorAttribute, - IDictionaryEqualityHashCodeStrategy, IDictionaryInitializer, IEqualityComparer - { - class HashCodeVisitor : AbstractDictionaryAdapterVisitor - { - private int hashCode; - - public int CalculateHashCode(IDictionaryAdapter dictionaryAdapter) - { - if (dictionaryAdapter == null) - return 0; - - hashCode = 27; - return VisitDictionaryAdapter(dictionaryAdapter, null) ? hashCode : 0; - } - - protected override void VisitProperty(IDictionaryAdapter dictionaryAdapter, PropertyDescriptor property, object state) - { - var value = dictionaryAdapter.GetProperty(property.PropertyName, true); - CollectHashCode(property, GetValueHashCode(value)); - } - - protected override void VisitInterface(IDictionaryAdapter dictionaryAdapter, PropertyDescriptor property, object state) - { - var nested = (IDictionaryAdapter)dictionaryAdapter.GetProperty(property.PropertyName, true); - CollectHashCode(property, GetNestedHashCode(nested)); - } - - protected override void VisitCollection(IDictionaryAdapter dictionaryAdapter, PropertyDescriptor property, Type collectionItemType, object state) - { - var collection = (IEnumerable)dictionaryAdapter.GetProperty(property.PropertyName, true); - CollectHashCode(property, GetCollectionHashcode(collection)); - } - - private int GetValueHashCode(object value) - { - if (value == null) - { - return 0; - } - - if (value is IDictionaryAdapter) - { - return GetNestedHashCode((IDictionaryAdapter)value); - } - - if ((value is IEnumerable) && (value is string) == false) - { - return GetCollectionHashcode((IEnumerable)value); - } - - return value.GetHashCode(); - } - - private int GetNestedHashCode(IDictionaryAdapter nested) - { - var currentHashCode = hashCode; - var nestedHashCode = CalculateHashCode(nested); - hashCode = currentHashCode; - return nestedHashCode; - } - - private int GetCollectionHashcode(IEnumerable collection) - { - if (collection == null) - { - return 0; - } - - var collectionHashCode = 0; - - foreach (var value in collection) - { - var valueHashCode = GetValueHashCode(value); - unchecked - { - collectionHashCode = (13 * collectionHashCode) + valueHashCode; - } - } - - return collectionHashCode; - } - - private void CollectHashCode(PropertyDescriptor property, int valueHashCode) - { - unchecked - { - hashCode = (13 * hashCode) + property.PropertyName.GetHashCode(); - hashCode = (13 * hashCode) + valueHashCode; - } - } - } - - public bool Equals(IDictionaryAdapter adapter1, IDictionaryAdapter adapter2) - { - if (ReferenceEquals(adapter1, adapter2)) - { - return true; - } - - if ((adapter1 == null) ^ (adapter2 == null)) - { - return false; - } - - if (adapter1.Meta.Type != adapter2.Meta.Type) - { - return false; - } - - return GetHashCode(adapter1) == GetHashCode(adapter2); - } - - public int GetHashCode(IDictionaryAdapter adapter) - { - int hashCode; - GetHashCode(adapter, out hashCode); - return hashCode; - } - - public bool GetHashCode(IDictionaryAdapter adapter, out int hashCode) - { - hashCode = new HashCodeVisitor().CalculateHashCode(adapter); - return true; - } - - void IDictionaryInitializer.Initialize(IDictionaryAdapter dictionaryAdapter, object[] behaviors) - { - dictionaryAdapter.This.EqualityHashCodeStrategy = this; - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/NameValueCollectionAdapter.cs b/Castle.Core/Components.DictionaryAdapter/NameValueCollectionAdapter.cs deleted file mode 100644 index f22a2df..0000000 --- a/Castle.Core/Components.DictionaryAdapter/NameValueCollectionAdapter.cs +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System; - using System.Collections.Specialized; - using System.Linq; - - /// - /// - /// - public class NameValueCollectionAdapter : AbstractDictionaryAdapter - { - private readonly NameValueCollection nameValues; - - /// - /// Initializes a new instance of the class. - /// - /// The name values. - public NameValueCollectionAdapter(NameValueCollection nameValues) - { - this.nameValues = nameValues; - } - - /// - /// Gets a value indicating whether the object is read-only. - /// - /// true if the object is read-only; otherwise, false. - public override bool IsReadOnly - { - get { return false; } - } - - /// - /// Determines whether the object contains an element with the specified key. - /// - /// The key to locate in the object. - /// - /// true if the contains an element with the key; otherwise, false. - /// - /// key is null. - public override bool Contains(object key) - { - if (key == null) - { - throw new ArgumentNullException(nameof(key)); - } - - //Getting a value out is O(1), so in the case that the collection contains a non-null value for this key - //we can skip the O(n) key lookup. - if (this[key] != null) - { - return true; - } - - return nameValues.AllKeys.Contains(key.ToString(), StringComparer.OrdinalIgnoreCase); - } - - /// - /// Gets or sets the with the specified key. - /// - public override object this[object key] - { - get { return nameValues[key.ToString()]; } - set - { - string val = (value != null) ? value.ToString() : null; - nameValues[key.ToString()] = val; - } - } - - /// - /// Adapts the specified name values. - /// - /// The name values. - public static NameValueCollectionAdapter Adapt(NameValueCollection nameValues) - { - return new NameValueCollectionAdapter(nameValues); - } - } -} \ No newline at end of file diff --git a/Castle.Core/Components.DictionaryAdapter/PropertyChangedEventArgsEx.cs b/Castle.Core/Components.DictionaryAdapter/PropertyChangedEventArgsEx.cs deleted file mode 100644 index 165cd58..0000000 --- a/Castle.Core/Components.DictionaryAdapter/PropertyChangedEventArgsEx.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System.ComponentModel; - - public class PropertyChangedEventArgsEx : PropertyChangedEventArgs - { - private readonly object oldValue; - private readonly object newValue; - - public PropertyChangedEventArgsEx(string propertyName, object oldValue, object newValue) - : base(propertyName) - { - this.oldValue = oldValue; - this.newValue = newValue; - } - - public object OldValue - { - get { return oldValue; } - } - - public object NewValue - { - get { return newValue; } - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/PropertyChangingEventArgsEx.cs b/Castle.Core/Components.DictionaryAdapter/PropertyChangingEventArgsEx.cs deleted file mode 100644 index 617e7e6..0000000 --- a/Castle.Core/Components.DictionaryAdapter/PropertyChangingEventArgsEx.cs +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System.ComponentModel; - - public class PropertyChangingEventArgsEx : PropertyChangingEventArgs - { - private readonly object oldValue; - private readonly object newValue; - private bool cancel; - - public PropertyChangingEventArgsEx(string propertyName, object oldValue, object newValue) - : base(propertyName) - { - this.oldValue = oldValue; - this.newValue = newValue; - } - - public object OldValue - { - get { return oldValue; } - } - - public object NewValue - { - get { return newValue; } - } - - public bool Cancel - { - get { return cancel; } - set { cancel = value; } - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/PropertyDescriptor.cs b/Castle.Core/Components.DictionaryAdapter/PropertyDescriptor.cs deleted file mode 100644 index 33055ce..0000000 --- a/Castle.Core/Components.DictionaryAdapter/PropertyDescriptor.cs +++ /dev/null @@ -1,471 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System; - using System.Collections; - using System.Collections.Generic; - using System.ComponentModel; - using System.Diagnostics; - using System.Linq; - using System.Reflection; - using Castle.Core.Internal; - - /// - /// Describes a dictionary property. - /// - [DebuggerDisplay("{Property.DeclaringType.FullName,nq}.{PropertyName,nq}")] - public class PropertyDescriptor : IDictionaryKeyBuilder, IDictionaryPropertyGetter, IDictionaryPropertySetter - { - private IDictionary state; - private Dictionary extendedProperties; - protected List dictionaryBehaviors; - - private static readonly object[] NoAnnotations = new object[0]; - - /// - /// Initializes an empty class. - /// - public PropertyDescriptor() - { - Annotations = NoAnnotations; - } - - /// - /// Initializes a new instance of the class. - /// - /// The property. - /// The annotations. - public PropertyDescriptor(PropertyInfo property, object[] annotations) : this() - { - Property = property; - Annotations = annotations ?? NoAnnotations; - IsDynamicProperty = typeof(IDynamicValue).IsAssignableFrom(property.PropertyType); - ObtainTypeConverter(); - } - - /// - /// Initializes a new instance class. - /// - public PropertyDescriptor(object[] annotations) - { - Annotations = annotations ?? NoAnnotations; - } - - /// - /// Copies an existing instance of the class. - /// - public PropertyDescriptor(PropertyDescriptor source, bool copyBehaviors) - { - Property = source.Property; - Annotations = source.Annotations; - IsDynamicProperty = source.IsDynamicProperty; - TypeConverter = source.TypeConverter; - SuppressNotifications = source.SuppressNotifications; - state = source.state; - IfExists = source.IfExists; - Fetch = source.Fetch; - - if (source.extendedProperties != null) - extendedProperties = new Dictionary(source.extendedProperties); - - if (copyBehaviors && source.dictionaryBehaviors != null) - dictionaryBehaviors = new List(source.dictionaryBehaviors); - } - - /// - /// - /// - public int ExecutionOrder - { - get { return 0; } - } - - /// - /// Gets the property name. - /// - public string PropertyName - { - get { return (Property != null) ? Property.Name : null; } - } - - /// - /// Gets the property type. - /// - public Type PropertyType - { - get { return (Property != null) ? Property.PropertyType : null; } - } - - /// - /// Gets the property. - /// - /// The property. - public PropertyInfo Property { get; private set; } - - /// - /// Returns true if the property is dynamic. - /// - public bool IsDynamicProperty { get; private set; } - - /// - /// Gets additional state. - /// - public IDictionary State - { - get { return state ?? (state = new Dictionary()); } - } - - /// - /// Determines if property should be fetched. - /// - public bool Fetch { get; set; } - - /// - /// Determines if property must exist first. - /// - public bool IfExists { get; set; } - - /// - /// Determines if notifications should occur. - /// - public bool SuppressNotifications { get; set; } - - /// - /// Gets the property behaviors. - /// - public object[] Annotations { get; private set; } - - /// - /// Gets the type converter. - /// - /// The type converter. - public TypeConverter TypeConverter { get; private set; } - - /// - /// Gets the extended properties. - /// - public IDictionary ExtendedProperties - { - get { return extendedProperties ?? (extendedProperties = new Dictionary()); } - } - - /// - /// Gets the setter. - /// - /// The setter. - public IEnumerable Behaviors - { - get - { - return dictionaryBehaviors ?? Enumerable.Empty(); - } - } - - internal List BehaviorsInternal - { - get { return dictionaryBehaviors; } - } - - /// - /// Gets the key builders. - /// - /// The key builders. - public IEnumerable KeyBuilders - { - get - { - return (dictionaryBehaviors != null) - ? dictionaryBehaviors.OfType() - : Enumerable.Empty(); - } - } - - /// - /// Gets the setter. - /// - /// The setter. - public IEnumerable Setters - { - get - { - return (dictionaryBehaviors != null) - ? dictionaryBehaviors.OfType() - : Enumerable.Empty(); - } - } - - /// - /// Gets the getter. - /// - /// The getter. - public IEnumerable Getters - { - get - { - return (dictionaryBehaviors != null) - ? dictionaryBehaviors.OfType() - : Enumerable.Empty(); - } - } - - /// - /// Gets the initializers. - /// - /// The initializers. - public IEnumerable Initializers - { - get - { - return (dictionaryBehaviors != null) - ? dictionaryBehaviors.OfType() - : Enumerable.Empty(); - } - } - - /// - /// Gets the meta-data initializers. - /// - /// The meta-data initializers. - public IEnumerable MetaInitializers - { - get - { - return (dictionaryBehaviors != null) - ? dictionaryBehaviors.OfType() - : Enumerable.Empty(); - } - } - - /// - /// Gets the key. - /// - /// The dictionary adapter. - /// The key. - /// The descriptor. - public string GetKey(IDictionaryAdapter dictionaryAdapter, string key, PropertyDescriptor descriptor) - { - var behaviors = dictionaryBehaviors; - if (behaviors != null) - { - var count = behaviors.Count; - for (int i = 0; i < count; i++) - { - var builder = behaviors[i] as IDictionaryKeyBuilder; - if (builder != null) - key = builder.GetKey(dictionaryAdapter, key, this); - } - } - return key; - } - - /// - /// Gets the property value. - /// - /// The dictionary adapter. - /// The key. - /// The stored value. - /// The descriptor. - /// true if return only existing. - public object GetPropertyValue(IDictionaryAdapter dictionaryAdapter, string key, object storedValue, PropertyDescriptor descriptor, bool ifExists) - { - key = GetKey(dictionaryAdapter, key, descriptor); - storedValue = storedValue ?? dictionaryAdapter.ReadProperty(key); - - var behaviors = dictionaryBehaviors; - if (behaviors != null) - { - var count = behaviors.Count; - for (int i = 0; i < count; i++) - { - var getter = behaviors[i] as IDictionaryPropertyGetter; - if (getter != null) - storedValue = getter.GetPropertyValue(dictionaryAdapter, key, storedValue, this, IfExists || ifExists); - } - } - - return storedValue; - } - - /// - /// Sets the property value. - /// - /// The dictionary adapter. - /// The key. - /// The value. - /// The descriptor. - public bool SetPropertyValue(IDictionaryAdapter dictionaryAdapter, string key, ref object value, PropertyDescriptor descriptor) - { - key = GetKey(dictionaryAdapter, key, descriptor); - - var behaviors = dictionaryBehaviors; - if (behaviors != null) - { - var count = behaviors.Count; - for (int i = 0; i < count; i++) - { - var setter = behaviors[i] as IDictionaryPropertySetter; - if (setter != null) - if (setter.SetPropertyValue(dictionaryAdapter, key, ref value, this) == false) - return false; - } - } - - dictionaryAdapter.StoreProperty(this, key, value); - return true; - } - - /// - /// Adds a single behavior. - /// - /// The behavior. - public PropertyDescriptor AddBehavior(IDictionaryBehavior behavior) - { - if (behavior == null) - return this; - - var builder = behavior as IDictionaryBehaviorBuilder; - if (builder == null) - MergeBehavior(ref dictionaryBehaviors, behavior); - else - foreach (var item in builder.BuildBehaviors()) - AddBehavior(item as IDictionaryBehavior); - - return this; - } - - public static void MergeBehavior(ref List dictionaryBehaviors, T behavior) - where T : class, IDictionaryBehavior - { - var behaviors = dictionaryBehaviors; - if (behaviors == null) - { - behaviors = new List(); - behaviors.Add(behavior); - dictionaryBehaviors = behaviors; - return; - } - - // The following is ugly but supposedly optimized - - // Locals using ldloc.# - var index = 0; - int candidatePriority; - var targetOrder = behavior.ExecutionOrder; - // Locals using ldloc.s - var count = behaviors.Count; - IDictionaryBehavior candidateBehavior; - - // Skip while order < behavior.ExecutionOrder - for (;;) - { - candidateBehavior = behaviors[index]; - candidatePriority = candidateBehavior.ExecutionOrder; - - if (candidatePriority >= targetOrder) - break; - - if (++index == count) - { - behaviors.Add(behavior); - return; - } - } - - // Skip while order == behavior.ExecutionOrder - for (;;) - { - if (candidatePriority != targetOrder) - break; - - if (candidateBehavior == behavior) - return; // Duplicate - - if (++index == count) - { - behaviors.Add(behavior); - return; - } - - candidateBehavior = behaviors[index]; - candidatePriority = candidateBehavior.ExecutionOrder; - } - - // Insert at found index - behaviors.Insert(index, behavior); - return; - } - - /// - /// Adds the behaviors. - /// - /// The behaviors. - public PropertyDescriptor AddBehaviors(params IDictionaryBehavior[] behaviors) - { - // DO NOT REFACTOR. Compiler will emit optimized iterator here. - foreach (var behavior in behaviors) - AddBehavior(behavior); - return this; - } - - /// - /// Adds the behaviors. - /// - /// The behaviors. - public PropertyDescriptor AddBehaviors(IEnumerable behaviors) - { - if (behaviors != null) - foreach (var behavior in behaviors) - AddBehavior(behavior); - return this; - } - - /// - /// Copies the behaviors to the other - /// - public PropertyDescriptor CopyBehaviors(PropertyDescriptor other) - { - var behaviors = dictionaryBehaviors; - if (behaviors != null) - { - var count = behaviors.Count; - for (var i = 0; i < count; i++) - { - var behavior = behaviors[i].Copy(); - if (behavior != null) - other.AddBehavior(behavior); - } - } - return this; - } - - /// - /// Copies the - /// - public IDictionaryBehavior Copy() - { - return new PropertyDescriptor(this, true); - } - - private void ObtainTypeConverter() - { - var converterType = AttributesUtil.GetTypeConverter(Property); - - TypeConverter = (converterType != null) - ? (TypeConverter) Activator.CreateInstance(converterType) - : TypeDescriptor.GetConverter(PropertyType); - } - } -} \ No newline at end of file diff --git a/Castle.Core/Components.DictionaryAdapter/Util/BindingList.cs b/Castle.Core/Components.DictionaryAdapter/Util/BindingList.cs deleted file mode 100644 index d8b9aae..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Util/BindingList.cs +++ /dev/null @@ -1,325 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System; - using System.Collections; - using System.Collections.Generic; - using SCM = System.ComponentModel; - - /// - /// Provides a generic collection that supports data binding. - /// - /// - /// This class wraps the CLR - /// in order to implement the Castle-specific . - /// - /// The type of elements in the list. - public class BindingList : IBindingList, IList - { - private readonly SCM.BindingList list; - - /// - /// Initializes a new instance of the class - /// using default values. - /// - public BindingList() - { - this.list = new SCM.BindingList(); - } - - /// - /// Initializes a new instance of the class - /// with the specified list. - /// - /// - /// An of items - /// to be contained in the . - /// - public BindingList(IList list) - { - this.list = new SCM.BindingList(list); - } - - /// - /// Initializes a new instance of the class - /// wrapping the specified instance. - /// - /// - /// A - /// to be wrapped by the . - /// - public BindingList(SCM.BindingList list) - { - if (list == null) - throw new ArgumentNullException(nameof(list)); - - this.list = list; - } - - public SCM.BindingList InnerList - { - get { return list; } - } - - public SCM.IBindingList AsBindingList - { - get { return list; } - } - - public int Count - { - get { return list.Count; } - } - - bool ICollection.IsReadOnly - { - get { return ((ICollection) list).IsReadOnly; } - } - - bool IList.IsReadOnly - { - get { return ((IList) list).IsReadOnly; } - } - - bool IList.IsFixedSize - { - get { return ((IList) list).IsFixedSize; } - } - - bool ICollection.IsSynchronized - { - get { return ((ICollection) list).IsSynchronized; } - } - - object ICollection.SyncRoot - { - get { return ((ICollection) list).SyncRoot; } - } - - public bool AllowNew - { - get { return list.AllowNew; } - set { list.AllowNew = value; } - } - - public bool AllowEdit - { - get { return list.AllowEdit; } - set { list.AllowEdit = value; } - } - - public bool AllowRemove - { - get { return list.AllowRemove; } - set { list.AllowRemove = value; } - } - - public bool RaiseListChangedEvents - { - get { return list.RaiseListChangedEvents; } - set { list.RaiseListChangedEvents = value; } - } - - bool SCM.IRaiseItemChangedEvents.RaisesItemChangedEvents - { - get { return ((SCM.IRaiseItemChangedEvents) list).RaisesItemChangedEvents; } - } - - bool IBindingList.SupportsChangeNotification - { - get { return AsBindingList.SupportsChangeNotification; } - } - - bool IBindingList.SupportsSearching - { - get { return AsBindingList.SupportsSearching; } - } - - bool IBindingList.SupportsSorting - { - get { return AsBindingList.SupportsSorting; } - } - - bool IBindingList.IsSorted - { - get { return AsBindingList.IsSorted; } - } - - SCM.PropertyDescriptor IBindingList.SortProperty - { - get { return AsBindingList.SortProperty; } - } - - SCM.ListSortDirection IBindingList.SortDirection - { - get { return AsBindingList.SortDirection; } - } - - int IBindingList.Find(SCM.PropertyDescriptor property, object key) - { - return AsBindingList.Find(property, key); - } - - void IBindingList.AddIndex(SCM.PropertyDescriptor property) - { - AsBindingList.AddIndex(property); - } - - void IBindingList.RemoveIndex(SCM.PropertyDescriptor property) - { - AsBindingList.RemoveIndex(property); - } - - void IBindingList.ApplySort(SCM.PropertyDescriptor property, SCM.ListSortDirection direction) - { - AsBindingList.ApplySort(property, direction); - } - - void IBindingList.RemoveSort() - { - AsBindingList.RemoveSort(); - } - - public event SCM.AddingNewEventHandler AddingNew - { - add { list.AddingNew += value; } - remove { list.AddingNew -= value; } - } - - public event SCM.ListChangedEventHandler ListChanged - { - add { list.ListChanged += value; } - remove { list.ListChanged -= value; } - } - - public T this[int index] - { - get { return list[index]; } - set { list[index] = value; } - } - - object IList.this[int index] - { - get { return ((IList) list)[index]; } - set { ((IList) list)[index] = value; } - } - - public bool Contains(T item) - { - return list.Contains(item); - } - - bool IList.Contains(object value) - { - return ((IList) list).Contains(value); - } - - public int IndexOf(T item) - { - return list.IndexOf(item); - } - - int IList.IndexOf(object value) - { - return ((IList) list).IndexOf(value); - } - - public void CopyTo(T[] array, int index) - { - list.CopyTo(array, index); - } - - void ICollection.CopyTo(Array array, int index) - { - ((IList) list).CopyTo(array, index); - } - - public IEnumerator GetEnumerator() - { - return list.GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return list.GetEnumerator(); - } - - public T AddNew() - { - return list.AddNew(); - } - - public void CancelNew(int index) - { - list.CancelNew(index); - } - - public void EndNew(int index) - { - list.EndNew(index); - } - - public void Add(T item) - { - list.Add(item); - } - - int IList.Add(object item) - { - return ((IList) list).Add(item); - } - - public void Insert(int index, T item) - { - list.Insert(index, item); - } - - void IList.Insert(int index, object item) - { - ((IList) list).Insert(index, item); - } - - public void RemoveAt(int index) - { - list.RemoveAt(index); - } - - public bool Remove(T item) - { - return list.Remove(item); - } - - void IList.Remove(object item) - { - ((IList) list).Remove(item); - } - - public void Clear() - { - list.Clear(); - } - - public void ResetBindings() - { - list.ResetBindings(); - } - - public void ResetItem(int index) - { - list.ResetItem(index); - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Util/BindingListInitializer.cs b/Castle.Core/Components.DictionaryAdapter/Util/BindingListInitializer.cs deleted file mode 100644 index aba8754..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Util/BindingListInitializer.cs +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System; - using System.ComponentModel; - - public class BindingListInitializer : IValueInitializer - { - private readonly Func addNew; - private readonly Func addAt; - private readonly Func setAt; - private readonly Action removeAt; - private readonly Action reset; - - private bool addingNew; - - public BindingListInitializer(Func addAt, Func addNew, Func setAt, Action removeAt, Action reset) - { - this.addAt = addAt; - this.addNew = addNew; - this.setAt = setAt; - this.removeAt = removeAt; - this.reset = reset; - } - - public void Initialize(IDictionaryAdapter dictionaryAdapter, object value) - { - var bindingList = (System.ComponentModel.BindingList)value; - if (addNew != null) - { - bindingList.AddingNew += (sender, args) => - { - args.NewObject = addNew(); - addingNew = true; - }; - } - bindingList.ListChanged += (sender, args) => - { - switch (args.ListChangedType) - { - case ListChangedType.ItemAdded: - if (addingNew == false && addAt != null) - { - var item = addAt(args.NewIndex, bindingList[args.NewIndex]); - if (item != null) - { - using (new SuppressListChangedEvents(bindingList)) - { - bindingList[args.NewIndex] = (T)item; - } - } - } - addingNew = false; - break; - - case ListChangedType.ItemChanged: - if (setAt != null) - { - var item = setAt(args.NewIndex, bindingList[args.NewIndex]); - if (item != null) - { - using (new SuppressListChangedEvents(bindingList)) - { - bindingList[args.NewIndex] = (T)item; - } - } - } - break; - - case ListChangedType.ItemDeleted: - if (removeAt != null) - removeAt(args.NewIndex); - break; - - case ListChangedType.Reset: - if (reset != null) - reset(); - break; - } - }; - } - - class SuppressListChangedEvents : IDisposable - { - private readonly bool raiseEvents; - private readonly System.ComponentModel.BindingList bindingList; - - public SuppressListChangedEvents(System.ComponentModel.BindingList bindingList) - { - this.bindingList = bindingList; - raiseEvents = this.bindingList.RaiseListChangedEvents; - this.bindingList.RaiseListChangedEvents = false; - } - - public void Dispose() - { - bindingList.RaiseListChangedEvents = raiseEvents; - } - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Util/DynamicValue.cs b/Castle.Core/Components.DictionaryAdapter/Util/DynamicValue.cs deleted file mode 100644 index 9a20b4f..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Util/DynamicValue.cs +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - public abstract class DynamicValue : IDynamicValue - { - object IDynamicValue.GetValue() - { - return Value; - } - - public abstract T Value { get; } - - public override string ToString() - { - var value = Value; - if (value != null) - { - return value.ToString(); - } - return base.ToString(); - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Util/DynamicValueDelegate.cs b/Castle.Core/Components.DictionaryAdapter/Util/DynamicValueDelegate.cs deleted file mode 100644 index 9135b76..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Util/DynamicValueDelegate.cs +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System; - - public class DynamicValueDelegate : DynamicValue - { - private readonly Func dynamicDelegate; - - public DynamicValueDelegate(Func dynamicDelegate) - { - this.dynamicDelegate = dynamicDelegate; - } - - public override T Value - { - get { return dynamicDelegate(); } - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Util/EditableBindingList.cs b/Castle.Core/Components.DictionaryAdapter/Util/EditableBindingList.cs deleted file mode 100644 index 5155361..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Util/EditableBindingList.cs +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System.Collections.Generic; - using System.ComponentModel; - - public class EditableBindingList : System.ComponentModel.BindingList, IList, IEditableObject, IRevertibleChangeTracking - { - private bool isEditing; - private List snapshot; - - public EditableBindingList() - { - } - - public EditableBindingList(IList initial) - : base(initial) - { - } - - public bool IsChanged - { - get - { - if (snapshot == null || snapshot.Count != Count) - return false; - - var items = GetEnumerator(); - var snapshotItems = snapshot.GetEnumerator(); - - while (items.MoveNext() && snapshotItems.MoveNext()) - { - if (ReferenceEquals(items.Current, snapshotItems.Current) == false) - return false; - - var tracked = items.Current as IChangeTracking; - if (tracked != null && tracked.IsChanged) - return true; - } - - return false; - } - } - - public void BeginEdit() - { - if (isEditing == false) - { - snapshot = new List(this); - isEditing = true; - } - } - - public void EndEdit() - { - isEditing = false; - snapshot = null; - } - - public void CancelEdit() - { - if (isEditing) - { - Clear(); - foreach (var item in snapshot) Add(item); - snapshot = null; - isEditing = false; - } - } - - public void AcceptChanges() - { - BeginEdit(); - } - - public void RejectChanges() - { - CancelEdit(); - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Util/EditableList.cs b/Castle.Core/Components.DictionaryAdapter/Util/EditableList.cs deleted file mode 100644 index 07f5f10..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Util/EditableList.cs +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System.Collections; - using System.Collections.Generic; - using System.ComponentModel; - - public class EditableList : List, IEditableObject, IRevertibleChangeTracking - { - private bool isEditing; - private List snapshot; - - public EditableList() - { - } - - public EditableList(IEnumerable collection) - : base(collection) - { - } - - public void BeginEdit() - { - if (isEditing == false) - { - snapshot = new List(this); - isEditing = true; - } - } - - public bool IsChanged - { - get - { - if (snapshot == null || snapshot.Count != Count) - return false; - - var items = GetEnumerator(); - var snapshotItems = snapshot.GetEnumerator(); - - while (items.MoveNext() && snapshotItems.MoveNext()) - { - if (ReferenceEquals(items.Current, snapshotItems.Current) == false) - return false; - - var tracked = items.Current as IChangeTracking; - if (tracked != null && tracked.IsChanged) - return true; - } - - return false; - } - } - - public void EndEdit() - { - isEditing = false; - snapshot = null; - } - - public void CancelEdit() - { - if (isEditing) - { - Clear(); - AddRange(snapshot); - snapshot = null; - isEditing = false; - } - } - - public void AcceptChanges() - { - BeginEdit(); - } - - public void RejectChanges() - { - CancelEdit(); - } - } - - public class EditableList : EditableList, IList - { - public EditableList() - { - } - - public EditableList(IEnumerable collection) - : base(collection) - { - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Util/IBindingList.cs b/Castle.Core/Components.DictionaryAdapter/Util/IBindingList.cs deleted file mode 100644 index 25bb96a..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Util/IBindingList.cs +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System.Collections.Generic; - using System.ComponentModel; - using SysPropertyDescriptor = System.ComponentModel.PropertyDescriptor; - - public interface IBindingList : IList, IBindingListSource, ICancelAddNew, IRaiseItemChangedEvents - { - bool AllowNew { get; } - bool AllowEdit { get; } - bool AllowRemove { get; } - bool SupportsChangeNotification { get; } - bool SupportsSearching { get; } - bool SupportsSorting { get; } - bool IsSorted { get; } - SysPropertyDescriptor SortProperty { get; } - ListSortDirection SortDirection { get; } - - event ListChangedEventHandler ListChanged; - - T AddNew (); - int Find (SysPropertyDescriptor property, object key); - void AddIndex (SysPropertyDescriptor property); - void RemoveIndex(SysPropertyDescriptor property); - void ApplySort (SysPropertyDescriptor property, ListSortDirection direction); - void RemoveSort (); - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Util/IBindingListSource.cs b/Castle.Core/Components.DictionaryAdapter/Util/IBindingListSource.cs deleted file mode 100644 index 77f42d9..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Util/IBindingListSource.cs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System.ComponentModel; - - public interface IBindingListSource - { - IBindingList AsBindingList { get; } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Util/ICollectionAdapter.cs b/Castle.Core/Components.DictionaryAdapter/Util/ICollectionAdapter.cs deleted file mode 100644 index d8cc6de..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Util/ICollectionAdapter.cs +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System.ComponentModel; - using System.Collections.Generic; - - public interface ICollectionAdapter - { - // Configuration - void Initialize(ICollectionAdapterObserver advisor); - IEqualityComparer Comparer { get; } - - // Collection Access - int Count { get; } - T this [int index] { get; set; } - T AddNew (); - bool Add (T value); - bool Insert (int index, T value); - void Remove (int index); - void Clear (); - void ClearReferences(); // A bit of a hack. Make this nicer in a future version. - - // Snapshot Support - bool HasSnapshot { get; } - int SnapshotCount { get; } - T GetCurrentItem (int index); - T GetSnapshotItem (int index); - void SaveSnapshot (); - void LoadSnapshot (); - void DropSnapshot (); - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Util/ICollectionAdapterObserver.cs b/Castle.Core/Components.DictionaryAdapter/Util/ICollectionAdapterObserver.cs deleted file mode 100644 index a228cdd..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Util/ICollectionAdapterObserver.cs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - public interface ICollectionAdapterObserver - { - bool OnInserting ( T newValue); - bool OnReplacing (T oldValue, T newValue); - void OnRemoving (T oldValue ); - - void OnInserted ( T newValue, int index); - void OnReplaced (T oldValue, T newValue, int index); - void OnRemoved (T oldValue, int index); - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Util/ICollectionProjection.cs b/Castle.Core/Components.DictionaryAdapter/Util/ICollectionProjection.cs deleted file mode 100644 index b33fd75..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Util/ICollectionProjection.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System.Collections; - - public interface ICollectionProjection : ICollection - { - void Replace(IEnumerable source); - void Clear(); - void ClearReferences(); - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Util/ICondition.cs b/Castle.Core/Components.DictionaryAdapter/Util/ICondition.cs deleted file mode 100644 index f2faf0c..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Util/ICondition.cs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - /// - /// Contract for value matching. - /// - public interface ICondition - { - bool SatisfiedBy(object value); - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Util/IDynamicValue.cs b/Castle.Core/Components.DictionaryAdapter/Util/IDynamicValue.cs deleted file mode 100644 index a32ffc6..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Util/IDynamicValue.cs +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - /// - /// Contract for dynamic value resolution. - /// - public interface IDynamicValue - { - object GetValue(); - } - - /// - /// Contract for typed dynamic value resolution. - /// - /// - public interface IDynamicValue : IDynamicValue - { - T Value { get; } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Util/IValueInitializer.cs b/Castle.Core/Components.DictionaryAdapter/Util/IValueInitializer.cs deleted file mode 100644 index c135856..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Util/IValueInitializer.cs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - public interface IValueInitializer - { - void Initialize(IDictionaryAdapter dictionaryAdapter, object value); - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Util/IVirtual.cs b/Castle.Core/Components.DictionaryAdapter/Util/IVirtual.cs deleted file mode 100644 index 55f2628..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Util/IVirtual.cs +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System; - - public interface IVirtual - { - bool IsReal { get; } - - void Realize(); - - event EventHandler Realized; - } - - public interface IVirtual : IVirtual - { - new T Realize(); - - void AddSite(IVirtualSite site); - - void RemoveSite(IVirtualSite site); - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Util/IVirtualSite.cs b/Castle.Core/Components.DictionaryAdapter/Util/IVirtualSite.cs deleted file mode 100644 index 32c66d2..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Util/IVirtualSite.cs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - public interface IVirtualSite - { - void OnRealizing(T node); - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Util/IVirtualTarget.cs b/Castle.Core/Components.DictionaryAdapter/Util/IVirtualTarget.cs deleted file mode 100644 index 257b627..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Util/IVirtualTarget.cs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - public interface IVirtualTarget - { - void OnRealizing(TNode node, TMember member); - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Util/ListProjection.cs b/Castle.Core/Components.DictionaryAdapter/Util/ListProjection.cs deleted file mode 100644 index 6a6f25f..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Util/ListProjection.cs +++ /dev/null @@ -1,603 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System; - using System.Collections; - using System.Collections.Generic; - using System.ComponentModel; - using System.Diagnostics; - using System.Reflection; - - using SysPropertyDescriptor = System.ComponentModel.PropertyDescriptor; - - [DebuggerDisplay("Count = {Count}, Adapter = {Adapter}")] - [DebuggerTypeProxy(typeof(ListProjectionDebugView<>))] - public class ListProjection : - IBindingList, // Castle - IBindingList, // System - IEditableObject, - IRevertibleChangeTracking, - ICollectionProjection, - ICollectionAdapterObserver - { - private readonly ICollectionAdapter adapter; - private int addNewIndex = NoIndex; - private int addedIndex = NoIndex; - private int suspendLevel = 0; - private int changedIndex = NoIndex; - private PropertyChangedEventHandler propertyHandler; - private static PropertyDescriptorCollection itemProperties; - private const int NoIndex = -1; - - public ListProjection(ICollectionAdapter adapter) - { - if (adapter == null) - throw new ArgumentNullException(nameof(adapter)); - - this.adapter = adapter; - adapter.Initialize(this); - } - - public int Count - { - get { return adapter.Count; } - } - - public IBindingList AsBindingList - { - get { return this; } - } - - public ICollectionAdapter Adapter - { - get { return adapter; } - } - - public IEqualityComparer Comparer - { - get { return adapter.Comparer ?? EqualityComparer.Default; } - } - - // Generic IBindingList Properties - bool IBindingList.AllowEdit { get { return true; } } - bool IBindingList.AllowNew { get { return true; } } - bool IBindingList.AllowRemove { get { return true; } } - bool IBindingList.SupportsChangeNotification { get { return true; } } - bool IBindingList.SupportsSearching { get { return false; } } - bool IBindingList.SupportsSorting { get { return false; } } - bool IBindingList.IsSorted { get { return false; } } - SysPropertyDescriptor IBindingList.SortProperty { get { return null; } } - ListSortDirection IBindingList.SortDirection { get { return ListSortDirection.Ascending; } } - - // System IBindingList Properties - bool IBindingList.AllowEdit { get { return true; } } - bool IBindingList.AllowNew { get { return true; } } - bool IBindingList.AllowRemove { get { return true; } } - bool IBindingList.SupportsChangeNotification { get { return true; } } - bool IBindingList.SupportsSearching { get { return false; } } - bool IBindingList.SupportsSorting { get { return false; } } - bool IBindingList.IsSorted { get { return false; } } - SysPropertyDescriptor IBindingList.SortProperty { get { return null; } } - ListSortDirection IBindingList.SortDirection { get { return ListSortDirection.Ascending; } } - - // Other Binding Properties - bool IRaiseItemChangedEvents.RaisesItemChangedEvents { get { return true; } } - - // IList Properties - bool IList.IsFixedSize { get { return false; } } - bool IList.IsReadOnly { get { return false; } } - bool ICollection.IsReadOnly { get { return false; } } - bool ICollection.IsSynchronized { get { return false; } } - object ICollection.SyncRoot { get { return this; } } - - public virtual bool Contains(T item) - { - return IndexOf(item) >= 0; - } - - bool IList.Contains(object item) - { - return Contains((T) item); - } - - public int IndexOf(T item) - { - var count = Count; - var comparer = Comparer; - - for (var i = 0; i < count; i++) - if (comparer.Equals(this[i], item)) - return i; - - return -1; - } - - int IList.IndexOf(object item) - { - return IndexOf((T) item); - } - - public void CopyTo(T[] array, int index) - { - var count = Count; - - for (int i = 0, j = index; i < count; i++, j++) - array[j] = this[i]; - } - - void ICollection.CopyTo(Array array, int index) - { - CopyTo((T[]) array, index); - } - - public IEnumerator GetEnumerator() - { - var count = Count; - - for (var i = 0; i < count; i++) - yield return this[i]; - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - public T this[int index] - { - get { return adapter[index]; } - set { adapter[index] = value; } - } - - object IList.this[int index] - { - get { return this[index]; } - set { this[index] = (T) value; } - } - - public void Replace(IEnumerable items) - { - (this as ICollectionProjection).Replace(items); - } - - void ICollectionProjection.Replace(IEnumerable items) - { - SuspendEvents(); - try - { - Clear(); - foreach (T item in items) - Add(item); - } - finally - { - ResumeEvents(); - } - } - - protected virtual bool OnReplacing(T oldValue, T newValue) - { - return true; - } - - bool ICollectionAdapterObserver.OnReplacing(T oldValue, T newValue) - { - return OnReplacing(oldValue, newValue); - } - - protected virtual void OnReplaced(T oldValue, T newValue, int index) - { - DetachPropertyChanged(oldValue); - AttachPropertyChanged(newValue); - NotifyListChanged(ListChangedType.ItemChanged, index); - } - - void ICollectionAdapterObserver.OnReplaced(T oldValue, T newValue, int index) - { - OnReplaced(oldValue, newValue, index); - } - - public virtual T AddNew() - { - var item = (T) adapter.AddNew(); - addNewIndex = addedIndex; - return item; - } - - object IBindingList.AddNew() - { - return AddNew(); - } - - public bool IsNew(int index) - { - return index == addNewIndex - && index >= 0; - } - - public virtual void EndNew(int index) - { - if (IsNew(index)) - addNewIndex = NoIndex; - } - - public virtual void CancelNew(int index) - { - if (IsNew(index)) - { - RemoveAt(addNewIndex); - addNewIndex = NoIndex; - } - } - - public virtual bool Add(T item) - { - return adapter.Add(item); - } - - void ICollection.Add(T item) - { - Add(item); - } - - int IList.Add(object item) - { - Add((T) item); - return addedIndex; - } - - public void Insert(int index, T item) - { - if (index < 0) - throw new ArgumentOutOfRangeException(nameof(index)); - - var count = Count; - if (index > count) - throw new ArgumentOutOfRangeException(nameof(index)); - - EndNew(addNewIndex); - if (index == count) - adapter.Add(item); - else - adapter.Insert(index, item); - } - - void IList.Insert(int index, object item) - { - Insert(index, (T) item); - } - - protected virtual bool OnInserting(T value) - { - return true; - } - - bool ICollectionAdapterObserver.OnInserting(T value) - { - return OnInserting(value); - } - - protected virtual void OnInserted(T newValue, int index) - { - addedIndex = index; - AttachPropertyChanged(newValue); - NotifyListChanged(ListChangedType.ItemAdded, index); - } - - void ICollectionAdapterObserver.OnInserted(T newValue, int index) - { - OnInserted(newValue, index); - } - - public virtual bool Remove(T item) - { - var index = IndexOf(item); - if (index < 0) return false; - RemoveAt(index); - return true; - } - - void IList.Remove(object value) - { - Remove((T) value); - } - - public virtual void RemoveAt(int index) - { - EndNew(addNewIndex); - adapter.Remove(index); - } - - public virtual void Clear() - { - EndNew(addNewIndex); - adapter.Clear(); - NotifyListReset(); - } - - void ICollectionProjection.ClearReferences() - { - adapter.ClearReferences(); - } - - protected virtual void OnRemoving(T oldValue) - { - DetachPropertyChanged(oldValue); - } - - void ICollectionAdapterObserver.OnRemoving(T oldValue) - { - OnRemoving(oldValue); - } - - protected virtual void OnRemoved(T oldValue, int index) - { - NotifyListChanged(ListChangedType.ItemDeleted, index); - } - - void ICollectionAdapterObserver.OnRemoved(T oldValue, int index) - { - OnRemoved(oldValue, index); - } - - public bool IsChanged - { - get - { - if (adapter.HasSnapshot == false) - return false; - - var count = Count; - if (adapter.SnapshotCount != count) - return true; - - var comparer = Comparer; - for (var i = 0; i < count; i++) - { - var currentItem = adapter.GetCurrentItem (i); - var snapshotItem = adapter.GetSnapshotItem(i); - - if (comparer.Equals(currentItem, snapshotItem) == false) - return true; - - var tracked = currentItem as IChangeTracking; - if (tracked != null && tracked.IsChanged) - return true; - } - - return false; - } - } - - public void BeginEdit() - { - if (!adapter.HasSnapshot) - adapter.SaveSnapshot(); - } - - public void EndEdit() - { - adapter.DropSnapshot(); - } - - public void CancelEdit() - { - if (adapter.HasSnapshot) - { - adapter.LoadSnapshot(); - adapter.DropSnapshot(); - NotifyListReset(); - } - } - - public void AcceptChanges() - { - BeginEdit(); - } - - public void RejectChanges() - { - CancelEdit(); - } - - private void AttachPropertyChanged(T value) - { - if (typeof(T).IsValueType) - return; - - var notifier = value as INotifyPropertyChanged; - if (notifier == null) - return; - - if (propertyHandler == null) - propertyHandler = HandlePropertyChanged; - - notifier.PropertyChanged += propertyHandler; - } - - private void DetachPropertyChanged(T value) - { - if (typeof(T).IsValueType) - return; - - var notifier = value as INotifyPropertyChanged; - if (notifier == null || propertyHandler == null) - return; - - notifier.PropertyChanged -= propertyHandler; - } - - private void HandlePropertyChanged(object sender, PropertyChangedEventArgs e) - { - T item; - var notify - = EventsEnabled - && CanHandle(sender, e) - && TryGetChangedItem(sender, out item) - && TryGetChangedIndex(item); - - if (notify) - { - var property = GetChangedProperty(e); - var change = new ListChangedEventArgs(ListChangedType.ItemChanged, changedIndex, property); - OnListChanged(change); - } - } - - private bool CanHandle(object sender, PropertyChangedEventArgs e) - { - if (sender == null || e == null || string.IsNullOrEmpty(e.PropertyName)) - { - NotifyListReset(); - return false; - } - return true; - } - - private bool TryGetChangedItem(object sender, out T item) - { - try - { - item = (T) sender; - return true; - } - catch (InvalidCastException) - { - NotifyListReset(); - item = default(T); - return false; - } - } - - private bool TryGetChangedIndex(T item) - { - var isSameItem - = changedIndex >= 0 - && changedIndex < Count - && Comparer.Equals(this[changedIndex], item); - if (isSameItem) - return true; - - changedIndex = IndexOf(item); - if (changedIndex >= 0) - return true; - - DetachPropertyChanged(item); - NotifyListReset(); - return false; - } - - private static SysPropertyDescriptor GetChangedProperty(PropertyChangedEventArgs e) - { - if (itemProperties == null) - itemProperties = TypeDescriptor.GetProperties(typeof(T)); - - return itemProperties.Find(e.PropertyName, true); - } - - public event ListChangedEventHandler ListChanged; - protected virtual void OnListChanged(ListChangedEventArgs args) - { - var handler = ListChanged; - if (handler != null) - handler(this, args); - } - - protected void NotifyListChanged(ListChangedType type, int index) - { - if (EventsEnabled) - OnListChanged(new ListChangedEventArgs(type, index)); - } - - protected void NotifyListReset() - { - if (EventsEnabled) - OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1)); - } - - public bool EventsEnabled - { - get { return suspendLevel == 0; } - } - - public void SuspendEvents() - { - suspendLevel++; - } - - public bool ResumeEvents() - { - var enabled - = suspendLevel == 0 - || --suspendLevel == 0; - - if (enabled) - NotifyListReset(); - - return enabled; - } - - void IBindingList.AddIndex(SysPropertyDescriptor property) - { - // Do nothing - } - - void IBindingList.AddIndex(SysPropertyDescriptor property) - { - // Do nothing - } - - void IBindingList.RemoveIndex(SysPropertyDescriptor property) - { - // Do nothing - } - - void IBindingList.RemoveIndex(SysPropertyDescriptor property) - { - // Do nothing - } - - int IBindingList.Find(SysPropertyDescriptor property, object key) - { - throw new NotSupportedException(); - } - - int IBindingList.Find(SysPropertyDescriptor property, object key) - { - throw new NotSupportedException(); - } - - void IBindingList.ApplySort(SysPropertyDescriptor property, ListSortDirection direction) - { - throw new NotSupportedException(); - } - - void IBindingList.ApplySort(SysPropertyDescriptor property, ListSortDirection direction) - { - throw new NotSupportedException(); - } - - void IBindingList.RemoveSort() - { - throw new NotSupportedException(); - } - - void IBindingList.RemoveSort() - { - throw new NotSupportedException(); - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Util/ListProjectionDebugView.cs b/Castle.Core/Components.DictionaryAdapter/Util/ListProjectionDebugView.cs deleted file mode 100644 index 31b75c3..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Util/ListProjectionDebugView.cs +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System; - using System.Diagnostics; - - internal sealed class ListProjectionDebugView - { - private readonly ListProjection projection; - - public ListProjectionDebugView(ListProjection projection) - { - if (projection == null) - throw new ArgumentNullException(nameof(projection)); - - this.projection = projection; - } - - [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] - public T[] Items - { - get - { - T[] array = new T[projection.Count]; - projection.CopyTo(array, 0); - return array; - } - } - - public ICollectionAdapter Adapter - { - get { return projection.Adapter; } - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Util/SetProjection.cs b/Castle.Core/Components.DictionaryAdapter/Util/SetProjection.cs deleted file mode 100644 index f8c7e1a..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Util/SetProjection.cs +++ /dev/null @@ -1,159 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System.Collections.Generic; - using System.Diagnostics; - using System.Linq; - - public class SetProjection : ListProjection, ISet - { - private readonly HashSet set; - - public SetProjection(ICollectionAdapter adapter) - : base(adapter) - { - set = new HashSet(); - Repopulate(); - } - - public override bool Contains(T item) - { - return set.Contains(item); - } - - public bool IsSubsetOf(IEnumerable other) - { - return set.IsSubsetOf(other); - } - - public bool IsSupersetOf(IEnumerable other) - { - return set.IsSupersetOf(other); - } - - public bool IsProperSubsetOf(IEnumerable other) - { - return set.IsProperSubsetOf(other); - } - - public bool IsProperSupersetOf(IEnumerable other) - { - return set.IsProperSupersetOf(other); - } - - public bool Overlaps(IEnumerable other) - { - return set.Overlaps(other); - } - - public bool SetEquals(IEnumerable other) - { - return set.SetEquals(other); - } - - private void Repopulate() - { - SuspendEvents(); - - var count = Count; - for (var index = 0; index < count;) - { - var value = this[index]; - - if (!set.Add(value)) - { RemoveAt(index); count--; } - else - index++; - } - - ResumeEvents(); - } - - public override void EndNew(int index) - { - if (IsNew(index) && OnInserting(this[index])) - base.EndNew(index); - else - CancelNew(index); - } - - public override bool Add(T item) - { - return !set.Contains(item) - && base.Add(item); - } - - protected override bool OnInserting(T value) - { - return set.Add(value); - } - - protected override bool OnReplacing(T oldValue, T newValue) - { - if (!set.Add(newValue)) - return false; - - set.Remove(oldValue); - return true; - } - - public override bool Remove(T item) - { - return set .Remove(item) - && base.Remove(item); - } - - public override void RemoveAt(int index) - { - set .Remove (this[index]); - base.RemoveAt(index); - } - - public override void Clear() - { - set .Clear(); - base.Clear(); - } - - public void UnionWith(IEnumerable other) - { - foreach (var value in other) - Add(value); - } - - public void ExceptWith(IEnumerable other) - { - foreach (var value in other) - Remove(value); - } - - public void IntersectWith(IEnumerable other) - { - var removals = set.Except(other).ToArray(); - - ExceptWith(removals); - } - - public void SymmetricExceptWith(IEnumerable other) - { - var removals = set.Intersect(other).ToArray(); - var additions = other.Except(removals); - - ExceptWith(removals); - UnionWith(additions); - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Util/VirtualObject.cs b/Castle.Core/Components.DictionaryAdapter/Util/VirtualObject.cs deleted file mode 100644 index c17a015..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Util/VirtualObject.cs +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System; - using System.Collections.Generic; - - public abstract class VirtualObject : IVirtual - { - private List> sites; - - protected VirtualObject() { } - - protected VirtualObject(IVirtualSite site) - { - sites = new List> { site }; - } - - public abstract bool IsReal { get; } - - protected void AddSite(IVirtualSite site) - { - if (sites != null) - { - sites.Add(site); - } - } - - void IVirtual.AddSite(IVirtualSite site) - { - AddSite(site); - } - - protected void RemoveSite(IVirtualSite site) - { - if (sites != null) - { - var index = sites.IndexOf(site); - if (index != -1) - sites.RemoveAt(index); - } - } - - void IVirtual.RemoveSite(IVirtualSite site) - { - RemoveSite(site); - } - - public TNode Realize() - { - TNode node; - if (TryRealize(out node)) - { - if (sites != null) - { - var count = sites.Count; - for (var i = 0; i < count; i++) - sites[i].OnRealizing(node); - sites = null; - } - - OnRealized(); - } - return node; - } - - void IVirtual.Realize() - { - Realize(); - } - - protected abstract bool TryRealize(out TNode node); - - public event EventHandler Realized; - protected virtual void OnRealized() - { - var handler = Realized; - if (handler != null) - { - handler(this, EventArgs.Empty); - Realized = null; - } - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Util/VirtualSite.cs b/Castle.Core/Components.DictionaryAdapter/Util/VirtualSite.cs deleted file mode 100644 index 918dc70..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Util/VirtualSite.cs +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter -{ - using System; - using System.Collections.Generic; - using Castle.Core; - - public sealed class VirtualSite : - IVirtualSite, - IEquatable> - { - private readonly IVirtualTarget target; - private readonly TMember member; - - public VirtualSite(IVirtualTarget target, TMember member) - { - this.target = target; - this.member = member; - } - - public IVirtualTarget Target - { - get { return target; } - } - - public TMember Member - { - get { return member; } - } - - public void OnRealizing(TNode node) - { - target.OnRealizing(node, member); - } - - public override bool Equals(object obj) - { - return Equals(obj as VirtualSite); - } - - public bool Equals(VirtualSite other) - { - return other != null - && TargetComparer.Equals(target, other.target) - && MemberComparer.Equals(member, other.member); - } - - public override int GetHashCode() - { - return 0x72F10A3D - + 37 * TargetComparer.GetHashCode(target) - + 37 * MemberComparer.GetHashCode(member); - } - - private static readonly IEqualityComparer> - TargetComparer = ReferenceEqualityComparer>.Instance; - - private static readonly IEqualityComparer - MemberComparer = EqualityComparer.Default; - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Core/DefaultXmlReferenceFormat.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Core/DefaultXmlReferenceFormat.cs deleted file mode 100644 index c175dce..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Core/DefaultXmlReferenceFormat.cs +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - using System.Globalization; - - public sealed class DefaultXmlReferenceFormat : IXmlReferenceFormat - { - public static readonly DefaultXmlReferenceFormat - Instance = new DefaultXmlReferenceFormat(); - - private DefaultXmlReferenceFormat() { } - - public bool TryGetIdentity(IXmlNode node, out int id) - { - var text = node.GetAttribute(XRef.Id); - return int.TryParse(text, IntegerStyle, Culture, out id); - } - - public bool TryGetReference(IXmlNode node, out int id) - { - var text = node.GetAttribute(XRef.Ref); - return int.TryParse(text, IntegerStyle, Culture, out id); - } - - public void SetIdentity(IXmlNode node, int id) - { - node.SetAttribute(XRef.Id, id.ToString(Culture)); - } - - public void SetReference(IXmlNode node, int id) - { - node.SetAttribute(XRef.Ref, id.ToString(Culture)); - } - - public void ClearIdentity(IXmlNode node) - { - node.SetAttribute(XRef.Id, null); - } - - public void ClearReference(IXmlNode node) - { - node.SetAttribute(XRef.Ref, null); - } - - private const NumberStyles - IntegerStyle = NumberStyles.Integer; - - private static readonly IFormatProvider - Culture = CultureInfo.InvariantCulture; - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Core/IXmlReferenceFormat.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Core/IXmlReferenceFormat.cs deleted file mode 100644 index e7478e3..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Core/IXmlReferenceFormat.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - public interface IXmlReferenceFormat - { - bool TryGetIdentity (IXmlNode node, out int id); - bool TryGetReference (IXmlNode node, out int id); - - void SetIdentity (IXmlNode node, int id); - void SetReference (IXmlNode node, int id); - - void ClearIdentity (IXmlNode node); - void ClearReference (IXmlNode node); - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Core/XmlAdapter.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Core/XmlAdapter.cs deleted file mode 100644 index 5f500c4..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Core/XmlAdapter.cs +++ /dev/null @@ -1,504 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - using System.Collections; - using System.Collections.Generic; - using System.Linq; - using System.Xml; - using System.Xml.Serialization; - using IBindingList = System.ComponentModel.IBindingList; - using ListChangedEventArgs = System.ComponentModel.ListChangedEventArgs; - using ListChangedType = System.ComponentModel.ListChangedType; - - public class XmlAdapter : DictionaryBehaviorAttribute, - IDictionaryInitializer, - IDictionaryPropertyGetter, - IDictionaryPropertySetter, - IDictionaryCreateStrategy, - IDictionaryCopyStrategy, - IDictionaryReferenceManager, - IVirtual, - IXmlNodeSource - { - private IXmlNode node; - private object source; - private XmlReferenceManager references; - private XmlMetadata primaryXmlMeta; - private Dictionary secondaryXmlMetas; - private readonly bool isRoot; - - public XmlAdapter() - : this(new XmlDocument()) { } - - public XmlAdapter(XmlNode node) - { - if (node == null) - throw Error.ArgumentNull(nameof(node)); - - this.source = node; - this.isRoot = true; - } - - /// - /// Initializes a new instance of the class - /// that represents a child object in a larger object graph. - /// - public XmlAdapter(IXmlNode node, XmlReferenceManager references) - { - if (node == null) - throw Error.ArgumentNull(nameof(node)); - if (references == null) - throw Error.ArgumentNull(nameof(references)); - - this.node = node; - this.references = references; - } - - public bool IsReal - { - get { return node != null && node.IsReal; } - } - - public IXmlNode Node - { - get { return node; } - } - - internal XmlReferenceManager References - { - get { return references; } - } - - object IDictionaryCreateStrategy.Create(IDictionaryAdapter parent, Type type, IDictionary dictionary) - { - var adapter = new XmlAdapter(new XmlDocument()); - return parent.CreateChildAdapter(type, adapter, dictionary); - } - - void IDictionaryInitializer.Initialize(IDictionaryAdapter dictionaryAdapter, object[] behaviors) - { - var meta = dictionaryAdapter.Meta; - - if (primaryXmlMeta == null) - InitializePrimary (meta, dictionaryAdapter); - else - InitializeSecondary(meta); - - InitializeBaseTypes (meta); - InitializeStrategies(dictionaryAdapter); - InitializeReference (dictionaryAdapter); - } - - private void InitializePrimary(DictionaryAdapterMeta meta, IDictionaryAdapter dictionaryAdapter) - { - RequireXmlMeta(meta); - primaryXmlMeta = meta.GetXmlMeta(); - - if (node == null) - node = GetBaseNode(); - if (!node.IsReal) - node.Realized += HandleNodeRealized; - - if (references == null) - references = new XmlReferenceManager(node, DefaultXmlReferenceFormat.Instance); - InitializeReference(this); - } - - private void InitializeSecondary(DictionaryAdapterMeta meta) - { - AddSecondaryXmlMeta(meta); - } - - private void InitializeBaseTypes(DictionaryAdapterMeta meta) - { - foreach (var type in meta.Type.GetInterfaces()) - { - var ns = type.Namespace; - var ignore - = ns == "Castle.Components.DictionaryAdapter" - || ns == "System.ComponentModel"; - if (ignore) continue; - - var baseMeta = meta.GetAdapterMeta(type); - AddSecondaryXmlMeta(baseMeta); - } - } - - private void InitializeStrategies(IDictionaryAdapter dictionaryAdapter) - { - var instance = dictionaryAdapter.This; - if (instance.CreateStrategy == null) - { - instance.CreateStrategy = this; - instance.AddCopyStrategy(this); - } - } - - private void InitializeReference(object value) - { - if (isRoot) - // If this is a root XmlAdapter, we must pre-populate the reference manager with - // this XmlAdapter and its IDictionaryAdapters. This enables child objects in the - // graph to reference the root object. - references.Add(node, this, value, true); - } - - private void AddSecondaryXmlMeta(DictionaryAdapterMeta meta) - { - if (secondaryXmlMetas == null) - secondaryXmlMetas = new Dictionary(); - else if (secondaryXmlMetas.ContainsKey(meta.Type)) - return; - - RequireXmlMeta(meta); - secondaryXmlMetas[meta.Type] = meta.GetXmlMeta(); - } - - private static void RequireXmlMeta(DictionaryAdapterMeta meta) - { - if (!meta.HasXmlMeta()) - throw Error.XmlMetadataNotAvailable(meta.Type); - } - - bool IDictionaryCopyStrategy.Copy(IDictionaryAdapter source, IDictionaryAdapter target, ref Func selector) - { - if (selector == null) - selector = property => HasProperty(property.PropertyName, source); - return false; - } - - object IDictionaryPropertyGetter.GetPropertyValue(IDictionaryAdapter dictionaryAdapter, - string key, object storedValue, PropertyDescriptor property, bool ifExists) - { - XmlAccessor accessor; - if (TryGetAccessor(key, property, null != storedValue, out accessor)) - { - storedValue = accessor.GetPropertyValue(node, dictionaryAdapter, references, !ifExists); - if (null != storedValue) - { - AttachObservers(storedValue, dictionaryAdapter, property); - dictionaryAdapter.StoreProperty(property, key, storedValue); - } - } - return storedValue; - } - - bool IDictionaryPropertySetter.SetPropertyValue(IDictionaryAdapter dictionaryAdapter, - string key, ref object value, PropertyDescriptor property) - { - XmlAccessor accessor; - if (TryGetAccessor(key, property, false, out accessor)) - { - if (value != null && dictionaryAdapter.ShouldClearProperty(property, value)) - value = null; - var oldValue = dictionaryAdapter.ReadProperty(key); - accessor.SetPropertyValue(node, dictionaryAdapter, references, oldValue, ref value); - } - return true; - } - - private static string EnsureKey(string key, PropertyDescriptor property) - { - return string.IsNullOrEmpty(key) - ? property.PropertyName - : key; - } - - private IXmlNode GetBaseNode() - { - var node = GetSourceNode(); - - if (node.IsElement) - return node; - if (node.IsAttribute) - throw Error.NotSupported(); - // must be root - - var cursor = primaryXmlMeta.SelectBase(node); - return cursor.MoveNext() - ? cursor.Save() - : cursor; - } - - private IXmlNode GetSourceNode() - { - var xmlNode = source as XmlNode; - if (xmlNode != null) - return new SysXmlNode(xmlNode, primaryXmlMeta.ClrType, primaryXmlMeta.Context); - - throw Error.NotSupported(); - } - - private bool TryGetAccessor(string key, PropertyDescriptor property, bool requireVolatile, out XmlAccessor accessor) - { - accessor = property.HasAccessor() - ? property.GetAccessor() - : CreateAccessor(key, property); - - if (accessor.IsIgnored) - return Try.Failure(out accessor); - if (requireVolatile && !accessor.IsVolatile) - return Try.Failure(out accessor); - return true; - } - - private XmlAccessor CreateAccessor(string key, PropertyDescriptor property) - { - var accessor = null as XmlAccessor; - var isVolatile = false; - var isReference = false; - - if (string.IsNullOrEmpty(key)) - accessor = CreateAccessor(key, property, XmlSelfAccessor.Factory); - - foreach (var behavior in property.Annotations) - { - if (IsIgnoreBehavior(behavior)) - return XmlIgnoreBehaviorAccessor.Instance; - else if (IsVolatileBehavior(behavior)) - isVolatile = true; - else if (IsReferenceBehavior(behavior)) - isReference = true; - else - TryApplyBehavior(key, property, behavior, ref accessor); - } - - if (accessor == null) - accessor = CreateAccessor(key, property, XmlDefaultBehaviorAccessor.Factory); - - accessor.ConfigureVolatile (isVolatile); - accessor.ConfigureReference(isReference); - accessor.Prepare(); - property.SetAccessor(accessor); - return accessor; - } - - private bool TryApplyBehavior(string key, PropertyDescriptor property, object behavior, ref XmlAccessor accessor) - { - return - TryApplyBehavior - (key, property, behavior, ref accessor, XmlElementBehaviorAccessor.Factory) - || - TryApplyBehavior - (key, property, behavior, ref accessor, XmlArrayBehaviorAccessor.Factory) - || - TryApplyBehavior - (key, property, behavior, ref accessor, XmlArrayBehaviorAccessor.Factory) - || - TryApplyBehavior - (key, property, behavior, ref accessor, XmlAttributeBehaviorAccessor.Factory) - || - TryApplyBehavior - (key, property, behavior, ref accessor, XPathBehaviorAccessor.Factory) - || - TryApplyBehavior - (key, property, behavior, ref accessor, XPathBehaviorAccessor.Factory) - || - TryApplyBehavior - (key, property, behavior, ref accessor, XPathBehaviorAccessor.Factory) - ; - } - - private bool TryApplyBehavior(string key, PropertyDescriptor property, object behavior, - ref XmlAccessor accessor, XmlAccessorFactory factory) - where TBehavior : class - where TAccessor : XmlAccessor, IConfigurable - { - var typedBehavior = behavior as TBehavior; - if (typedBehavior == null) - return false; - - if (accessor == null) - accessor = CreateAccessor(key, property, factory); - - var typedAccessor = accessor as TAccessor; - if (typedAccessor == null) - throw Error.AttributeConflict(key); - - typedAccessor.Configure(typedBehavior); - return true; - } - - private TAccessor CreateAccessor(string key, PropertyDescriptor property, XmlAccessorFactory factory) - where TAccessor : XmlAccessor - { - var xmlMeta = GetXmlMetadata(property.Property.DeclaringType); - var accessor = factory(key, property.PropertyType, xmlMeta.Context); - if (xmlMeta.IsNullable.HasValue) - accessor.ConfigureNillable(xmlMeta.IsNullable.Value); - if (xmlMeta.IsReference.HasValue) - accessor.ConfigureReference(xmlMeta.IsReference.Value); - return accessor; - } - - private XmlMetadata GetXmlMetadata(Type type) - { - if (type == primaryXmlMeta.ClrType) - return primaryXmlMeta; - - XmlMetadata xmlMeta; - if (secondaryXmlMetas.TryGetValue(type, out xmlMeta)) - return xmlMeta; - - throw Error.XmlMetadataNotAvailable(type); - } - - private static bool IsIgnoreBehavior(object behavior) - { - return behavior is XmlIgnoreAttribute; - } - - private static bool IsVolatileBehavior(object behavior) - { - return behavior is VolatileAttribute; - } - - private static bool IsReferenceBehavior(object behavior) - { - return behavior is ReferenceAttribute; - } - - void IVirtual.Realize() - { - throw new NotSupportedException("XmlAdapter does not support realization via IVirtual.Realize()."); - } - - public event EventHandler Realized; - protected virtual void OnRealized() - { - if (Realized != null) - Realized(this, EventArgs.Empty); - } - - private void HandleNodeRealized(object sender, EventArgs e) - { - OnRealized(); - } - - private void AttachObservers(object value, IDictionaryAdapter dictionaryAdapter, PropertyDescriptor property) - { - var bindingList = value as IBindingList; - if (bindingList != null) - bindingList.ListChanged += (s,e) => HandleListChanged(s, e, dictionaryAdapter, property); - } - - private void HandleListChanged(object value, ListChangedEventArgs args, IDictionaryAdapter dictionaryAdapter, PropertyDescriptor property) - { - var change = args.ListChangedType; - var changed - = change == ListChangedType.ItemAdded - || change == ListChangedType.ItemDeleted - || change == ListChangedType.ItemMoved - || change == ListChangedType.Reset; - - if (changed && dictionaryAdapter.ShouldClearProperty(property, value)) - { - value = null; - dictionaryAdapter.SetProperty(property.PropertyName, ref value); - } - } - - bool IDictionaryReferenceManager.IsReferenceProperty(IDictionaryAdapter dictionaryAdapter, string propertyName) - { - var xmlAdapter = XmlAdapter.For(dictionaryAdapter, false); - if (xmlAdapter == null) - return false; - - var instance = dictionaryAdapter.This; - - PropertyDescriptor property; - if (!instance.Properties.TryGetValue(propertyName, out property)) - return false; - - var key = property.GetKey(dictionaryAdapter, propertyName, instance.Descriptor); - - XmlAccessor accessor; - return xmlAdapter.TryGetAccessor(key, property, false, out accessor) - && accessor.IsReference; - } - - bool IDictionaryReferenceManager.TryGetReference(object keyObject, out object inGraphObject) - { - return references.TryGet(keyObject, out inGraphObject); - } - - void IDictionaryReferenceManager.AddReference(object keyObject, object relatedObject, bool isInGraph) - { - references.Add(null, keyObject, relatedObject, isInGraph); - } - - public override IDictionaryBehavior Copy() - { - return null; - } - - public static XmlAdapter For(object obj) - { - return For(obj, true); - } - - public static XmlAdapter For(object obj, bool required) - { - if (obj == null) - if (!required) return null; - else throw Error.ArgumentNull(nameof(obj)); - - var dictionaryAdapter = obj as IDictionaryAdapter; - if (dictionaryAdapter == null) - if (!required) return null; - else throw Error.NotDictionaryAdapter(nameof(obj)); - - var descriptor = dictionaryAdapter.This.Descriptor; - if (descriptor == null) - if (!required) return null; - else throw Error.NoInstanceDescriptor(nameof(obj)); - - var getters = descriptor.Getters; - if (getters == null) - if (!required) return null; - else throw Error.NoXmlAdapter(nameof(obj)); - - XmlAdapter xmlAdapter; - foreach (var getter in getters) - if (null != (xmlAdapter = getter as XmlAdapter)) - return xmlAdapter; - - if (!required) return null; - else throw Error.NoXmlAdapter(nameof(obj)); - } - - public static bool IsPropertyDefined(string propertyName, IDictionaryAdapter dictionaryAdapter) - { - var xmlAdapter = XmlAdapter.For(dictionaryAdapter, true); - return xmlAdapter != null - && xmlAdapter.HasProperty(propertyName, dictionaryAdapter); - } - - public bool HasProperty(string propertyName, IDictionaryAdapter dictionaryAdapter) - { - var key = dictionaryAdapter.GetKey(propertyName); - if (key == null) - return false; - - PropertyDescriptor property; - XmlAccessor accessor; - return dictionaryAdapter.This.Properties.TryGetValue(propertyName, out property) - && TryGetAccessor(key, property, false, out accessor) - && accessor.IsPropertyDefined(node); - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Core/XmlMetadata.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Core/XmlMetadata.cs deleted file mode 100644 index f8919fe..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Core/XmlMetadata.cs +++ /dev/null @@ -1,385 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - using System.Collections.Generic; - using System.Linq; - using System.Reflection; - using System.Xml; - using System.Xml.Serialization; - - public class XmlMetadata : IXmlKnownType, IXmlKnownTypeMap, IXmlIncludedType, IXmlIncludedTypeMap - { - private readonly Type clrType; - private readonly bool? qualified; - private readonly bool? isNullable; - private readonly bool? isReference; - private readonly string rootLocalName; - private readonly string rootNamespaceUri; - private readonly string childNamespaceUri; - private readonly string typeLocalName; - private readonly string typeNamespaceUri; - - private readonly HashSet reservedNamespaceUris; - private List pendingIncludes; - private readonly XmlIncludedTypeSet includedTypes; - private readonly XmlContext context; - private readonly DictionaryAdapterMeta source; - private readonly CompiledXPath path; - - public XmlMetadata(DictionaryAdapterMeta meta, IEnumerable reservedNamespaceUris) - { - if (meta == null) - throw Error.ArgumentNull(nameof(meta)); - if (reservedNamespaceUris == null) - throw Error.ArgumentNull(nameof(reservedNamespaceUris)); - - source = meta; - clrType = meta.Type; - context = new XmlContext(this); - includedTypes = new XmlIncludedTypeSet(); - - this.reservedNamespaceUris - = reservedNamespaceUris as HashSet - ?? new HashSet(reservedNamespaceUris); - - var xmlRoot = null as XmlRootAttribute; - var xmlType = null as XmlTypeAttribute; - var xmlDefaults = null as XmlDefaultsAttribute; - var xmlInclude = null as XmlIncludeAttribute; - var xmlNamespace = null as XmlNamespaceAttribute; - var reference = null as ReferenceAttribute; - var xPath = null as XPathAttribute; - var xPathVariable = null as XPathVariableAttribute; - var xPathFunction = null as XPathFunctionAttribute; - - foreach (var behavior in meta.Behaviors) - { - if (TryCast(behavior, ref xmlRoot )) { } - else if (TryCast(behavior, ref xmlType )) { } - else if (TryCast(behavior, ref xmlDefaults )) { } - else if (TryCast(behavior, ref xmlInclude )) { AddPendingInclude(xmlInclude); } - else if (TryCast(behavior, ref xmlNamespace )) { context.AddNamespace(xmlNamespace ); } - else if (TryCast(behavior, ref reference )) { } - else if (TryCast(behavior, ref xPath )) { } - else if (TryCast(behavior, ref xPathVariable)) { context.AddVariable (xPathVariable); } - else if (TryCast(behavior, ref xPathFunction)) { context.AddFunction (xPathFunction); } - } - - if (xmlDefaults != null) - { - qualified = xmlDefaults.Qualified; - isNullable = xmlDefaults.IsNullable; - } - - if (reference != null) - { - isReference = true; - } - - typeLocalName = XmlConvert.EncodeLocalName - ( - (!meta.HasXmlType() ? null : meta.GetXmlType().NonEmpty()) ?? - (xmlType == null ? null : xmlType.TypeName .NonEmpty()) ?? - GetDefaultTypeLocalName(clrType) - ); - - rootLocalName = XmlConvert.EncodeLocalName - ( - (xmlRoot == null ? null : xmlRoot.ElementName.NonEmpty()) ?? - typeLocalName - ); - - typeNamespaceUri = - ( - (xmlType == null ? null : xmlType.Namespace) - ); - - rootNamespaceUri = - ( - (xmlRoot == null ? null : xmlRoot.Namespace) - ); - - childNamespaceUri = - ( - typeNamespaceUri ?? - rootNamespaceUri - ); - - if (xPath != null) - { - path = xPath.GetPath; - path.SetContext(context); - } - } - - public Type ClrType - { - get { return clrType; } - } - - public bool? Qualified - { - get { return qualified; } - } - - public bool? IsNullable - { - get { return isNullable; } - } - - public bool? IsReference - { - get { return isReference; } - } - - public XmlName Name - { - get { return new XmlName(rootLocalName, rootNamespaceUri); } - } - - public XmlName XsiType - { - get { return new XmlName(typeLocalName, typeNamespaceUri); } - } - - XmlName IXmlIdentity.XsiType - { - get { return XmlName.Empty; } - } - - public string ChildNamespaceUri - { - get { return childNamespaceUri; } - } - - public IEnumerable ReservedNamespaceUris - { - get { return reservedNamespaceUris.ToArray(); } - } - - public XmlIncludedTypeSet IncludedTypes - { - get { ProcessPendingIncludes(); return includedTypes; } - } - - public IXmlContext Context - { - get { return context; } - } - - public CompiledXPath Path - { - get { return path; } - } - - IXmlKnownType IXmlKnownTypeMap.Default - { - get { return this; } - } - - IXmlIncludedType IXmlIncludedTypeMap.Default - { - get { return this; } - } - - public bool IsReservedNamespaceUri(string namespaceUri) - { - return reservedNamespaceUris.Contains(namespaceUri); - } - - public IXmlCursor SelectBase(IXmlNode node) // node is root - { - if (path != null) - return node.Select(path, this, context, RootFlags); - - return node.SelectChildren(this, context, RootFlags); - } - - private bool IsMatch(IXmlIdentity xmlIdentity) - { - var name = xmlIdentity.Name; - - return NameComparer.Equals(rootLocalName, name.LocalName) - && (rootNamespaceUri == null || NameComparer.Equals(rootNamespaceUri, name.NamespaceUri)); - } - - private bool IsMatch(Type clrType) - { - return clrType == this.clrType; - } - - public bool TryGet(IXmlIdentity xmlIdentity, out IXmlKnownType knownType) - { - return IsMatch(xmlIdentity) - ? Try.Success(out knownType, this) - : Try.Failure(out knownType); - } - - public bool TryGet(Type clrType, out IXmlKnownType knownType) - { - return IsMatch(clrType) - ? Try.Success(out knownType, this) - : Try.Failure(out knownType); - } - - public bool TryGet(XmlName xsiType, out IXmlIncludedType includedType) - { - return xsiType == XmlName.Empty || xsiType == this.XsiType - ? Try.Success(out includedType, this) - : Try.Failure(out includedType); - } - - public bool TryGet(Type clrType, out IXmlIncludedType includedType) - { - return clrType == this.clrType - ? Try.Success(out includedType, this) - : Try.Failure(out includedType); - } - - private void AddPendingInclude(XmlIncludeAttribute attribute) - { - if (pendingIncludes == null) - pendingIncludes = new List(); - pendingIncludes.Add(attribute.Type); - } - - private void ProcessPendingIncludes() - { - var clrTypes = pendingIncludes; - pendingIncludes = null; - if (clrTypes == null) return; - - foreach (var clrType in clrTypes) - { - var xsiType = GetDefaultXsiType(clrType); - var includedType = new XmlIncludedType(xsiType, clrType); - includedTypes.Add(includedType); - } - } - - public XmlName GetDefaultXsiType(Type clrType) - { - if (clrType == this.clrType) - return this.XsiType; - - IXmlIncludedType include; - if (includedTypes.TryGet(clrType, out include)) - return include.XsiType; - - var kind = XmlTypeSerializer.For(clrType).Kind; - switch (kind) - { - case XmlTypeKind.Complex: - if (!clrType.IsInterface) goto default; - return GetXmlMetadata(clrType).XsiType; - - case XmlTypeKind.Collection: - var itemClrType = clrType.GetCollectionItemType(); - var itemXsiType = GetDefaultXsiType(itemClrType); - return new XmlName("ArrayOf" + itemXsiType.LocalName, null); - - default: - return new XmlName(clrType.Name, null); - } - } - - public IEnumerable GetIncludedTypes(Type baseType) - { - var queue = new Queue(); - var visited = new HashSet(); - XmlMetadata metadata; - - visited.Add(baseType); - if (TryGetXmlMetadata(baseType, out metadata)) - queue.Enqueue(metadata); - metadata = this; - - for (;;) - { - foreach (var includedType in metadata.IncludedTypes) - { - var clrType = includedType.ClrType; - var relevant - = baseType != clrType - && baseType.IsAssignableFrom(clrType) - && visited.Add(clrType); - - if (!relevant) - continue; - - yield return includedType; - - if (TryGetXmlMetadata(clrType, out metadata)) - queue.Enqueue(metadata); - } - - if (queue.Count == 0) - yield break; - - metadata = queue.Dequeue(); - } - } - - private bool TryGetXmlMetadata(Type clrType, out XmlMetadata metadata) - { - var kind = XmlTypeSerializer.For(clrType).Kind; - - return kind == XmlTypeKind.Complex && clrType.IsInterface - ? Try.Success(out metadata, GetXmlMetadata(clrType)) - : Try.Failure(out metadata); - } - - private XmlMetadata GetXmlMetadata(Type clrType) - { - return source - .GetAdapterMeta(clrType) - .GetXmlMeta(); - } - - private string GetDefaultTypeLocalName(Type clrType) - { - var name = clrType.Name; - return IsInterfaceName(name) - ? name.Substring(1) - : name; - } - - private static bool IsInterfaceName(string name) - { - return name.Length > 1 - && name[0] == 'I' - && char.IsUpper(name, 1); - } - - private static bool TryCast(object obj, ref T result) - where T : class - { - var value = obj as T; - if (null == value) return false; - - result = value; - return true; - } - - protected static readonly StringComparer - NameComparer = StringComparer.OrdinalIgnoreCase; - - private const CursorFlags RootFlags - = CursorFlags.Elements - | CursorFlags.Mutable; - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Core/XmlMetadataBehavior.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Core/XmlMetadataBehavior.cs deleted file mode 100644 index 93306ba..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Core/XmlMetadataBehavior.cs +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System.Collections.Generic; - using System.Linq; - - public class XmlMetadataBehavior : DictionaryBehaviorAttribute, IDictionaryMetaInitializer - { - public static readonly XmlMetadataBehavior - Default = new XmlMetadataBehavior(); - - private readonly HashSet reservedNamespaceUris = new HashSet - { - Xmlns.NamespaceUri, - Xsi .NamespaceUri, - XRef .NamespaceUri - }; - - public IEnumerable ReservedNamespaceUris - { - get { return reservedNamespaceUris.ToArray(); } - } - - public XmlMetadataBehavior AddReservedNamespaceUri(string uri) - { - reservedNamespaceUris.Add(uri); - return this; - } - - void IDictionaryMetaInitializer.Initialize(IDictionaryAdapterFactory factory, DictionaryAdapterMeta meta) - { - meta.SetXmlMeta(new XmlMetadata(meta, reservedNamespaceUris)); - } - - bool IDictionaryMetaInitializer.ShouldHaveBehavior(object behavior) - { - return behavior is XmlDefaultsAttribute - || behavior is XmlNamespaceAttribute - || behavior is XPathVariableAttribute - || behavior is XPathFunctionAttribute; - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Core/XmlReferenceManager.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Core/XmlReferenceManager.cs deleted file mode 100644 index c325e7e..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Core/XmlReferenceManager.cs +++ /dev/null @@ -1,584 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - using System.Collections.Generic; - using System.Linq; - using System.Reflection; - - using Castle.Core; - using Castle.Core.Internal; - - public class XmlReferenceManager - { - private readonly Dictionary entriesById; - private readonly WeakKeyDictionary entriesByValue; - private readonly IXmlReferenceFormat format; - private int nextId; - - public XmlReferenceManager(IXmlNode root, IXmlReferenceFormat format) - { - entriesById = new Dictionary(); - entriesByValue = new WeakKeyDictionary(ReferenceEqualityComparer.Instance); - this.format = format; - this.nextId = 1; - - Populate(root); - } - - #region Populate - - private void Populate(IXmlNode node) - { - var references = new List(); - var iterator = node.SelectSubtree(); - - while (iterator.MoveNext()) - PopulateFromNode(iterator, references); - - PopulateDeferredReferences(references); - } - - private void PopulateFromNode(IXmlIterator node, ICollection references) - { - int id; - if (format.TryGetIdentity(node, out id)) - PopulateIdentity(id, node.Save()); - else if (format.TryGetReference(node, out id)) - PopulateReference(id, node.Save(), references); - } - - private void PopulateIdentity(int id, IXmlNode node) - { - Entry entry; - if (!entriesById.TryGetValue(id, out entry)) - entriesById.Add(id, new Entry(id, node)); - if (nextId <= id) - nextId = ++id; - } - - private void PopulateReference(int id, IXmlNode node, ICollection references) - { - Entry entry; - if (entriesById.TryGetValue(id, out entry)) - entry.AddReference(node); - else - references.Add(new Reference(id, node)); - } - - private void PopulateDeferredReferences(ICollection references) - { - foreach (var reference in references) - { - Entry entry; - if (entriesById.TryGetValue(reference.Id, out entry)) - entry.AddReference(reference.Node); - } - } - - #endregion - - public bool TryGet(object keyObject, out object inGraphObject) - { - Entry entry; - if (entriesByValue.TryGetValue(keyObject, out entry)) - { - inGraphObject = keyObject; - TryGetCompatibleValue(entry, keyObject.GetComponentType(), ref inGraphObject); - return true; - } - else - { - inGraphObject = null; - return false; - } - } - - public void Add(IXmlNode node, object keyValue, object newValue, bool isInGraph) - { - if (keyValue == null) - throw Error.ArgumentNull(nameof(keyValue)); - if (newValue == null) - throw Error.ArgumentNull(nameof(newValue)); - - var type = newValue.GetComponentType(); - if (ShouldExclude(type)) - return; - if (entriesByValue.ContainsKey(newValue)) - return; - - Entry entry; - if (entriesByValue.TryGetValue(keyValue, out entry)) - { - if (newValue == keyValue) - return; - } - else if (node != null) - { - bool reference; - if (!TryGetEntry(node, out entry, out reference)) - entry = new Entry(node); - } - else return; - - AddValueCore(entry, type, newValue, isInGraph); - } - - public bool OnGetStarting(ref IXmlNode node, ref object value, out object token) - { - Entry entry; - bool isReference; - - var type = node.ClrType; - if (ShouldExclude(type)) - { token = null; return true; } - - if (!TryGetEntry(node, out entry, out isReference)) - { token = CreateEntryToken; return true; } - - if (isReference) - RedirectNode(ref node, entry); - - var proceed = ! TryGetCompatibleValue(entry, node.ClrType, ref value); - - token = proceed ? entry : null; - return proceed; - } - - public void OnGetCompleted(IXmlNode node, object value, object token) - { - if (value == null) - return; - - var type = node.ClrType; - if (ShouldExclude(type)) - return; - - if (entriesByValue.ContainsKey(value)) - return; - - var entry = (token == CreateEntryToken) - ? new Entry(node) - : token as Entry; - if (entry == null) - return; - - AddValue(entry, type, value, null); - } - - public bool OnAssigningNull(IXmlNode node, object oldValue) - { - object token, newValue = null; - return OnAssigningValue(node, oldValue, ref newValue, out token); - } - - public bool OnAssigningValue(IXmlNode node, object oldValue, ref object newValue, out object token) - { - if (newValue == oldValue && newValue != null) - { token = null; return false; } - - var oldEntry = OnReplacingValue(node, oldValue); - - if (newValue == null) - return ShouldAssignmentProceed(oldEntry, null, token = null); - - var type = newValue.GetComponentType(); - if (ShouldExclude(type)) - return ShouldAssignmentProceed(oldEntry, null, token = null); - - var xmlAdapter = XmlAdapter.For(newValue, false); - - Entry newEntry; - if (entriesByValue.TryGetValue(xmlAdapter ?? newValue, out newEntry)) - { - // Value already present in graph; add reference - TryGetCompatibleValue(newEntry, type, ref newValue); - AddReference(node, newEntry); - token = null; - } - else - { - // Value not present in graph; add as primary - newEntry = oldEntry ?? new Entry(node); - AddValue(newEntry, type, newValue, xmlAdapter); - format.ClearIdentity (node); - format.ClearReference(node); - token = newEntry; - } - return ShouldAssignmentProceed(oldEntry, newEntry, token); - } - - private bool ShouldAssignmentProceed(Entry oldEntry, Entry newEntry, object token) - { - if (oldEntry != null && oldEntry != newEntry && oldEntry.Id > 0) - entriesById.Remove(oldEntry.Id); // Didn't reuse old entry; delete it - - return token != null // Expecting callback with a token, so proceed with set - || newEntry == null; // No reference tracking for this value; don't prevent assignment - } - - private Entry OnReplacingValue(IXmlNode node, object oldValue) - { - Entry entry; - bool isReference; - - if (oldValue == null) - { - if (!TryGetEntry(node, out entry, out isReference)) - return null; - } - else - { - if (!entriesByValue.TryGetValue(oldValue, out entry)) - return null; - isReference = !entry.Node.PositionEquals(node); - } - - if (isReference) - { - // Replacing reference - entry.RemoveReference(node); - ClearReference(entry, node); - return null; - } - else if (entry.References != null) - { - // Replacing primary that has references - // Relocate content to a referencing node (making it a new primary) - node = entry.RemoveReference(0); - ClearReference(entry, node); - entry.Node.CopyTo(node); - entry.Node.Clear(); - entry.Node = node; - return null; - } - else - { - // Replacing primary with no references; reuse entry - PrepareForReuse(entry); - return entry; - } - } - - public void OnAssignedValue(IXmlNode node, object givenValue, object storedValue, object token) - { - var entry = token as Entry; - if (entry == null) - return; - - if (ReferenceEquals(givenValue, storedValue)) - return; - - SetNotInGraph(entry, givenValue); - - if (entriesByValue.ContainsKey(storedValue)) - return; - - AddValue(entry, node.ClrType, storedValue, null); - } - - private void AddReference(IXmlNode node, Entry entry) - { - if (!entry.Node.PositionEquals(node)) - { - if (entry.References == null) - { - GenerateId(entry); - format.SetIdentity(entry.Node, entry.Id); - } - node.Clear(); - entry.AddReference(node); - format.SetReference(node, entry.Id); - } - } - - private void GenerateId(Entry entry) - { - if (entry.Id == 0) - { - entry.Id = nextId++; - entriesById.Add(entry.Id, entry); - } - } - - private void AddValue(Entry entry, Type type, object value, XmlAdapter xmlAdapter) - { - if (xmlAdapter == null) - xmlAdapter = XmlAdapter.For(value, false); - - AddValueCore(entry, type, value, true); - - if (xmlAdapter != null) - AddValueCore(entry, typeof(XmlAdapter), xmlAdapter, true); - } - - private void AddValueCore(Entry entry, Type type, object value, bool isInGraph) - { - entry.AddValue(type, value, isInGraph); - entriesByValue.Add(value, entry); - } - - private void ClearReference(Entry entry, IXmlNode node) - { - format.ClearReference(node); - - if (entry.References == null) - format.ClearIdentity(entry.Node); - } - - private void PrepareForReuse(Entry entry) - { - foreach (var item in entry.Values) - { - var value = item.Value.Target; - if (null != value) - entriesByValue.Remove(value); - } - entry.Values.Clear(); - - format.ClearIdentity(entry.Node); - } - - private bool TryGetEntry(IXmlNode node, out Entry entry, out bool reference) - { - int id; - - if (format.TryGetIdentity(node, out id)) - reference = false; - else if (format.TryGetReference(node, out id)) - reference = true; - else - { - reference = false; - entry = null; - return false; - } - - if (!entriesById.TryGetValue(id, out entry)) - throw IdNotFoundError(id); - return true; - } - - private bool TryGetCompatibleValue(Entry entry, Type type, ref object value) - { - var values = entry.Values; - if (values == null) - return false; - - var dictionaryAdapter = null as IDictionaryAdapter; - - // Try to find in the graph a directly assignable value - foreach (var item in values) - { - if (!item.IsInGraph) - continue; - - var candidate = item.Value.Target; - if (candidate == null) - continue; - - if (type.IsAssignableFrom(item.Type)) - if (null != candidate) - return Try.Success(out value, candidate); - - if (dictionaryAdapter == null) - dictionaryAdapter = candidate as IDictionaryAdapter; - } - - // Fall back to coercing a DA found in the graph - if (dictionaryAdapter != null) - { - value = dictionaryAdapter.Coerce(type); - entry.AddValue(type, value, true); - return true; - } - - return false; - } - - private static void SetNotInGraph(Entry entry, object value) - { - var xmlAdapter = XmlAdapter.For(value, false); - - SetNotInGraphCore(entry, value); - - if (xmlAdapter != null) - SetNotInGraphCore(entry, xmlAdapter); - } - - private static bool ShouldExclude(Type type) - { - return type.IsValueType - || type == StringType; - } - - private static void SetNotInGraphCore(Entry entry, object value) - { - var values = entry.Values; - for (int index = 0; index < values.Count; index++) - { - var item = values[index]; - var candidate = item.Value.Target; - - if (ReferenceEquals(candidate, value)) - { - item = new EntryValue(item.Type, item.Value, false); - values[index] = item; - return; - } - } - } - - private static IXmlNode RedirectNode(ref IXmlNode node, Entry entry) - { - var cursor = entry.Node.SelectSelf(node.ClrType); - cursor.MoveNext(); - return node = cursor; - } - - public void UnionWith(XmlReferenceManager other) - { - var visited = null as HashSet; - - foreach (var otherEntry in other.entriesByValue) - { - Entry thisEntry; - if (entriesByValue.TryGetValue(otherEntry.Key, out thisEntry)) - { - if (visited == null) - visited = new HashSet(ReferenceEqualityComparer.Instance); - else if (visited.Contains(thisEntry)) - continue; - visited.Add(thisEntry); - - foreach (var otherValue in otherEntry.Value.Values) - { - var otherTarget = otherValue.Value.Target; - if (otherTarget == null || - otherTarget == otherEntry.Key || - entriesByValue.ContainsKey(otherTarget)) - { continue; } - AddValueCore(thisEntry, otherValue.Type, otherTarget, false); - } - } - } - } - - private static readonly Type - StringType = typeof(string); - - private static readonly object - CreateEntryToken = new object(); - - private class Entry - { - public int Id; - public IXmlNode Node; - private List references; - private List values; - - public Entry(IXmlNode node) - { - Node = node.Save(); - } - - public Entry(int id, IXmlNode node) : this(node) - { - Id = id; - } - - public void AddReference(IXmlNode node) - { - if (references == null) - references = new List(); - references.Add(node); - } - - public IXmlNode RemoveReference(IXmlNode node) - { - for (var index = 0; index < references.Count; index++) - if (references[index].PositionEquals(node)) - return RemoveReference(index); - return node; - } - - public IXmlNode RemoveReference(int index) - { - var node = references[index]; - references.RemoveAt(index); - if (references.Count == 0) - references = null; - return node; - } - - public void AddValue(Type type, object value, bool isInGraph) - { - if (values == null) - values = new List(); - values.Add(new EntryValue(type, value, isInGraph)); - } - - public List References - { - get { return references; } - } - - public List Values - { - get { return values; } - } - } - - private struct Reference - { - public readonly int Id; - public readonly IXmlNode Node; - - public Reference(int id, IXmlNode node) - { - Id = id; - Node = node; - } - } - - private struct EntryValue - { - public readonly Type Type; - public readonly WeakReference Value; - public readonly bool IsInGraph; - - public EntryValue(Type type, object value, bool isInGraph) - : this(type, new WeakReference(value), isInGraph) { } - - public EntryValue(Type type, WeakReference value, bool isInGraph) - { - Type = type; - Value = value; - IsInGraph = isInGraph; - } - } - - private static Exception IdNotFoundError(int id) - { - var message = string.Format - ( - "The given ID ({0}) was not present in the underlying data.", - id - ); - return new KeyNotFoundException(message); - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/IXmlAccessor.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/IXmlAccessor.cs deleted file mode 100644 index 37683f0..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/IXmlAccessor.cs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - - public interface IXmlAccessor - { - Type ClrType { get; } - XmlTypeSerializer Serializer { get; } - IXmlContext Context { get; } - bool IsNillable { get; } - bool IsReference { get; } - - object GetValue(IXmlNode node, IDictionaryAdapter parentObject, XmlReferenceManager references, bool nodeExists, bool orStub); - void SetValue(IXmlCursor cursor, IDictionaryAdapter parentObject, XmlReferenceManager references, bool hasCurrent, object oldValue, ref object newValue); - - IXmlCollectionAccessor GetCollectionAccessor(Type itemType); - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/IXmlBehaviorSemantics.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/IXmlBehaviorSemantics.cs deleted file mode 100644 index 6e51cb5..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/IXmlBehaviorSemantics.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - - public interface IXmlBehaviorSemantics - { - string GetLocalName (T behavior); - string GetNamespaceUri(T behavior); - Type GetClrType (T behavior); - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/IXmlCollectionAccessor.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/IXmlCollectionAccessor.cs deleted file mode 100644 index 736a2d0..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/IXmlCollectionAccessor.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - using System.Collections; - - public interface IXmlCollectionAccessor : IXmlAccessor - { - IXmlCursor SelectCollectionItems(IXmlNode parentNode, bool mutable); - void GetCollectionItems (IXmlNode parentNode, IDictionaryAdapter parentObject, XmlReferenceManager references, IList values); - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/IXmlPropertyAccessor.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/IXmlPropertyAccessor.cs deleted file mode 100644 index 4582fe9..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/IXmlPropertyAccessor.cs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - - public interface IXmlPropertyAccessor : IXmlAccessor - { - object GetPropertyValue(IXmlNode parentNode, IDictionaryAdapter parentObject, XmlReferenceManager references, bool orStub); - void SetPropertyValue(IXmlNode parentNode, IDictionaryAdapter parentObject, XmlReferenceManager references, object oldValue, ref object newValue); - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XPathBehaviorAccessor.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XPathBehaviorAccessor.cs deleted file mode 100644 index 72910aa..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XPathBehaviorAccessor.cs +++ /dev/null @@ -1,220 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - using System.Xml.XPath; - - public class XPathBehaviorAccessor : XmlAccessor, IXmlIncludedType, IXmlIncludedTypeMap, - IConfigurable, - IConfigurable, - IConfigurable - { - private CompiledXPath path; - private XmlIncludedTypeSet includedTypes; - private XmlAccessor defaultAccessor; - private XmlAccessor itemAccessor; - - internal static readonly XmlAccessorFactory - Factory = (name, type, context) => new XPathBehaviorAccessor(type, context); - - protected XPathBehaviorAccessor(Type type, IXmlContext context) - : base(type, context) - { - includedTypes = new XmlIncludedTypeSet(); - - foreach (var includedType in context.GetIncludedTypes(ClrType)) - includedTypes.Add(includedType); - } - - XmlName IXmlIncludedType.XsiType - { - get { return XmlName.Empty; } - } - - IXmlIncludedType IXmlIncludedTypeMap.Default - { - get { return this; } - } - - private bool SelectsNodes - { - get { return path.Path.ReturnType == XPathResultType.NodeSet; } - } - - private bool CreatesAttributes - { - get { var step = path.LastStep; return step != null && step.IsAttribute; } - } - - public void Configure(XPathAttribute attribute) - { - if (path != null) - throw Error.AttributeConflict(path.Path.Expression); - - path = attribute.SetPath; - - if (path == attribute.GetPath) - return; - else if (Serializer.CanGetStub) - throw Error.SeparateGetterSetterOnComplexType(path.Path.Expression); - - defaultAccessor = new DefaultAccessor(this, attribute.GetPath); - } - - public void Configure(XPathVariableAttribute attribute) - { - CloneContext().AddVariable(attribute); - } - - public void Configure(XPathFunctionAttribute attribute) - { - CloneContext().AddFunction(attribute); - } - - public override void Prepare() - { - if (CreatesAttributes) - state &= ~States.Nillable; - - Context.Enlist(path); - - if (defaultAccessor != null) - defaultAccessor.Prepare(); - } - - public override bool IsPropertyDefined(IXmlNode parentNode) - { - return SelectsNodes - && base.IsPropertyDefined(parentNode); - } - - public override object GetPropertyValue(IXmlNode parentNode, IDictionaryAdapter parentObject, XmlReferenceManager references, bool orStub) - { - return GetPropertyValueCore (parentNode, parentObject, references, orStub) - ?? GetDefaultPropertyValue(parentNode, parentObject, references, orStub); - } - - private object GetPropertyValueCore(IXmlNode parentNode, IDictionaryAdapter parentObject, XmlReferenceManager references, bool orStub) - { - return SelectsNodes - ? base.GetPropertyValue(parentNode, parentObject, references, orStub) - : Evaluate(parentNode); - } - - private object GetDefaultPropertyValue(IXmlNode parentNode, IDictionaryAdapter parentObject, XmlReferenceManager references, bool orStub) - { - return defaultAccessor != null - ? defaultAccessor.GetPropertyValue(parentNode, parentObject, references, orStub) - : null; - } - - private object Evaluate(IXmlNode node) - { - var value = node.Evaluate(path); - return value != null - ? Convert.ChangeType(value, ClrType) - : null; - } - - public override void SetPropertyValue(IXmlNode parentNode, IDictionaryAdapter parentObject, XmlReferenceManager references, object oldValue, ref object value) - { - if (SelectsNodes) - base.SetPropertyValue(parentNode, parentObject, references, oldValue, ref value); - else - throw Error.XPathNotCreatable(path); - } - - public override IXmlCollectionAccessor GetCollectionAccessor(Type itemType) - { - return itemAccessor ?? (itemAccessor = new ItemAccessor(this)); - } - - public override IXmlCursor SelectPropertyNode(IXmlNode node, bool create) - { - var flags = CursorFlags.AllNodes.MutableIf(create); - return node.Select(path, this, Context, flags); - } - - public override IXmlCursor SelectCollectionNode(IXmlNode node, bool create) - { - return node.SelectSelf(ClrType); - } - - public override IXmlCursor SelectCollectionItems(IXmlNode node, bool create) - { - var flags = CursorFlags.AllNodes.MutableIf(create) | CursorFlags.Multiple; - return node.Select(path, this, Context, flags); - } - - public bool TryGet(XmlName xsiType, out IXmlIncludedType includedType) - { - if (xsiType == XmlName.Empty || xsiType == this.XsiType) - return Try.Success(out includedType, this); - - if (!includedTypes.TryGet(xsiType, out includedType)) - return false; - - if (!ClrType.IsAssignableFrom(includedType.ClrType)) - return Try.Failure(out includedType); - - return true; - } - - public bool TryGet(Type clrType, out IXmlIncludedType includedType) - { - return clrType == this.ClrType - ? Try.Success(out includedType, this) - : includedTypes.TryGet(clrType, out includedType); - } - - private class DefaultAccessor : XPathBehaviorAccessor - { - private readonly XPathBehaviorAccessor parent; - - public DefaultAccessor(XPathBehaviorAccessor parent, CompiledXPath path) - : base(parent.ClrType, parent.Context) - { - this.parent = parent; - this.path = path; - } - - public override void Prepare() - { - this.includedTypes = parent.includedTypes; - this.Context = parent.Context; - - base.Prepare(); - } - } - - private class ItemAccessor : XPathBehaviorAccessor - { - public ItemAccessor(XPathBehaviorAccessor parent) - : base(parent.ClrType.GetCollectionItemType(), parent.Context) - { - includedTypes = parent.includedTypes; - path = parent.path; - - ConfigureNillable(true); - } - - public override IXmlCollectionAccessor GetCollectionAccessor(Type itemType) - { - return GetDefaultCollectionAccessor(itemType); - } - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlAccessor.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlAccessor.cs deleted file mode 100644 index 3057b3c..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlAccessor.cs +++ /dev/null @@ -1,345 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - using System.Collections; - - public abstract class XmlAccessor : IXmlPropertyAccessor, IXmlCollectionAccessor - { - private readonly Type clrType; - private readonly XmlName xsiType; - private readonly XmlTypeSerializer serializer; - private IXmlContext context; - protected States state; - - protected XmlAccessor(Type clrType, IXmlContext context) - { - if (clrType == null) - throw Error.ArgumentNull(nameof(clrType)); - if (context == null) - throw Error.ArgumentNull(nameof(context)); - - clrType = clrType.NonNullable(); - this.clrType = clrType; - this.xsiType = context.GetDefaultXsiType(clrType); - this.serializer = XmlTypeSerializer.For(clrType); - this.context = context; - } - - public Type ClrType - { - get { return clrType; } - } - - public XmlName XsiType - { - get { return xsiType; } - } - - public XmlTypeSerializer Serializer - { - get { return serializer; } - } - - public IXmlContext Context - { - get { return context; } - protected set { SetContext(value); } - } - - public bool IsCollection - { - get { return serializer.Kind == XmlTypeKind.Collection; } - } - - public virtual bool IsIgnored - { - get { return false; } - } - - public bool IsNillable - { - get { return 0 != (state & States.Nillable); } - } - - public bool IsVolatile - { - get { return 0 != (state & States.Volatile); } - } - - public bool IsReference - { - get { return 0 != (state & States.Reference); } - } - - public virtual void ConfigureNillable(bool nillable) - { - if (nillable) - state |= States.Nillable; - } - - public void ConfigureVolatile(bool isVolatile) - { - if (isVolatile) - state |= States.Volatile; - } - - public virtual void ConfigureReference(bool isReference) - { - if (isReference) - state |= States.Reference; - } - - public virtual void Prepare() - { - // Do nothing - } - - protected IXmlContext CloneContext() - { - if (0 == (state & States.ConfiguredContext)) - { - context = context.Clone(); - state |= States.ConfiguredContext; - } - return context; - } - - private void SetContext(IXmlContext value) - { - if (null == value) - throw Error.ArgumentNull(nameof(value)); - - context = value; - } - - public virtual bool IsPropertyDefined(IXmlNode parentNode) - { - var cursor = IsCollection - ? SelectCollectionNode(parentNode, false) - : SelectPropertyNode (parentNode, false); - - return cursor.MoveNext(); - } - - public virtual object GetPropertyValue(IXmlNode parentNode, IDictionaryAdapter parentObject, XmlReferenceManager references, bool orStub) - { - if (orStub) orStub &= serializer.CanGetStub; - - var cursor = IsCollection - ? SelectCollectionNode(parentNode, orStub) - : SelectPropertyNode (parentNode, orStub); - - return GetValue(cursor, parentObject, references, cursor.MoveNext(), orStub); - } - - public object GetValue(IXmlNode node, IDictionaryAdapter parentObject, XmlReferenceManager references, bool nodeExists, bool orStub) - { - object value; - - if ((nodeExists || orStub) && IsReference) - { - value = null; - object token; - - if (references.OnGetStarting(ref node, ref value, out token)) - { - value = GetValueCore(node, parentObject, nodeExists, orStub); - references.OnGetCompleted(node, value, token); - } - } - else - { - value = GetValueCore(node, parentObject, nodeExists, orStub); - } - return value; - } - - private object GetValueCore(IXmlNode node, IDictionaryAdapter parentObject, bool nodeExists, bool orStub) - { - if (nodeExists) - if (!node.IsNil) - return serializer.GetValue(node, parentObject, this); - else if (IsNillable) - return null; - - return orStub - ? serializer.GetStub(node, parentObject, this) - : null; - } - - public virtual void SetPropertyValue(IXmlNode parentNode, IDictionaryAdapter parentObject, XmlReferenceManager references, - object oldValue, ref object value) - { - var cursor = IsCollection - ? SelectCollectionNode(parentNode, true) - : SelectPropertyNode (parentNode, true); - - SetValue(cursor, parentObject, references, cursor.MoveNext(), oldValue, ref value); - } - - public virtual void SetValue(IXmlCursor cursor, IDictionaryAdapter parentObject, XmlReferenceManager references, - bool hasCurrent, object oldValue, ref object newValue) - { - var hasValue = null != newValue; - var isNillable = this.IsNillable; - var isReference = this.IsReference; - - var clrType = hasValue - ? newValue.GetComponentType() - : this.clrType; - - if (hasValue || isNillable) - { - if (hasCurrent) - Coerce(cursor, clrType, !hasValue && cursor.IsAttribute); // TODO: Refactor. (NB: && isNillable is implied) - else - cursor.Create(clrType); - } - else if (!hasCurrent) - { - // No node exists + no value to assign + and not nillable = no work to do - return; - } - - object token = null; - if (isReference) - if (!references.OnAssigningValue(cursor, oldValue, ref newValue, out token)) - return; - - var givenValue = newValue; - - if (hasValue) - serializer.SetValue(cursor, parentObject, this, oldValue, ref newValue); - else if (isNillable) - cursor.IsNil = true; - else - { cursor.Remove(); cursor.RemoveAllNext(); } - - if (isReference) - references.OnAssignedValue(cursor, givenValue, newValue, token); - } - - private void Coerce(IXmlCursor cursor, Type clrType, bool replace) - { - if (replace) - { - cursor.Remove(); - cursor.MoveNext(); - cursor.Create(ClrType); - } - else cursor.Coerce(clrType); - } - - public void GetCollectionItems(IXmlNode parentNode, IDictionaryAdapter parentObject, XmlReferenceManager references, IList values) - { - var cursor = SelectCollectionItems(parentNode, false); - - while (cursor.MoveNext()) - { - object value; - - if (IsReference) - { - IXmlNode node = cursor; - value = null; - object token; - - if (references.OnGetStarting(ref node, ref value, out token)) - { - value = serializer.GetValue(node, parentObject, this); - references.OnGetCompleted(node, value, token); - } - } - else - { - value = serializer.GetValue(cursor, parentObject, this); - } - values.Add(value); - } - } - - protected void RemoveCollectionItems(IXmlNode parentNode, XmlReferenceManager references, object value) - { - var collection = value as ICollectionProjection; - if (collection != null) - { - collection.Clear(); - return; - } - - var itemType = clrType.GetCollectionItemType(); - var accessor = GetCollectionAccessor(itemType); - var cursor = accessor.SelectCollectionItems(parentNode, true); - var isReference = IsReference; - - var items = value as IEnumerable; - if (items != null) - { - foreach (var item in items) - { - if (!cursor.MoveNext()) - break; - if (isReference) - references.OnAssigningNull(cursor, item); - } - } - - cursor.Reset(); - cursor.RemoveAllNext(); - } - - public virtual IXmlCollectionAccessor GetCollectionAccessor(Type itemType) - { - return GetDefaultCollectionAccessor(itemType); - } - - protected IXmlCollectionAccessor GetDefaultCollectionAccessor(Type itemType) - { - var accessor = new XmlDefaultBehaviorAccessor(itemType, Context); - accessor.ConfigureNillable (true); - accessor.ConfigureReference(IsReference); - return accessor; - } - - public virtual IXmlCursor SelectPropertyNode(IXmlNode parentNode, bool mutable) - { - throw Error.NotSupported(); - } - - public virtual IXmlCursor SelectCollectionNode(IXmlNode parentNode, bool mutable) - { - return SelectPropertyNode(parentNode, mutable); - } - - public virtual IXmlCursor SelectCollectionItems(IXmlNode parentNode, bool mutable) - { - throw Error.NotSupported(); - } - - [Flags] - protected enum States - { - Nillable = 0x01, // Set a null value as xsi:nil='true' - Volatile = 0x02, // Always get value from XML store; don't cache it - Reference = 0x04, // Participate in reference tracking - ConfiguredContext = 0x08, // Have created our own IXmlContext instance - ConfiguredLocalName = 0x10, // The local name has been configured - ConfiguredNamespaceUri = 0x20, // The namespace URI has been configured - ConfiguredKnownTypes = 0x40, // Known types have been configured from attributes - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlAccessorFactory.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlAccessorFactory.cs deleted file mode 100644 index daade16..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlAccessorFactory.cs +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - - public delegate TAccessor - XmlAccessorFactory(string name, Type type, IXmlContext context) - where TAccessor : XmlAccessor; -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlArrayBehaviorAccessor.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlArrayBehaviorAccessor.cs deleted file mode 100644 index c0a28aa..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlArrayBehaviorAccessor.cs +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - using System.Collections.Generic; - using System.Xml.Serialization; - - public class XmlArrayBehaviorAccessor : XmlNodeAccessor, - IConfigurable, - IConfigurable - { - private readonly ItemAccessor itemAccessor; - - internal static readonly XmlAccessorFactory - Factory = (name, type, context) => new XmlArrayBehaviorAccessor(name, type, context); - - public XmlArrayBehaviorAccessor(string name, Type type, IXmlContext context) - : base(name, type, context) - { - if (Serializer.Kind != XmlTypeKind.Collection) - throw Error.AttributeConflict(name); - - itemAccessor = new ItemAccessor(ClrType.GetCollectionItemType(), this); - } - - public void Configure(XmlArrayAttribute attribute) - { - ConfigureLocalName (attribute.ElementName); - ConfigureNamespaceUri(attribute.Namespace ); - ConfigureNillable (attribute.IsNullable ); - } - - public void Configure(XmlArrayItemAttribute attribute) - { - itemAccessor.Configure(attribute); - } - - public override void Prepare() - { - base.Prepare(); - itemAccessor.Prepare(); - } - - public override IXmlCollectionAccessor GetCollectionAccessor(Type itemType) - { - return itemAccessor; - } - - public override IXmlCursor SelectPropertyNode(IXmlNode node, bool mutable) - { - return node.SelectChildren(this, Context, PropertyFlags.MutableIf(mutable)); - } - - private class ItemAccessor : XmlNodeAccessor, - IConfigurable, - IXmlBehaviorSemantics - { - private List attributes; - - public ItemAccessor(Type itemClrType, XmlNodeAccessor accessor) - : base(itemClrType, accessor.Context) - { - ConfigureNillable(true); - ConfigureReference(accessor.IsReference); - } - - public void Configure(XmlArrayItemAttribute attribute) - { - if (attribute.Type == null) - { - ConfigureLocalName (attribute.ElementName); - ConfigureNamespaceUri(attribute.Namespace ); - ConfigureNillable (attribute.IsNullable ); - } - else - { - if (attributes == null) - attributes = new List(); - attributes.Add(attribute); - } - } - - public override void Prepare() - { - if (attributes != null) - { - ConfigureKnownTypesFromAttributes(attributes, this); - attributes = null; - } - base.Prepare(); - } - - public override IXmlCursor SelectCollectionItems(IXmlNode node, bool mutable) - { - return node.SelectChildren(KnownTypes, Context, CollectionItemFlags.MutableIf(mutable)); - } - - public string GetLocalName(XmlArrayItemAttribute attribute) - { - return attribute.ElementName; - } - - public string GetNamespaceUri(XmlArrayItemAttribute attribute) - { - return attribute.Namespace; - } - - public Type GetClrType(XmlArrayItemAttribute attribute) - { - return attribute.Type; - } - } - - private const CursorFlags - PropertyFlags = CursorFlags.Elements, - CollectionItemFlags = CursorFlags.Elements | CursorFlags.Multiple; - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlAttributeBehaviorAccessor.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlAttributeBehaviorAccessor.cs deleted file mode 100644 index 311145e..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlAttributeBehaviorAccessor.cs +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - using System.Xml.Serialization; - - public class XmlAttributeBehaviorAccessor : XmlNodeAccessor, - IConfigurable - { - internal static readonly XmlAccessorFactory - Factory = (name, type, context) => new XmlAttributeBehaviorAccessor(name, type, context); - - public XmlAttributeBehaviorAccessor(string name, Type type, IXmlContext context) - : base(name, type, context) - { - if (Serializer.Kind != XmlTypeKind.Simple) - throw Error.NotSupported(); - } - - public void Configure(XmlAttributeAttribute attribute) - { - ConfigureLocalName (attribute.AttributeName); - ConfigureNamespaceUri(attribute.Namespace); - } - - public override void ConfigureNillable(bool nillable) - { - // Attributes are never nillable - } - - public override void ConfigureReference(bool isReference) - { - // Attributes cannot store references - } - - public override IXmlCollectionAccessor GetCollectionAccessor(Type itemType) - { - throw Error.NotSupported(); - } - - public override IXmlCursor SelectPropertyNode(IXmlNode node, bool mutable) - { - return node.SelectChildren(this, Context, CursorFlags.Attributes.MutableIf(mutable)); - } - - public override IXmlCursor SelectCollectionNode(IXmlNode node, bool mutable) - { - throw Error.NotSupported(); - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlDefaultBehaviorAccessor.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlDefaultBehaviorAccessor.cs deleted file mode 100644 index ecd7474..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlDefaultBehaviorAccessor.cs +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - using System.Xml; - - public class XmlDefaultBehaviorAccessor : XmlNodeAccessor - { - internal static readonly XmlAccessorFactory - Factory = (name, type, context) => new XmlDefaultBehaviorAccessor(name, type, context); - - public XmlDefaultBehaviorAccessor(Type type, IXmlContext context) - : base(type, context) { } - - public XmlDefaultBehaviorAccessor(string name, Type type, IXmlContext context) - : base(name, type, context) { } - - public override IXmlCursor SelectPropertyNode(IXmlNode node, bool mutable) - { - var flags = Serializer.Kind == XmlTypeKind.Simple - ? CursorFlags.AllNodes - : CursorFlags.Elements; - return node.SelectChildren(KnownTypes, Context, flags.MutableIf(mutable)); - } - - public override IXmlCursor SelectCollectionNode(IXmlNode node, bool mutable) - { - return SelectPropertyNode(node, mutable); - } - - public override IXmlCursor SelectCollectionItems(IXmlNode node, bool mutable) - { - var flags = CursorFlags.Elements | CursorFlags.Multiple; - return node.SelectChildren(KnownTypes, Context, flags.MutableIf(mutable)); - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlElementBehaviorAccessor.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlElementBehaviorAccessor.cs deleted file mode 100644 index 750b2e4..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlElementBehaviorAccessor.cs +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - using System.Collections.Generic; - using System.Xml.Serialization; - - public class XmlElementBehaviorAccessor : XmlNodeAccessor, - IConfigurable, - IXmlBehaviorSemantics - { - private ItemAccessor itemAccessor; - private List attributes; - - internal static readonly XmlAccessorFactory - Factory = (name, type, context) => new XmlElementBehaviorAccessor(name, type, context); - - public XmlElementBehaviorAccessor(string name, Type type, IXmlContext context) - : base(name, type, context) { } - - public void Configure(XmlElementAttribute attribute) - { - if (attribute.Type == null) - { - ConfigureLocalName (attribute.ElementName); - ConfigureNamespaceUri(attribute.Namespace ); - ConfigureNillable (attribute.IsNullable ); - } - else - { - if (attributes == null) - attributes = new List(); - attributes.Add(attribute); - } - } - - public override void Prepare() - { - if (attributes != null) - { - ConfigureKnownTypesFromAttributes(attributes, this); - attributes = null; - } - base.Prepare(); - } - - public override void SetValue(IXmlCursor cursor, IDictionaryAdapter parentObject, XmlReferenceManager references, - bool hasCurrent, object oldValue, ref object newValue) - { - if (newValue == null && IsCollection) - base.RemoveCollectionItems(cursor, references, oldValue); - else - base.SetValue(cursor, parentObject, references, hasCurrent, oldValue, ref newValue); - } - - public override IXmlCollectionAccessor GetCollectionAccessor(Type itemType) - { - return itemAccessor ?? (itemAccessor = new ItemAccessor(this)); - } - - public override IXmlCursor SelectPropertyNode(IXmlNode node, bool mutable) - { - return node.SelectChildren(KnownTypes, Context, CursorFlags.Elements.MutableIf(mutable)); - } - - public override IXmlCursor SelectCollectionNode(IXmlNode node, bool mutable) - { - return node.SelectSelf(ClrType); - } - - public string GetLocalName(XmlElementAttribute attribute) - { - return attribute.ElementName; - } - - public string GetNamespaceUri(XmlElementAttribute attribute) - { - return attribute.Namespace; - } - - public Type GetClrType(XmlElementAttribute attribute) - { - return attribute.Type; - } - - private class ItemAccessor : XmlNodeAccessor - { - public ItemAccessor(XmlNodeAccessor parent) - : base(parent.ClrType.GetCollectionItemType(), parent.Context) - { - ConfigureLocalName (parent.Name.LocalName ); - ConfigureNamespaceUri(parent.Name.NamespaceUri); - ConfigureNillable (parent.IsNillable ); - ConfigureReference (parent.IsReference ); - ConfigureKnownTypesFromParent(parent); - } - - public override void Prepare() - { - // Don't prepare; parent already did it - } - - public override IXmlCursor SelectCollectionItems(IXmlNode node, bool mutable) - { - return node.SelectChildren(KnownTypes, Context, CursorFlags.Elements.MutableIf(mutable) | CursorFlags.Multiple); - } - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlIgnoreBehaviorAccessor.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlIgnoreBehaviorAccessor.cs deleted file mode 100644 index 29a5468..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlIgnoreBehaviorAccessor.cs +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - using System.Collections.Generic; - using System.Linq; - - public class XmlIgnoreBehaviorAccessor : XmlAccessor - { - public static readonly XmlIgnoreBehaviorAccessor - Instance = new XmlIgnoreBehaviorAccessor(); - - private XmlIgnoreBehaviorAccessor() - : base(typeof(object), DummyContext.Instance) { } - - public override bool IsIgnored - { - get { return true; } - } - - public override IXmlCollectionAccessor GetCollectionAccessor(Type itemType) - { - throw Error.NotSupported(); - } - - public override IXmlCursor SelectPropertyNode(IXmlNode node, bool mutable) - { - throw Error.NotSupported(); - } - - public override IXmlCursor SelectCollectionNode(IXmlNode node, bool mutable) - { - throw Error.NotSupported(); - } - - public override IXmlCursor SelectCollectionItems(IXmlNode node, bool mutable) - { - throw Error.NotSupported(); - } - - private sealed class DummyContext : IXmlContext - { - public static DummyContext Instance = new DummyContext(); - - private DummyContext() { } - - public string ChildNamespaceUri - { - get { return null; } - } - - public IXmlContext Clone() - { - return this; - } - - public bool IsReservedNamespaceUri(string namespaceUri) - { - return false; - } - - public XmlName GetDefaultXsiType(Type clrType) - { - return new XmlName("anyType", Xsd.NamespaceUri); - } - - public IEnumerable GetIncludedTypes(Type baseType) - { - throw Error.NotSupported(); - } - - public void Enlist(CompiledXPath path) - { - throw Error.NotSupported(); - } - - public string GetElementPrefix(IXmlNode node, string namespaceUri) - { - throw Error.NotSupported(); - } - - public string GetAttributePrefix(IXmlNode node, string namespaceUri) - { - throw Error.NotSupported(); - } - - public void AddVariable(XPathVariableAttribute attribute) - { - throw Error.NotSupported(); - } - - public void AddFunction(XPathFunctionAttribute attribute) - { - throw Error.NotSupported(); - } - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlNodeAccessor.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlNodeAccessor.cs deleted file mode 100644 index 98515cd..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlNodeAccessor.cs +++ /dev/null @@ -1,223 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - using System.Collections; - using System.Collections.Generic; - using System.Xml; - - public abstract class XmlNodeAccessor : XmlAccessor, IXmlKnownType, IXmlKnownTypeMap - { - private string localName; - private string namespaceUri; - private XmlKnownTypeSet knownTypes; - - protected XmlNodeAccessor(Type type, IXmlContext context) - : this(context.GetDefaultXsiType(type).LocalName, type, context) { } - - protected XmlNodeAccessor(string name, Type type, IXmlContext context) - : base(type, context) - { - if (name == null) - throw Error.ArgumentNull(nameof(name)); - if (name == string.Empty) - throw Error.InvalidLocalName(); - - localName = XmlConvert.EncodeLocalName(name); - namespaceUri = context.ChildNamespaceUri; - } - - public XmlName Name - { - get { return new XmlName(localName, namespaceUri); } - } - - XmlName IXmlIdentity.XsiType - { - get { return XmlName.Empty; } - } - - protected IXmlKnownTypeMap KnownTypes - { - get - { - if (knownTypes != null) - return knownTypes; - return this; - } - } - - IXmlKnownType IXmlKnownTypeMap.Default - { - get { return this; } - } - - public bool TryGet(IXmlIdentity xmlName, out IXmlKnownType knownType) - { - return IsMatch(xmlName) - ? Try.Success(out knownType, this) - : Try.Failure(out knownType); - } - - public bool TryGet(Type clrType, out IXmlKnownType knownType) - { - return IsMatch(clrType) - ? Try.Success(out knownType, this) - : Try.Failure(out knownType); - } - - protected virtual bool IsMatch(IXmlIdentity xmlIdentity) - { - return NameComparer.Equals(localName, xmlIdentity.Name.LocalName) - && IsMatchOnNamespaceUri(xmlIdentity) - && IsMatchOnXsiType (xmlIdentity); - } - - private bool IsMatchOnNamespaceUri(IXmlIdentity xmlIdentity) - { - var otherNamespaceUri = xmlIdentity.Name.NamespaceUri; - if (Context.IsReservedNamespaceUri(otherNamespaceUri)) - return NameComparer.Equals(namespaceUri, otherNamespaceUri); - return namespaceUri == null - || ShouldIgnoreAttributeNamespaceUri(xmlIdentity) - || NameComparer.Equals(namespaceUri, otherNamespaceUri); - } - - private bool IsMatchOnXsiType(IXmlIdentity xmlIdentity) - { - var otherXsiType = xmlIdentity.XsiType; - return otherXsiType == XmlName.Empty - || otherXsiType == XsiType; - } - - private bool ShouldIgnoreAttributeNamespaceUri(IXmlIdentity xmlName) - { - var xmlNode = xmlName as IXmlNode; - return xmlNode != null - && xmlNode.IsAttribute - && 0 == (state & States.ConfiguredNamespaceUri); - } - - protected virtual bool IsMatch(Type clrType) - { - return clrType == this.ClrType - || ( Serializer.Kind == XmlTypeKind.Collection - && typeof(IEnumerable).IsAssignableFrom(clrType) ); - } - - protected void ConfigureLocalName(string localName) - { - ConfigureField(ref this.localName, localName, States.ConfiguredLocalName); - } - - protected void ConfigureNamespaceUri(string namespaceUri) - { - ConfigureField(ref this.namespaceUri, namespaceUri, States.ConfiguredNamespaceUri); - } - - private void ConfigureField(ref string field, string value, States mask) - { - if (string.IsNullOrEmpty(value)) - return; - if (0 != (state & mask)) - throw Error.AttributeConflict(localName); - field = value; - state |= mask; - } - - protected void ConfigureKnownTypesFromParent(XmlNodeAccessor accessor) - { - if (knownTypes != null) - throw Error.AttributeConflict(localName); - - knownTypes = accessor.knownTypes; - } - - protected void ConfigureKnownTypesFromAttributes(IEnumerable attributes, IXmlBehaviorSemantics semantics) - { - foreach (var attribute in attributes) - { - var clrType = semantics.GetClrType(attribute); - if (clrType != null) - { - var xsiType = Context.GetDefaultXsiType(clrType); - - var name = new XmlName( - semantics.GetLocalName (attribute).NonEmpty() ?? xsiType.LocalName, - semantics.GetNamespaceUri(attribute) ?? namespaceUri); - - AddKnownType(name, xsiType, clrType, true); - } - } - } - - public override void Prepare() - { - if (knownTypes == null) - ConfigureIncludedTypes(this); - else - ConfigureDefaultAndIncludedTypes(); - } - - private void ConfigureDefaultAndIncludedTypes() - { - var configuredKnownTypes = knownTypes.ToArray(); - - knownTypes.AddXsiTypeDefaults(); - - foreach (var knownType in configuredKnownTypes) - ConfigureIncludedTypes(knownType); - } - - private void ConfigureIncludedTypes(IXmlKnownType knownType) - { - var includedTypes = Context.GetIncludedTypes(knownType.ClrType); - - foreach (var include in includedTypes) - AddKnownType(knownType.Name, include.XsiType, include.ClrType, false); - } - - private void AddKnownType(XmlName name, XmlName xsiType, Type clrType, bool overwrite) - { - if (knownTypes == null) - { - knownTypes = new XmlKnownTypeSet(ClrType); - AddSelfAsKnownType(); - } - knownTypes.Add(new XmlKnownType(name, xsiType, clrType), overwrite); - } - - private void AddSelfAsKnownType() - { - var mask - = States.ConfiguredLocalName - | States.ConfiguredNamespaceUri - | States.ConfiguredKnownTypes; - - var selfIsKnownType - = (state & mask) != States.ConfiguredKnownTypes; - - if (selfIsKnownType) - { - knownTypes.Add(new XmlKnownType(Name, XsiType, ClrType), true); - knownTypes.Add(new XmlKnownType(Name, XmlName.Empty, ClrType), true); - } - } - - protected static readonly StringComparer - NameComparer = StringComparer.OrdinalIgnoreCase; - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlSelfAccessor.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlSelfAccessor.cs deleted file mode 100644 index 51f2ce8..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Accessors/XmlSelfAccessor.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - - public class XmlSelfAccessor : XmlAccessor - { - internal static readonly XmlAccessorFactory - Factory = (name, type, context) => new XmlSelfAccessor(type, context); - - public XmlSelfAccessor(Type clrType, IXmlContext context) - : base(clrType, context) { } - - public override void ConfigureNillable(bool nillable) - { - // This behavior cannot support nillable - } - - public override IXmlCursor SelectPropertyNode(IXmlNode parentNode, bool mutable) - { - return parentNode.SelectSelf(ClrType); - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Collections/XmlCollectionAdapter.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Collections/XmlCollectionAdapter.cs deleted file mode 100644 index 0b825e5..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Collections/XmlCollectionAdapter.cs +++ /dev/null @@ -1,258 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - using System.Collections.Generic; - - internal class XmlCollectionAdapter : ICollectionAdapter, IXmlNodeSource - { - private List> items; - private List> snapshot; - private ICollectionAdapterObserver advisor; - - private readonly IXmlCursor cursor; - private readonly IXmlCollectionAccessor accessor; - private readonly IXmlNode parentNode; - private readonly IDictionaryAdapter parentObject; - private readonly XmlReferenceManager references; - - public XmlCollectionAdapter( - IXmlNode parentNode, - IDictionaryAdapter parentObject, - IXmlCollectionAccessor accessor) - { - items = new List>(); - - this.accessor = accessor; - this.cursor = accessor.SelectCollectionItems(parentNode, true); - this.parentNode = parentNode; - this.parentObject = parentObject; - this.references = XmlAdapter.For(parentObject).References; - - while (cursor.MoveNext()) - items.Add(new XmlCollectionItem(cursor.Save())); - } - - public IXmlNode Node - { - get { return parentNode; } - } - - public XmlReferenceManager References - { - get { return references; } - } - - public int Count - { - get { return items.Count; } - } - - public void Initialize(ICollectionAdapterObserver advisor) - { - this.advisor = advisor; - } - - public T this[int index] - { - get - { - var item = items[index]; - - if (!item.HasValue) - items[index] = item = item.WithValue(GetValue(item.Node)); - - return item.Value; - } - set - { - var item = items[index]; - cursor.MoveTo(item.Node); - SetValue(cursor, item.Value, ref value); - - if (advisor.OnReplacing(item.Value, value)) - { - // Commit the replacement - items[index] = item.WithValue(value); - advisor.OnReplaced(item.Value, value, index); - } - else - { - // Rollback the replacement - var oldValue = item.Value; - SetValue(cursor, value, ref oldValue); - items[index] = item.WithValue(oldValue); - } - } - } - - public T AddNew() - { - cursor.MoveToEnd(); - cursor.Create(typeof(T)); - - var node = cursor.Save(); - var value = GetValue(node); - var index = items.Count; - - CommitInsert(index, node, value, true); - return (T) value; - } - - public bool Add(T value) - { - return InsertCore(Count, value, append: true); - } - - public bool Insert(int index, T value) - { - return InsertCore(index, value, append: false); - } - - private bool InsertCore(int index, T value, bool append) - { - if (append) - cursor.MoveToEnd(); - else - cursor.MoveTo(items[index].Node); - - cursor.Create(GetTypeOrDefault(value)); - var node = cursor.Save(); - SetValue(cursor, default(T), ref value); - - return advisor.OnInserting(value) - ? CommitInsert(index, node, value, append) - : RollbackInsert(); - } - - private bool CommitInsert(int index, IXmlNode node, T value, bool append) - { - var item = new XmlCollectionItem(node, value); - - if (append) - items.Add(item); - else - items.Insert(index, item); - - advisor.OnInserted(value, index); - return true; - } - - private bool RollbackInsert() - { - cursor.Remove(); - return false; - } - - public void Remove(int index) - { - var item = items[index]; - OnRemoving(item); - - cursor.MoveTo(item.Node); - cursor.Remove(); - items.RemoveAt(index); - - advisor.OnRemoved(item.Value, index); - } - - public void Clear() - { - foreach (var item in items) - OnRemoving(item); - - cursor.Reset(); - cursor.RemoveAllNext(); - items.Clear(); - - // Don't call OnRemoved. Caller is already going to fire a Reset shortly. - } - - public void ClearReferences() - { - if (accessor.IsReference) - foreach (var item in items) - references.OnAssigningNull(item.Node, item.Value); - } - - private void OnRemoving(XmlCollectionItem item) - { - advisor.OnRemoving(item.Value); - - if (accessor.IsReference) - references.OnAssigningNull(item.Node, item.Value); - } - - private T GetValue(IXmlNode node) - { - return (T) (accessor.GetValue(node, parentObject, references, true, true) ?? default(T)); - } - - private void SetValue(IXmlCursor cursor, object oldValue, ref T value) - { - object obj = value; - accessor.SetValue(cursor, parentObject, references, true, oldValue, ref obj); - value = (T) (obj ?? default(T)); - } - - private static Type GetTypeOrDefault(T value) - { - return (null == value) - ? typeof(T) - : value.GetComponentType(); - } - - public IEqualityComparer Comparer - { - get { return null; } - } - - public bool HasSnapshot - { - get { return snapshot != null; } - } - - public int SnapshotCount - { - get { return snapshot.Count; } - } - - public T GetCurrentItem(int index) - { - return items[index].Value; - } - - public T GetSnapshotItem(int index) - { - return snapshot[index].Value; - } - - public void SaveSnapshot() - { - snapshot = new List>(items); - } - - public void LoadSnapshot() - { - items = snapshot; - } - - public void DropSnapshot() - { - snapshot = null; - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Collections/XmlCollectionItem.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Collections/XmlCollectionItem.cs deleted file mode 100644 index 1fd1cbd..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Collections/XmlCollectionItem.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - internal struct XmlCollectionItem - { - public readonly IXmlNode Node; - public readonly T Value; - public readonly bool HasValue; - - public XmlCollectionItem(IXmlNode node) - : this(node, default(T), false) { } - - public XmlCollectionItem(IXmlNode node, T value) - : this(node, value, true) { } - - private XmlCollectionItem(IXmlNode node, T value, bool hasValue) - { - Node = node; - Value = value; - HasValue = hasValue; - } - - public XmlCollectionItem WithValue(T value) - { - return new XmlCollectionItem(Node, value); - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Collections/XmlNodeList.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Collections/XmlNodeList.cs deleted file mode 100644 index a66bbfd..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Collections/XmlNodeList.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - internal class XmlNodeList : ListProjection, IXmlNodeSource - { - public XmlNodeList - ( - IXmlNode parentNode, - IDictionaryAdapter parentObject, - IXmlCollectionAccessor accessor - ) - : base - ( - new XmlCollectionAdapter - ( - parentNode, - parentObject, - accessor - ) - ) - { } - - public IXmlNode Node - { - get { return ((IXmlNodeSource)Adapter).Node; } - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Collections/XmlNodeSet.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Collections/XmlNodeSet.cs deleted file mode 100644 index efc47c8..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Collections/XmlNodeSet.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - internal class XmlNodeSet : SetProjection, IXmlNodeSource - { - public XmlNodeSet - ( - IXmlNode parentNode, - IDictionaryAdapter parentObject, - IXmlCollectionAccessor accessor - ) - : base - ( - new XmlCollectionAdapter - ( - parentNode, - parentObject, - accessor - ) - ) - { } - - public IXmlNode Node - { - get { return ((IXmlNodeSource)Adapter).Node; } - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/CursorFlags.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/CursorFlags.cs deleted file mode 100644 index 4e5c314..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/CursorFlags.cs +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - - [Flags] - public enum CursorFlags - { - None = 0, - Elements = 1, - Attributes = 2, - Multiple = 4, - Mutable = 8, - AllNodes = Elements | Attributes - } - - public static class CursorFlagsExtensions - { - public static CursorFlags MutableIf(this CursorFlags flags, bool mutable) - { - return mutable ? (flags | CursorFlags.Mutable) : flags; - } - - public static bool IncludesElements(this CursorFlags flags) - { - return 0 != (flags & CursorFlags.Elements); - } - - public static bool IncludesAttributes(this CursorFlags flags) - { - return 0 != (flags & CursorFlags.Attributes); - } - - public static bool AllowsMultipleItems(this CursorFlags flags) - { - return 0 != (flags & CursorFlags.Multiple); - } - - public static bool SupportsMutation(this CursorFlags flags) - { - return 0 != (flags & CursorFlags.Mutable); - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/IXmlContext.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/IXmlContext.cs deleted file mode 100644 index 18bdbb2..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/IXmlContext.cs +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - using System.Collections.Generic; - - public interface IXmlContext : IXmlNamespaceSource - { - string ChildNamespaceUri { get; } - - IXmlContext Clone(); - XmlName GetDefaultXsiType(Type clrType); - IEnumerable GetIncludedTypes(Type baseType); - bool IsReservedNamespaceUri(string namespaceUri); - - void AddVariable(XPathVariableAttribute attribute); - void AddFunction(XPathFunctionAttribute attribute); - void Enlist(CompiledXPath path); - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/IXmlCursor.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/IXmlCursor.cs deleted file mode 100644 index 0a359c7..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/IXmlCursor.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - - public interface IXmlCursor : IXmlIterator - { - void Reset(); - void MoveTo(IXmlNode node); - void MoveToEnd(); - - void Create(Type type); - void Coerce(Type type); - void Remove(); - void RemoveAllNext(); - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/IXmlIterator.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/IXmlIterator.cs deleted file mode 100644 index 6be4cc2..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/IXmlIterator.cs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - - public interface IXmlIterator : IXmlNode - { - bool MoveNext(); - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/IXmlNamespaceSource.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/IXmlNamespaceSource.cs deleted file mode 100644 index 6afb05f..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/IXmlNamespaceSource.cs +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - public interface IXmlNamespaceSource - { - string GetElementPrefix (IXmlNode node, string namespaceUri); - string GetAttributePrefix(IXmlNode node, string namespaceUri); - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/IXmlNode.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/IXmlNode.cs deleted file mode 100644 index 1b7d7e1..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/IXmlNode.cs +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - using System.Xml; - - public interface IXmlNode : IXmlKnownType, IRealizableSource, IVirtual - { - bool IsElement { get; } - bool IsAttribute { get; } - bool IsNil { get; set; } - string Value { get; set; } // Equivalent to InnerText - string Xml { get; } // Equivalent to OuterXml - - IXmlNode Parent { get; } - IXmlNamespaceSource Namespaces { get; } - - string GetAttribute(XmlName name); - void SetAttribute(XmlName name, string value); - - string LookupPrefix (string namespaceUri); - string LookupNamespaceUri(string prefix); - void DefineNamespace (string prefix, string namespaceUri, bool root); - - object UnderlyingObject { get; } - bool UnderlyingPositionEquals(IXmlNode node); - - IXmlNode Save(); - IXmlCursor SelectSelf(Type clrType); - IXmlCursor SelectChildren(IXmlKnownTypeMap knownTypes, IXmlNamespaceSource namespaces, CursorFlags flags); - IXmlIterator SelectSubtree(); - - CompiledXPath Path { get; } - IXmlCursor Select (CompiledXPath path, IXmlIncludedTypeMap includedTypes, IXmlNamespaceSource namespaces, CursorFlags flags); - object Evaluate(CompiledXPath path); - - void Clear(); - XmlReader ReadSubtree(); - XmlWriter WriteAttributes(); - XmlWriter WriteChildren(); - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/IXmlNodeSource.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/IXmlNodeSource.cs deleted file mode 100644 index 3a09b12..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/IXmlNodeSource.cs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - public interface IXmlNodeSource - { - IXmlNode Node { get; } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/XmlContext.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/XmlContext.cs deleted file mode 100644 index 3c207be..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/XmlContext.cs +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - using System.Collections.Generic; - - public class XmlContext : XmlContextBase, IXmlContext - { - private readonly XmlMetadata metadata; - - public XmlContext(XmlMetadata metadata) - { - if (metadata == null) - throw Error.ArgumentNull(nameof(metadata)); - - this.metadata = metadata; - } - - protected XmlContext(XmlContext parent) : base(parent) - { - this.metadata = parent.metadata; - } - - public IXmlContext Clone() - { - return new XmlContext(this); - } - - public string ChildNamespaceUri - { - get { return metadata.ChildNamespaceUri; } - } - - public bool IsReservedNamespaceUri(string namespaceUri) - { - return metadata.IsReservedNamespaceUri(namespaceUri); - } - - public XmlName GetDefaultXsiType(Type clrType) - { - return metadata.GetDefaultXsiType(clrType); - } - - public IEnumerable GetIncludedTypes(Type baseType) - { - return metadata.GetIncludedTypes(baseType); - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/XmlContextBase.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/XmlContextBase.cs deleted file mode 100644 index eb7d85e..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/XmlContextBase.cs +++ /dev/null @@ -1,287 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - using System.Collections.Generic; - using System.Xml; - using System.Xml.XPath; - using System.Xml.Xsl; - - public class XmlContextBase : XsltContext, IXmlNamespaceSource - { - private readonly XmlContextBase parent; - private Dictionary rootNamespaces; - private bool hasNamespaces; - private XPathContext xPathContext; - private Dictionary variables; - private Dictionary functions; - - public XmlContextBase() - : base(new NameTable()) - { - AddNamespace(Xsd .Namespace); - AddNamespace(Xsi .Namespace); - AddNamespace(Wsdl.Namespace); - AddNamespace(XRef.Namespace); - } - - protected XmlContextBase(XmlContextBase parent) - : base(GetNameTable(parent)) - { - this.parent = parent; - } - - private static NameTable GetNameTable(XmlContextBase parent) - { - return parent.NameTable as NameTable ?? new NameTable(); - } - - public void AddNamespace(XmlNamespaceAttribute attribute) - { - var prefix = attribute.Prefix; - var uri = attribute.NamespaceUri; - - if (string.IsNullOrEmpty(uri)) - throw Error.InvalidNamespaceUri(); - - if (attribute.Default) - AddNamespace(string.Empty, uri); - - if (string.IsNullOrEmpty(prefix)) - return; - - AddNamespace(prefix, uri); - - if (attribute.Root) - EnsureRootNamespaces().Add(prefix, uri); - } - - public override void AddNamespace(string prefix, string uri) - { - base.AddNamespace(prefix, uri); - hasNamespaces = true; - } - - private Dictionary EnsureRootNamespaces() - { - return rootNamespaces ?? - ( - rootNamespaces = parent != null - ? new Dictionary(parent.EnsureRootNamespaces()) - : new Dictionary() - ); - } - - public override string LookupNamespace(string prefix) - { - return hasNamespaces - ? base .LookupNamespace(prefix) - : parent.LookupNamespace(prefix); - } - - public override string LookupPrefix(string uri) - { - return hasNamespaces - ? base .LookupPrefix(uri) - : parent.LookupPrefix(uri); - } - - public string GetElementPrefix(IXmlNode node, string namespaceUri) - { - string prefix; - if (namespaceUri == node.LookupNamespaceUri(string.Empty)) - return string.Empty; - if (TryGetDefinedPrefix(node, namespaceUri, out prefix)) - return prefix; - if (!TryGetPreferredPrefix(node, namespaceUri, out prefix)) - return string.Empty; - if (!ShouldDefineOnRoot(prefix, namespaceUri)) - return string.Empty; - - node.DefineNamespace(prefix, namespaceUri, true); - return prefix; - } - - public string GetAttributePrefix(IXmlNode node, string namespaceUri) - { - string prefix; - if (string.IsNullOrEmpty(namespaceUri)) // was: namespaceUri == node.Name.NamespaceUri - return string.Empty; - if (TryGetDefinedPrefix(node, namespaceUri, out prefix)) - return prefix; - if (!TryGetPreferredPrefix(node, namespaceUri, out prefix)) - prefix = GeneratePrefix(node); - - var root = ShouldDefineOnRoot(prefix, namespaceUri); - node.DefineNamespace(prefix, namespaceUri, root); - return prefix; - } - - private static bool TryGetDefinedPrefix(IXmlNode node, string namespaceUri, out string prefix) - { - var definedPrefix = node.LookupPrefix(namespaceUri); - return string.IsNullOrEmpty(definedPrefix) - ? Try.Failure(out prefix) - : Try.Success(out prefix, definedPrefix); - } - - private bool TryGetPreferredPrefix(IXmlNode node, string namespaceUri, out string prefix) - { - prefix = this.LookupPrefix(namespaceUri); - if (string.IsNullOrEmpty(prefix)) - return Try.Failure(out prefix); // No preferred prefix - - namespaceUri = node.LookupNamespaceUri(prefix); - return string.IsNullOrEmpty(namespaceUri) - ? true // Can use preferred prefix - : Try.Failure(out prefix); // Preferred prefix already in use - } - - private static string GeneratePrefix(IXmlNode node) - { - for (var i = 0; ; i++) - { - var prefix = "p" + i; - var namespaceUri = node.LookupNamespaceUri(prefix); - if (string.IsNullOrEmpty(namespaceUri)) - return prefix; - } - } - - private bool ShouldDefineOnRoot(string prefix, string uri) - { - return rootNamespaces != null - ? ShouldDefineOnRootCore (prefix, uri) - : parent.ShouldDefineOnRoot(prefix, uri); - } - - private bool ShouldDefineOnRootCore(string prefix, string uri) - { - string candidate; - return rootNamespaces.TryGetValue(prefix, out candidate) - && candidate == uri; - } - - private XPathContext XPathContext - { - get { return xPathContext ?? (xPathContext = new XPathContext(this)); } - } - - public override bool Whitespace - { - get { return true; } - } - - public override bool PreserveWhitespace(XPathNavigator node) - { - return true; - } - - public override int CompareDocument(string baseUriA, string baseUriB) - { - return StringComparer.Ordinal.Compare(baseUriA, baseUriB); - } - - public void AddVariable(string prefix, string name, IXsltContextVariable variable) - { - var key = new XmlName(name, prefix ?? string.Empty); - AddVariable(key, variable); - } - - public void AddFunction(string prefix, string name, IXsltContextFunction function) - { - var key = new XmlName(name, prefix ?? string.Empty); - AddFunction(key, function); - } - - public void AddVariable(XPathVariableAttribute attribute) - { - AddVariable(attribute.Name, attribute); - } - - public void AddFunction(XPathFunctionAttribute attribute) - { - AddFunction(attribute.Name, attribute); - } - - public void AddVariable(XmlName name, IXsltContextVariable variable) - { - EnsureVariables()[name] = variable; - } - - public void AddFunction(XmlName name, IXsltContextFunction function) - { - EnsureFunctions()[name] = function; - } - - private Dictionary EnsureVariables() - { - return variables ?? - ( - variables = (parent != null) - ? new Dictionary(parent.EnsureVariables()) - : new Dictionary() - ); - } - - private Dictionary EnsureFunctions() - { - return functions ?? - ( - functions = (parent != null) - ? new Dictionary(parent.EnsureFunctions()) - : new Dictionary() - ); - } - - public override IXsltContextVariable ResolveVariable(string prefix, string name) - { - return - variables != null ? ResolveVariableCore (prefix, name) : - parent != null ? parent.ResolveVariable(prefix, name) : - null; - } - - public override IXsltContextFunction ResolveFunction(string prefix, string name, XPathResultType[] argTypes) - { - return - functions != null ? ResolveFunctionCore (prefix, name, argTypes) : - parent != null ? parent.ResolveFunction(prefix, name, argTypes) : - null; - } - - private IXsltContextVariable ResolveVariableCore(string prefix, string name) - { - IXsltContextVariable variable; - var key = new XmlName(name, prefix ?? string.Empty); - variables.TryGetValue(key, out variable); - return variable; - } - - private IXsltContextFunction ResolveFunctionCore(string prefix, string name, XPathResultType[] argTypes) - { - IXsltContextFunction function; - var key = new XmlName(name, prefix ?? string.Empty); - functions.TryGetValue(key, out function); - return function; - } - - public void Enlist(CompiledXPath path) - { - path.SetContext(XPathContext); - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/XmlExtensions.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/XmlExtensions.cs deleted file mode 100644 index 3dd2de5..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/XmlExtensions.cs +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - using System.Xml; - - internal static class XmlExtensions - { - public static bool PositionEquals(this IXmlNode nodeA, IXmlNode nodeB) - { - return XmlPositionComparer.Instance.Equals(nodeA, nodeB); - } - - public static void CopyTo(this IXmlNode source, IXmlNode target) - { - using (var reader = source.ReadSubtree()) - { - if (!reader.Read()) - return; - - using (var writer = target.WriteAttributes()) - writer.WriteAttributes(reader, false); - - if (!reader.Read()) - return; - - using (var writer = target.WriteChildren()) - do writer.WriteNode(reader, false); - while (!(reader.EOF || reader.NodeType == XmlNodeType.EndElement)); - } - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/XmlName.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/XmlName.cs deleted file mode 100644 index 38eca47..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/XmlName.cs +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - - public struct XmlName : IEquatable - { - public static readonly XmlName Empty = default(XmlName); - - private readonly string localName; - private readonly string namespaceUri; - - public XmlName(string localName, string namespaceUri) - { - this.localName = localName; - this.namespaceUri = namespaceUri; - } - - public string LocalName - { - get { return localName; } - } - - public string NamespaceUri - { - get { return namespaceUri; } - } - - public override int GetHashCode() - { - return XmlNameComparer.Default.GetHashCode(this); - } - - public bool Equals(XmlName other) - { - return XmlNameComparer.Default.Equals(this, other); - } - - public override bool Equals(object obj) - { - return obj is XmlName - && Equals((XmlName) obj); - } - - public static bool operator == (XmlName x, XmlName y) - { - return XmlNameComparer.Default.Equals(x, y); - } - - public static bool operator != (XmlName x, XmlName y) - { - return ! XmlNameComparer.Default.Equals(x, y); - } - - public XmlName WithNamespaceUri(string namespaceUri) - { - return new XmlName(localName, namespaceUri); - } - - public override string ToString() - { - if (string.IsNullOrEmpty(localName)) - return string.Empty; - if (string.IsNullOrEmpty(namespaceUri)) - return localName; - return string.Concat(namespaceUri, ":", localName); - } - - public static XmlName ParseQName(string text) - { - if (text == null) - throw Error.ArgumentNull(nameof(text)); - - var index = text.IndexOf(':'); - if (index == -1) - return new XmlName(text, null); - if (index == 0) - return new XmlName(text.Substring(1), null); - if (index == text.Length) - return new XmlName(text.Substring(0, index), null); - - return new XmlName( - text.Substring(index + 1), - text.Substring(0, index)); - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/XmlNameComparer.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/XmlNameComparer.cs deleted file mode 100644 index c1cc9c3..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/XmlNameComparer.cs +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - using System.Collections.Generic; - - public class XmlNameComparer : IEqualityComparer - { - public static readonly XmlNameComparer - Default = new XmlNameComparer(StringComparer.Ordinal), - IgnoreCase = new XmlNameComparer(StringComparer.OrdinalIgnoreCase); - - private readonly StringComparer comparer; - - private XmlNameComparer(StringComparer comparer) - { - this.comparer = comparer; - } - - public int GetHashCode(XmlName name) - { - var code = (name.LocalName != null) - ? comparer.GetHashCode(name.LocalName) - : 0; - - if (name.NamespaceUri != null) - code = (code << 7 | code >> 25) - ^ comparer.GetHashCode(name.NamespaceUri); - - return code; - } - - public bool Equals(XmlName x, XmlName y) - { - return comparer.Equals(x.LocalName, y.LocalName) - && comparer.Equals(x.NamespaceUri, y.NamespaceUri); - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/XmlNodeBase.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/XmlNodeBase.cs deleted file mode 100644 index 90dc2e6..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/XmlNodeBase.cs +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - - public abstract class XmlNodeBase : IRealizableSource, IVirtual - { - protected Type type; - private readonly IXmlNode parent; - private readonly IXmlNamespaceSource namespaces; - - protected XmlNodeBase(IXmlNamespaceSource namespaces, IXmlNode parent) - { - if (null == namespaces) - throw Error.ArgumentNull(nameof(namespaces)); - - this.namespaces = namespaces; - this.parent = parent; - } - - public virtual bool IsReal - { - get { return true; } - } - - public virtual Type ClrType - { - get { return type; } - } - - public IXmlNode Parent - { - get { return parent; } - } - - public IXmlNamespaceSource Namespaces - { - get { return namespaces; } - } - - public virtual CompiledXPath Path - { - get { return null; } - } - - IRealizable IRealizableSource.AsRealizable() - { - return this as IRealizable; - } - - protected virtual void Realize() - { - // Default nodes are fully realized already - } - - void IVirtual.Realize() - { - Realize(); - } - - public virtual event EventHandler Realized - { - // Default nodes never realize - add { } - remove { } - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/XmlPositionComparer.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/XmlPositionComparer.cs deleted file mode 100644 index bbf0fe9..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/XmlPositionComparer.cs +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - public class XmlPositionComparer - { - public static readonly XmlPositionComparer - Instance = new XmlPositionComparer(); - - public bool Equals(IXmlNode nodeA, IXmlNode nodeB) - { - var comparer = XmlNameComparer.Default; - var a = new ComparandIterator { Node = nodeA }; - var b = new ComparandIterator { Node = nodeB }; - - for (;;) - { - if (a.Node.IsReal && b.Node.IsReal) - return a.Node.UnderlyingPositionEquals(b.Node); - if (!a.MoveNext() || !b.MoveNext()) - return false; - if (!comparer.Equals(a.Name, b.Name)) - return false; - } - } - - private struct ComparandIterator - { - public IXmlNode Node; - public XmlName Name; - public CompiledXPathNode Step; - - public bool MoveNext() - { - return - Step != null ? ConsumeStep() : - Node != null ? ConsumeNode() : - Stop(); - } - - private bool ConsumeNode() - { - var result = true; - var path = Node.Path; - if (path != null) - result = ConsumeFirstStep(path); - else - Name = Node.Name; - - Node = Node.Parent; - return result; - } - - private bool Stop() - { - Name = XmlName.Empty; - return false; - } - - private bool ConsumeFirstStep(CompiledXPath path) - { - if (!path.IsCreatable) - return false; - - Step = path.LastStep; - return ConsumeStep(); - } - - private bool ConsumeStep() - { - Name = new XmlName - ( - Step.LocalName, - Node.LookupNamespaceUri(Step.Prefix) - ); - - Step = Step.PreviousNode; - return true; - } - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/XmlSelfCursor.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/XmlSelfCursor.cs deleted file mode 100644 index 04c4287..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/Base/XmlSelfCursor.cs +++ /dev/null @@ -1,250 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - using System.Xml; - - public class XmlSelfCursor : IXmlCursor - { - private readonly IXmlNode node; - private readonly Type clrType; - private int position; - - public XmlSelfCursor(IXmlNode node, Type clrType) - { - this.node = node; - this.clrType = clrType; - Reset(); - } - - public CursorFlags Flags - { - get { return node.IsAttribute ? CursorFlags.Attributes : CursorFlags.Elements; } - } - - public CompiledXPath Path - { - get { return node.Path; } - } - - public XmlName Name - { - get { return node.Name; } - } - - public XmlName XsiType - { - get { return node.XsiType; } - } - - public Type ClrType - { - get { return clrType ?? node.ClrType; } - } - - public bool IsReal - { - get { return node.IsReal; } - } - - public bool IsElement - { - get { return node.IsElement; } - } - - public bool IsAttribute - { - get { return node.IsAttribute; } - } - - public bool IsNil - { - get { return node.IsNil; } - set { throw Error.NotSupported(); } - } - - public string Value - { - get { return node.Value; } - set { node.Value = value; } - } - - public string Xml - { - get { return node.Xml; } - } - - public IXmlNode Parent - { - get { return node.Parent; } - } - - public IXmlNamespaceSource Namespaces - { - get { return node.Namespaces; } - } - - public object UnderlyingObject - { - get { return node.UnderlyingObject; } - } - - public bool UnderlyingPositionEquals(IXmlNode node) - { - return this.node.UnderlyingPositionEquals(node); - } - - public IRealizable AsRealizable() - { - return node.AsRealizable(); - } - - public void Realize() - { - node.Realize(); - } - - public event EventHandler Realized - { - add { node.Realized += value; } - remove { node.Realized -= value; } - } - - public string GetAttribute(XmlName name) - { - return node.GetAttribute(name); - } - - public void SetAttribute(XmlName name, string value) - { - node.SetAttribute(name, value); - } - - public string LookupPrefix(string namespaceUri) - { - return node.LookupPrefix(namespaceUri); - } - - public string LookupNamespaceUri(string prefix) - { - return node.LookupNamespaceUri(prefix); - } - - public void DefineNamespace(string prefix, string namespaceUri, bool root) - { - node.DefineNamespace(prefix, namespaceUri, root); - } - - public bool MoveNext() - { - return 0 == ++position; - } - - public void MoveToEnd() - { - position = 1; - } - - public void Reset() - { - position = -1; - } - - public void MoveTo(IXmlNode position) - { - if (position != node) - throw Error.NotSupported(); - } - - public IXmlNode Save() - { - return position == 0 - ? new XmlSelfCursor(node.Save(), clrType) { position = 0 } - : this; - } - - public IXmlCursor SelectSelf(Type clrType) - { - return new XmlSelfCursor(node, clrType); - } - - public IXmlCursor SelectChildren(IXmlKnownTypeMap knownTypes, IXmlNamespaceSource namespaces, CursorFlags flags) - { - return node.SelectChildren(knownTypes, namespaces, flags); - } - - public IXmlIterator SelectSubtree() - { - return node.SelectSubtree(); - } - - public IXmlCursor Select(CompiledXPath path, IXmlIncludedTypeMap knownTypes, IXmlNamespaceSource namespaces, CursorFlags flags) - { - return node.Select(path, knownTypes, namespaces, flags); - } - - public object Evaluate(CompiledXPath path) - { - return node.Evaluate(path); - } - - public XmlReader ReadSubtree() - { - return node.ReadSubtree(); - } - - public XmlWriter WriteAttributes() - { - return node.WriteAttributes(); - } - - public XmlWriter WriteChildren() - { - return node.WriteChildren(); - } - - public void MakeNext(Type type) - { - if (!MoveNext()) - throw Error.NotSupported(); - } - - public void Create(Type type) - { - throw Error.NotSupported(); - } - - public void Coerce(Type type) - { - // Do nothing - } - - public void Clear() - { - node.Clear(); - } - - public void Remove() - { - // Do nothing - } - - public void RemoveAllNext() - { - // Do nothing - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/SystemXml/SysXmlCursor.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/SystemXml/SysXmlCursor.cs deleted file mode 100644 index 62fa949..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/SystemXml/SysXmlCursor.cs +++ /dev/null @@ -1,566 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - using System.Xml.XPath; - using System.Xml; - - public class SysXmlCursor : SysXmlNode, IXmlCursor - { - private State state; - private int index; - private readonly IXmlKnownTypeMap knownTypes; - private readonly CursorFlags flags; - - protected enum State - { - Empty = -4, // After last item, no items were selected - End = -3, // After last item, 1+ items were selected - AttributePrimed = -2, // MoveNext will select an attribute (happens after remove) - ElementPrimed = -1, // MoveNext will select an element (happens after remove) - Initial = 0, // Before first item - Element = 1, // An element is currently selected - Attribute = 2 // An attribute is currently selected - } - - public SysXmlCursor(IXmlNode parent, IXmlKnownTypeMap knownTypes, IXmlNamespaceSource namespaces, CursorFlags flags) - : base(namespaces, parent) - { - if (null == parent) - throw Error.ArgumentNull(nameof(parent)); - if (null == knownTypes) - throw Error.ArgumentNull(nameof(knownTypes)); - - this.knownTypes = knownTypes; - this.flags = flags; - this.index = -1; - - var source = parent.RequireRealizable(); - if (source.IsReal) - node = source.Value; - } - - public override bool IsReal - { - get { return HasCurrent; } - } - - public bool HasCurrent - { - get { return state > State.Initial; } - } - - public override Type ClrType - { - get { return HasCurrent ? base.ClrType : knownTypes.Default.ClrType; } - } - - public override XmlName Name - { - get { return HasCurrent ? base.Name : GetEffectiveName(knownTypes.Default, node); } - } - - public override XmlName XsiType - { - get { return HasCurrent ? base.XsiType : knownTypes.Default.XsiType; } - } - - public override bool IsElement - { - get { return HasCurrent ? base.IsElement : flags.IncludesElements(); } - } - - public override bool IsAttribute - { - get { return HasCurrent ? base.IsAttribute : !flags.IncludesElements(); } - } - - public override bool IsNil - { - get { return HasCurrent && base.IsNil; } - set { Realize(); base.IsNil = value; } - } - - public override string Value - { - get { return HasCurrent ? base.Value : string.Empty; } - set { base.Value = value; } // base sets IsNil, so no need to call Realize() here - } - - public override string Xml - { - get { return HasCurrent ? base.Xml : null; } - } - - public override object Evaluate(CompiledXPath path) - { - return HasCurrent ? base.Evaluate(path) : null; - } - - public bool MoveNext() - { - var hadCurrent = HasCurrent; - var hasCurrent = MoveNextCore() && - ( - flags.AllowsMultipleItems() || - IsAtEnd() - ); - - if (!hasCurrent && !hadCurrent) - state = State.Empty; - - return hasCurrent; - } - - private bool MoveNextCore() - { - while (Advance()) - if (IsMatch()) return true; - - return false; - } - - private bool IsMatch() - { - IXmlKnownType knownType; - return knownTypes.TryGet(this, out knownType) - ? Try.Success(out type, knownType.ClrType) - : Try.Failure(out type); - } - - private bool Advance() - { - for (;;) - { - switch (state) - { - case State.Initial: return AdvanceToFirstElement() || AdvanceToFirstAttribute() || Fail(State.End); - case State.Element: return AdvanceToNextElement() || AdvanceToFirstAttribute() || Fail(State.End); - case State.Attribute: return AdvanceToNextAttribute() || Fail(State.End); - case State.ElementPrimed: return Succeed(State.Element); - case State.AttributePrimed: return Succeed(State.Attribute); - case State.End: return false; - case State.Empty: return false; - } - } - } - - protected virtual bool AdvanceToFirstElement() - { - if (!flags.IncludesElements() || node == null) - return false; - if (!AdvanceElement(node.FirstChild)) - return false; - state = State.Element; - return true; - } - - private bool AdvanceToNextElement() - { - if (AdvanceElement(node.NextSibling)) - return true; - MoveToParentOfElement(); - return false; - } - - protected virtual bool AdvanceToFirstAttribute() - { - if (!flags.IncludesAttributes() || node == null) - return false; - if (!AdvanceAttribute(node)) - return false; - state = State.Attribute; - return true; - } - - private bool AdvanceToNextAttribute() - { - if (AdvanceAttribute(((XmlAttribute)node).OwnerElement)) - return true; - MoveToParentOfAttribute(); - return false; - } - - private bool AdvanceElement(XmlNode next) - { - for (;;) - { - if (next == null) - return false; - - if (next.NodeType == XmlNodeType.Element) - { - node = next; - return true; - } - - next = next.NextSibling; - } - } - - private bool AdvanceAttribute(XmlNode parent) - { - var attributes = parent.Attributes; - - for (;;) - { - index++; - if (index >= attributes.Count) - return false; - - var attribute = attributes[index]; - if (!attribute.IsNamespace()) - { - node = attribute; - return true; - } - } - } - - private bool Succeed(State state) - { - this.state = state; - return true; - } - - private bool Fail(State state) - { - this.state = state; - return false; - } - - private bool IsAtEnd() - { - var priorNode = node; - var priorType = type; - var priorState = state; - var priorIndex = index; - - var hasNext = MoveNextCore(); - - node = priorNode; - type = priorType; - state = priorState; - index = priorIndex; - - return !hasNext; - } - - public void MoveTo(IXmlNode position) - { - var source = position.AsRealizable(); - if (source == null || !source.IsReal) - throw Error.CursorCannotMoveToGivenNode(); - - IXmlKnownType knownType; - if (!knownTypes.TryGet(position, out knownType)) - throw Error.CursorCannotMoveToGivenNode(); - - node = source.Value; - type = knownType.ClrType; - - if (IsElement) - SetMovedToElement(); - else - SetMovedToAttribute(); - } - - private void SetMovedToElement() - { - state = State.Element; - index = -1; - } - - private void SetMovedToAttribute() - { - state = State.Attribute; - - var parent = ((XmlAttribute) node).OwnerElement; - var attributes = parent.Attributes; - - for (index = 0; index < attributes.Count; index++) - if (attributes[index] == node) - break; - } - - public void MoveToEnd() - { - switch (state) - { - case State.Element: - case State.ElementPrimed: - MoveToParentOfElement(); - state = State.End; - break; - - case State.Attribute: - case State.AttributePrimed: - MoveToParentOfAttribute(); - state = State.End; - break; - - case State.Initial: - state = IsAtEnd() ? State.Empty : State.End; - break; - } - } - - public void Reset() - { - MoveToEnd(); - state = State.Initial; - index = -1; - } - - private void MoveToParentOfElement() - { - node = node.ParentNode; - } - - private void MoveToParentOfAttribute() - { - node = ((XmlAttribute) node).OwnerElement; - } - - private void MoveToRealizedParent() - { - var parent = Parent; - node = parent.AsRealizable().Value; - parent.IsNil = false; - } - - public override event EventHandler Realized; - protected virtual void OnRealized() - { - if (Realized != null) - Realized(this, EventArgs.Empty); - } - - protected override void Realize() - { - if (HasCurrent) - return; - if (state != State.Empty) - throw Error.CursorNotInRealizableState(); - if (!flags.SupportsMutation()) - throw Error.CursorNotMutable(); - Create(knownTypes.Default.ClrType); - OnRealized(); - } - - public void MakeNext(Type clrType) - { - if (MoveNext()) - Coerce(clrType); - else - Create(clrType); - } - - public void Coerce(Type clrType) - { - RequireCoercible(); - - var knownType = knownTypes.Require(clrType); - - if (IsElement) - CoerceElement (knownType); - else - CoerceAttribute(knownType); - - this.type = knownType.ClrType; - } - - private void CoerceElement(IXmlKnownType knownType) - { - var oldNode = (XmlElement) node; - var parent = oldNode.ParentNode; - var name = GetEffectiveName(knownType, parent); - - if (!XmlNameComparer.Default.Equals(this.Name, name)) - { - var newNode = CreateElementCore(parent, name); - parent.ReplaceChild(newNode, oldNode); - - if (knownType.XsiType != XmlName.Empty) - this.SetXsiType(knownType.XsiType); - } - else this.SetXsiType(knownType.XsiType); - } - - private void CoerceAttribute(IXmlKnownType knownType) - { - RequireNoXsiType(knownType); - - var oldNode = (XmlAttribute) node; - var parent = oldNode.OwnerElement; - var name = GetEffectiveName(knownType, parent); - - if (!XmlNameComparer.Default.Equals(this.Name, name)) - { - var newNode = CreateAttributeCore(parent, name); - var attributes = parent.Attributes; - attributes.RemoveNamedItem(newNode.LocalName, newNode.NamespaceURI); - attributes.InsertBefore(newNode, oldNode); - attributes.Remove(oldNode); - } - } - - public void Create(Type type) - { - var knownType = knownTypes.Require(type); - var position = RequireCreatable(); - - if (flags.IncludesElements()) - CreateElement (knownType, position); - else - CreateAttribute(knownType, position); - - this.type = knownType.ClrType; - } - - private void CreateElement(IXmlKnownType knownType, XmlNode position) - { - var parent = node; - var name = GetEffectiveName(knownType, parent); - var element = CreateElementCore(parent, name); - parent.InsertBefore(element, position); - state = State.Element; - - if (knownType.XsiType != XmlName.Empty) - this.SetXsiType(knownType.XsiType); - } - - private void CreateAttribute(IXmlKnownType knownType, XmlNode position) - { - RequireNoXsiType(knownType); - - var parent = node; - var name = GetEffectiveName(knownType, parent); - var attribute = CreateAttributeCore(parent, name); - parent.Attributes.InsertBefore(attribute, (XmlAttribute) position); - state = State.Attribute; - } - - private XmlElement CreateElementCore(XmlNode parent, XmlName name) - { - var document = parent.OwnerDocument ?? (XmlDocument) parent; - var prefix = Namespaces.GetElementPrefix(this, name.NamespaceUri); - var element = document.CreateElement(prefix, name.LocalName, name.NamespaceUri); - node = element; - return element; - } - - private XmlAttribute CreateAttributeCore(XmlNode parent, XmlName name) - { - var document = parent.OwnerDocument ?? (XmlDocument) parent; - var prefix = Namespaces.GetAttributePrefix(this, name.NamespaceUri); - var attribute = document.CreateAttribute(prefix, name.LocalName, name.NamespaceUri); - node = attribute; - return attribute; - } - - private void RequireNoXsiType(IXmlKnownType knownType) - { - if (knownType.XsiType != XmlName.Empty) - throw Error.CannotSetAttribute(this); - } - - private XmlName GetEffectiveName(IXmlKnownType knownType, XmlNode parent) - { - var name = knownType.Name; - - return name.NamespaceUri != null - ? name - : name.WithNamespaceUri - ( - parent != null - ? parent.NamespaceURI - : string.Empty - ); - } - - public void RemoveAllNext() - { - while (MoveNext()) - Remove(); - } - - public void Remove() - { - RequireRemovable(); - - var removedNode = node; - var wasElement = IsElement; - MoveNext(); - - switch (state) - { - case State.Attribute: state = State.AttributePrimed; break; - case State.Element: state = State.ElementPrimed; break; - } - - if (wasElement) - RemoveElement (removedNode); - else - RemoveAttribute(removedNode); - } - - private void RemoveElement(XmlNode node) - { - node.ParentNode.RemoveChild(node); - } - - private void RemoveAttribute(XmlNode node) - { - var attribute = (XmlAttribute) node; - attribute.OwnerElement.Attributes.Remove(attribute); - } - - public override IXmlNode Save() - { - return HasCurrent ? new SysXmlNode(node, type, Namespaces) : this; - } - - private XmlNode RequireCreatable() - { - XmlNode position; - switch (state) - { - case State.Element: position = node; MoveToParentOfElement(); break; - case State.Attribute: position = node; MoveToParentOfAttribute(); break; - case State.Empty: position = null; MoveToRealizedParent(); break; - case State.End: position = null; break; - default: throw Error.CursorNotInCreatableState(); - } - return position; - } - - private void RequireCoercible() - { - if (state <= State.Initial) - throw Error.CursorNotInCoercibleState(); - } - - private void RequireRemovable() - { - if (state <= State.Initial) - throw Error.CursorNotInRemovableState(); - } - - protected static readonly StringComparer - DefaultComparer = StringComparer.OrdinalIgnoreCase; - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/SystemXml/SysXmlExtensions.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/SystemXml/SysXmlExtensions.cs deleted file mode 100644 index 791f365..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/SystemXml/SysXmlExtensions.cs +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - using System.Collections.Generic; - using System.Xml; - using System.Xml.Serialization; - using System.Xml.XPath; - - public static class SysXmlExtensions - { - public static void DefineNamespace(this XmlElement node, string prefix, string namespaceUri) - { - var attribute = node.OwnerDocument.CreateAttribute(Xmlns.Prefix, prefix, Xmlns.NamespaceUri); - attribute.Value = namespaceUri; - node.SetAttributeNode(attribute); - } - - public static bool IsNamespace(this XmlAttribute attribute) - { - return attribute.Prefix == Xmlns.Prefix || - ( - string.IsNullOrEmpty(attribute.Prefix) && - attribute.LocalName == Xmlns.Prefix - ); - } - - public static XmlElement FindRoot(this XmlElement node) - { - for (;;) - { - var next = node.ParentNode as XmlElement; - if (next == null) return node; - node = next; - } - } - - public static bool IsXsiType(this XmlAttribute attribute) - { - return attribute.LocalName == Xsi.Type.LocalName - && attribute.NamespaceURI == Xsi.NamespaceUri; - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/SystemXml/SysXmlNode.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/SystemXml/SysXmlNode.cs deleted file mode 100644 index 81202f6..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/SystemXml/SysXmlNode.cs +++ /dev/null @@ -1,298 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - using System.Xml; - using System.Xml.XPath; - - public class SysXmlNode : XmlNodeBase, IXmlNode, - IRealizable, - IRealizable - { - protected XmlNode node; - - protected SysXmlNode(IXmlNamespaceSource namespaces, IXmlNode parent) - : base(namespaces, parent) { } - - public SysXmlNode(XmlNode node, Type type, IXmlNamespaceSource namespaces) - : base(namespaces, null) - { - if (node == null) - throw Error.ArgumentNull(nameof(node)); - if (type == null) - throw Error.ArgumentNull(nameof(type)); - - this.node = node; - this.type = type; - } - - public object UnderlyingObject - { - get { return node; } - } - - XmlNode IRealizable.Value - { - get { Realize(); return node; } - } - - XPathNavigator IRealizable.Value - { - get { Realize(); return node.CreateNavigator(); } - } - - public virtual XmlName Name - { - get { return new XmlName(node.LocalName, node.NamespaceURI); } - } - - public virtual XmlName XsiType - { - get { return this.GetXsiType(); } - } - - public virtual bool IsElement - { - get { return node.NodeType == XmlNodeType.Element; } - } - - public virtual bool IsAttribute - { - get { return node.NodeType == XmlNodeType.Attribute; } - } - - public virtual bool IsNil - { - get { return this.IsXsiNil(); } - set { this.SetXsiNil(value); } - } - - public virtual string Value - { - get { return node.InnerText; } - set { var nil = (value == null); IsNil = nil; if (!nil) node.InnerText = value; } - } - - public virtual string Xml - { - get { return node.OuterXml; } - } - - public bool UnderlyingPositionEquals(IXmlNode node) - { - var sysXmlNode = node.AsRealizable(); - if (sysXmlNode != null) - return sysXmlNode.IsReal - && sysXmlNode.Value == this.node; - - var xPathNode = node.AsRealizable(); - if (xPathNode != null) - return xPathNode.IsReal - && xPathNode.Value.UnderlyingObject == this.node; - - return false; - } - - public string GetAttribute(XmlName name) - { - if (!IsReal) - return null; - - var element = node as XmlElement; - if (element == null) - return null; - - var attribute = element.GetAttributeNode(name.LocalName, name.NamespaceUri); - if (attribute == null) - return null; - - var value = attribute.Value; - if (string.IsNullOrEmpty(value)) - return null; - - return value; - } - - public void SetAttribute(XmlName name, string value) - { - if (string.IsNullOrEmpty(value)) - ClearAttribute(name); - else - SetAttributeCore(name, value); - } - - private void SetAttributeCore(XmlName name, string value) - { - if (!IsElement) - throw Error.CannotSetAttribute(this); - - Realize(); - - var element = node as XmlElement; - if (element == null) - throw Error.CannotSetAttribute(this); - - var attribute = element.GetAttributeNode(name.LocalName, name.NamespaceUri); - if (attribute == null) - { - var prefix = Namespaces.GetAttributePrefix(this, name.NamespaceUri); - attribute = element.OwnerDocument.CreateAttribute(prefix, name.LocalName, name.NamespaceUri); - element.SetAttributeNode(attribute); - } - attribute.Value = value; - } - - private void ClearAttribute(XmlName name) - { - if (!IsReal) - return; - - var element = node as XmlElement; - if (element == null) - return; - - element.RemoveAttribute(name.LocalName, name.NamespaceUri); - return; - } - - public string LookupPrefix(string namespaceUri) - { - return node.GetPrefixOfNamespace(namespaceUri); - } - - public string LookupNamespaceUri(string prefix) - { - return node.GetNamespaceOfPrefix(prefix); - } - - public void DefineNamespace(string prefix, string namespaceUri, bool root) - { - var target = GetNamespaceTargetElement(); - if (target == null) - throw Error.InvalidOperation(); - - if (root) - target = target.FindRoot(); - - target.DefineNamespace(prefix, namespaceUri); - } - - private XmlElement GetNamespaceTargetElement() - { - var element = node as XmlElement; - if (element != null) - return element; - - var attribute = node as XmlAttribute; - if (attribute != null) - return attribute.OwnerElement; - - var document = node as XmlDocument; - if (document != null) - return document.DocumentElement; - - return null; - } - - public virtual IXmlNode Save() - { - return this; - } - - public IXmlCursor SelectSelf(Type clrType) - { - return new XmlSelfCursor(this, clrType); - } - - public IXmlCursor SelectChildren(IXmlKnownTypeMap knownTypes, IXmlNamespaceSource namespaces, CursorFlags flags) - { - return new SysXmlCursor(this, knownTypes, namespaces, flags); - } - - public IXmlIterator SelectSubtree() - { - return new SysXmlSubtreeIterator(this, Namespaces); - } - - public XmlReader ReadSubtree() - { - return node.CreateNavigator().ReadSubtree(); - } - - public XmlWriter WriteAttributes() - { - return node.CreateNavigator().CreateAttributes(); - } - - public XmlWriter WriteChildren() - { - return node.CreateNavigator().AppendChild(); - } - - public IXmlCursor Select(CompiledXPath path, IXmlIncludedTypeMap includedTypes, IXmlNamespaceSource namespaces, CursorFlags flags) - { - return flags.SupportsMutation() - ? (IXmlCursor) new XPathMutableCursor (this, path, includedTypes, namespaces, flags) - : (IXmlCursor) new XPathReadOnlyCursor(this, path, includedTypes, namespaces, flags); - } - - public virtual object Evaluate(CompiledXPath path) - { - return node.CreateNavigator().Evaluate(path.Path); - } - - public XmlNode GetNode() - { - return node; - } - - public void Clear() - { - if (IsElement) - { - ClearAttributes(); - } - else if (IsAttribute) - { - Value = string.Empty; - return; - } - ClearChildren(); - } - - private void ClearAttributes() - { - var attributes = node.Attributes; - var count = attributes.Count; - while (count > 0) - { - var attribute = attributes[--count]; - if (!attribute.IsNamespace() && !attribute.IsXsiType()) - attributes.RemoveAt(count); - } - } - - private void ClearChildren() - { - XmlNode next; - for (var child = node.FirstChild; child != null; child = next) - { - next = child.NextSibling; - node.RemoveChild(child); - } - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/SystemXml/SysXmlSubtreeIterator.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/SystemXml/SysXmlSubtreeIterator.cs deleted file mode 100644 index c3191d4..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/SystemXml/SysXmlSubtreeIterator.cs +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - using System.Xml; - - public class SysXmlSubtreeIterator : SysXmlNode, IXmlIterator - { - private State state; - - public SysXmlSubtreeIterator(IXmlNode parent, IXmlNamespaceSource namespaces) - : base(namespaces, parent) - { - if (null == parent) - throw Error.ArgumentNull(nameof(parent)); - - var source = parent.RequireRealizable(); - if (source.IsReal) - node = source.Value; - - type = typeof(object); - } - - public bool MoveNext() - { - switch (state) - { - case State.Initial: return MoveToInitial(); - case State.Current: return MoveToSubsequent(); - default: return false; - } - } - - private bool MoveToInitial() - { - if (node == null) - return false; - - state = State.Current; - return true; - } - - private bool MoveToSubsequent() - { - if (MoveToElement(node.FirstChild)) - return true; - - for (; node != null; node = node.ParentNode) - if (MoveToElement(node.NextSibling)) - return true; - - state = State.End; - return false; - } - - private bool MoveToElement(XmlNode node) - { - for (; node != null; node = node.NextSibling) - if (node.NodeType == XmlNodeType.Element) - return SetNext(node); - - return false; - } - - private bool SetNext(XmlNode node) - { - this.node = node; - return true; - } - - public override IXmlNode Save() - { - return new SysXmlNode(node, type, Namespaces); - } - - private enum State - { - Initial, - Current, - End - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/CompiledXPath.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/CompiledXPath.cs deleted file mode 100644 index 8ffc697..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/CompiledXPath.cs +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System.Xml.XPath; - using System.Xml.Xsl; - - public class CompiledXPath - { - private XPathExpression path; - private CompiledXPathStep firstStep; - private int depth; - - internal CompiledXPath() { } - - public XPathExpression Path - { - get { return path; } - internal set { path = value; } - } - - public CompiledXPathStep FirstStep - { - get { return firstStep; } - internal set { firstStep = value; } - } - - public CompiledXPathStep LastStep - { - get - { - var step = null as CompiledXPathStep; - var next = firstStep; - - while (next != null) - { - step = next; - next = step.NextStep; - } - - return step; - } - } - - public int Depth - { - get { return depth; } - internal set { depth = value; } - } - - public bool IsCreatable - { - get { return firstStep != null; } - } - - internal void MakeNotCreatable() - { - firstStep = null; - depth = 0; - } - - internal void Prepare() - { - if (firstStep != null) - firstStep.Prepare(); - } - - public void SetContext(XsltContext context) - { - path.SetContext(context); - - if (firstStep != null) - firstStep.SetContext(context); - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/CompiledXPathNode.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/CompiledXPathNode.cs deleted file mode 100644 index a5a4748..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/CompiledXPathNode.cs +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - using System.Collections.Generic; - using System.Linq; - using System.Xml.XPath; - using System.Xml.Xsl; - - public class CompiledXPathNode - { - private string prefix; - private string localName; - private bool isAttribute; - private XPathExpression value; - private CompiledXPathNode next; - private CompiledXPathNode previous; - private IList dependencies; - - internal CompiledXPathNode() { } - - public string Prefix - { - get { return prefix; } - internal set { prefix = value; } - } - - public string LocalName - { - get { return localName; } - internal set { localName = value; } - } - - public bool IsAttribute - { - get { return isAttribute; } - internal set { isAttribute = value; } - } - - public bool IsSelfReference - { - get { return localName == null; } - } - - public bool IsSimple - { - get { return next == null && HasNoRealDependencies(); } - } - - public XPathExpression Value - { - get { return value ?? GetSelfReferenceValue(); } - internal set { this.value = value; } - } - - public CompiledXPathNode NextNode - { - get { return next; } - internal set { next = value; } - } - - public CompiledXPathNode PreviousNode - { - get { return previous; } - internal set { previous = value; } - } - - public IList Dependencies - { - get { return dependencies ?? (dependencies = new List()); } - } - - private static readonly IList - NoDependencies = Array.AsReadOnly(new CompiledXPathNode[0]); - - private bool HasNoRealDependencies() - { - return - ( - dependencies == null || - dependencies.Count == 0 || - ( - dependencies.Count == 1 && - dependencies[0].IsSelfReference - ) - ); - } - - private XPathExpression GetSelfReferenceValue() - { - return dependencies != null - && dependencies.Count == 1 - && dependencies[0].IsSelfReference - ? dependencies[0].value - : null; - } - - internal virtual void Prepare() - { - dependencies = (dependencies != null) - ? Array.AsReadOnly(dependencies.ToArray()) - : NoDependencies; - - foreach (var child in dependencies) - child.Prepare(); - - if (next != null) - next.Prepare(); - } - - internal virtual void SetContext(XsltContext context) - { - if (value != null) - value.SetContext(context); - - foreach (var child in dependencies) - child.SetContext(context); - - if (next != null) - next.SetContext(context); - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/CompiledXPathStep.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/CompiledXPathStep.cs deleted file mode 100644 index 2fffe13..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/CompiledXPathStep.cs +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - using System.Xml.XPath; - using System.Xml.Xsl; - - public class CompiledXPathStep : CompiledXPathNode - { - private XPathExpression path; - - internal CompiledXPathStep() { } - - public XPathExpression Path - { - get { return path; } - internal set { path = value; } - } - - public CompiledXPathStep NextStep - { - get { return (CompiledXPathStep) NextNode; } - } - - internal override void SetContext(XsltContext context) - { - path.SetContext(context); - base.SetContext(context); - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/XPathBufferedNodeIterator.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/XPathBufferedNodeIterator.cs deleted file mode 100644 index d310569..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/XPathBufferedNodeIterator.cs +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - using System.Collections.Generic; - using System.Xml.XPath; - - internal class XPathBufferedNodeIterator : XPathNodeIterator - { - private readonly IList items; - private int index; - - public XPathBufferedNodeIterator(XPathNodeIterator iterator) - { - items = new List(); - do items.Add(iterator.Current.Clone()); - while (iterator.MoveNext()); - } - - private XPathBufferedNodeIterator(XPathBufferedNodeIterator iterator) - { - items = iterator.items; - index = iterator.index; - } - - public override int CurrentPosition - { - get { return index; } - } - - public override int Count - { - get { return items.Count - 1; } - } - - public bool IsEmpty - { - get { return items.Count == 1; } - } - - public override XPathNavigator Current - { - get { return items[index]; } - } - - public void Reset() - { - index = 0; - } - - public override bool MoveNext() - { - if (++index < items.Count) - return true; - if (index > items.Count) - index--; - return false; - } - - public void MoveToEnd() - { - index = items.Count; - } - - public override XPathNodeIterator Clone() - { - return new XPathBufferedNodeIterator(this); - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/XPathCompiler.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/XPathCompiler.cs deleted file mode 100644 index 8a88dc4..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/XPathCompiler.cs +++ /dev/null @@ -1,452 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - using System.Xml; - using System.Xml.XPath; - - public static class XPathCompiler - { - public static CompiledXPath Compile(string path) - { - if (null == path) - throw Error.ArgumentNull(nameof(path)); - - // Compile whole path to catch errors - var result = new CompiledXPath(); - result.Path = XPathExpression.Compile(path); - - // Try to split into individual path steps - var tokenizer = new Tokenizer(path); - if (!ParsePath(tokenizer, result)) - result.MakeNotCreatable(); - - // Finish compilation - result.Prepare(); - return result; - } - - private static bool ParsePath(Tokenizer source, CompiledXPath path) - { - for (CompiledXPathStep step = null;;) - { - if (!ParseStep(source, path, ref step)) - return false; - if (source.Token == Token.EndOfInput) - return true; - if (!Consume(source, Token.StepSeparator)) - return false; - if (step.IsAttribute) - return false; - } - } - - private static bool ParseStep(Tokenizer source, CompiledXPath path, ref CompiledXPathStep step) - { - var previous = step; - var start = source.Index; - - if (!ParseNodeCore(source, StepFactory, ref step)) - return false; - - if (step != previous) - { - var text = source.GetConsumedText(start); - step.Path = XPathExpression.Compile(text); - - if (previous == null) - path.FirstStep = step; - else - LinkNodes(previous, step); - - path.Depth++; - } - return true; - } - - private static bool ParseNodeCore(Tokenizer source, Func factory, ref TNode node) - where TNode : CompiledXPathNode - { - if (!Consume(source, Token.SelfReference)) - { - node = factory(); - - if (Consume(source, Token.AttributeStart)) - node.IsAttribute = true; - - if (!ParseQualifiedName(source, node)) - return false; - } - - return node == null - ? source.Token != Token.PredicateStart - : ParsePredicateList(source, node); - } - - private static bool ParsePredicateList(Tokenizer source, CompiledXPathNode parent) - { - while (Consume(source, Token.PredicateStart)) - if (!ParsePredicate(source, parent)) - return false; - - return true; - } - - private static bool ParsePredicate(Tokenizer source, CompiledXPathNode parent) - { - // Don't need to check this; caller must have already checked it. - //if (!Consume(source, Token.PredicateStart)) - // return false; - - if (!ParseAndExpression(source, parent)) - return false; - - if (!Consume(source, Token.PredicateEnd)) - return false; - - return true; - } - - private static bool ParseAndExpression(Tokenizer source, CompiledXPathNode parent) - { - for (;;) - { - if (!ParseExpression(source, parent)) - return false; - - if (source.Token != Token.Name || source.Text != "and") - return true; - source.Consume(); - } - } - - private static bool ParseExpression(Tokenizer source, CompiledXPathNode parent) - { - var isLeftToRight - = source.Token == Token.Name - || source.Token == Token.AttributeStart - || source.Token == Token.SelfReference; - - return (isLeftToRight) - ? ParseLeftToRightExpression(source, parent) - : ParseRightToLeftExpression(source, parent); - } - - private static bool ParseLeftToRightExpression(Tokenizer source, CompiledXPathNode parent) - { - CompiledXPathNode node; - if (!ParseNestedPath(source, parent, out node)) - return false; - - if (!Consume(source, Token.EqualsOperator)) - return true; - - XPathExpression value; - if (!ParseValue(source, out value)) - return false; - - node.Value = value; - return true; - } - - private static bool ParseRightToLeftExpression(Tokenizer source, CompiledXPathNode parent) - { - XPathExpression value; - if (!ParseValue(source, out value)) - return false; - - if (!Consume(source, Token.EqualsOperator)) - return false; - - CompiledXPathNode node; - if (!ParseNestedPath(source, parent, out node)) - return false; - - node.Value = value; - return true; - } - - private static bool ParseNestedPath(Tokenizer source, CompiledXPathNode parent, out CompiledXPathNode node) - { - for (node = null;;) - { - if (!ParseNode(source, parent, ref node)) - return false; - if (!Consume(source, Token.StepSeparator)) - break; - if (node.IsAttribute) - return false; - } - - if (node == null) - { - var dependencies = parent.Dependencies; - if (dependencies.Count != 0) - return false; - dependencies.Add(node = NodeFactory()); // Self-reference - } - return true; - } - - private static bool ParseNode(Tokenizer source, CompiledXPathNode parent, ref CompiledXPathNode node) - { - var previous = node; - - if (!ParseNodeCore(source, NodeFactory, ref node)) - return false; - - if (node != previous) - { - if (previous == null) - parent.Dependencies.Add(node); - else - LinkNodes(previous, node); - } - return true; - } - - private static bool ParseValue(Tokenizer source, out XPathExpression value) - { - var start = source.Index; - - var parsed = - Consume(source, Token.StringLiteral) || - ( - Consume(source, Token.VariableStart) && - ParseQualifiedName(source, null) - ); - if (!parsed) - return Try.Failure(out value); - - var xpath = source.GetConsumedText(start); - value = XPathExpression.Compile(xpath); - return true; - } - - private static bool ParseQualifiedName(Tokenizer source, CompiledXPathNode node) - { - string nameA, nameB; - - if (!ParseName(source, out nameA)) - return false; - - if (!Consume(source, Token.NameSeparator)) - { - if (node != null) - node.LocalName = nameA; - return true; - } - - if (!ParseName(source, out nameB)) - return false; - - if (node != null) - { - node.Prefix = nameA; - node.LocalName = nameB; - } - return true; - } - - private static bool ParseName(Tokenizer source, out string name) - { - if (source.Token != Token.Name) - return Try.Failure(out name); - name = source.Text; - source.Consume(); - return true; - } - - private static bool Consume(Tokenizer source, Token token) - { - if (source.Token != token) - return false; - source.Consume(); - return true; - } - - private static void LinkNodes(CompiledXPathNode previous, CompiledXPathNode next) - { - previous.NextNode = next; - next.PreviousNode = previous; - } - - private static readonly Func - NodeFactory = () => new CompiledXPathNode(); - - private static readonly Func - StepFactory = () => new CompiledXPathStep(); - - private enum Token - { - Name, - SelfReference, - - StepSeparator, - NameSeparator, - AttributeStart, - VariableStart, - EqualsOperator, - - PredicateStart, - PredicateEnd, - - StringLiteral, - - EndOfInput, - Error - } - - private class Tokenizer - { - private readonly string input; - - private State state; - private Token token; - private int index; - private int start; - private int prior; - - public Tokenizer(string input) - { - this.input = input; - this.state = State.Initial; - this.index = -1; - Consume(); - } - - // Type of the current token - public Token Token - { - get { return token; } - } - - // Text of the current token - public string Text - { - get { return input.Substring(start, index - start + 1); } - } - - // Gets text that has been consumed previously - public string GetConsumedText(int start) - { - return input.Substring(start, prior - start + 1); - } - - // Index where current token starts - public int Index - { - get { return start; } - } - - // Consider the current token consumed, and read next token - public void Consume() - { - prior = index; - - for(;;) - { - var c = ReadChar(); - - switch (state) - { - case State.Initial: - start = index; - switch (c) - { - case '.': token = Token.SelfReference; return; - case '/': token = Token.StepSeparator; return; - case ':': token = Token.NameSeparator; return; - case '@': token = Token.AttributeStart; return; - case '$': token = Token.VariableStart; return; - case '=': token = Token.EqualsOperator; return; - case '[': token = Token.PredicateStart; return; - case ']': token = Token.PredicateEnd; return; - case '\0': token = Token.EndOfInput; return; - case '\'': state = State.SingleQuoteString; break; - case '\"': state = State.DoubleQuoteString; break; - default: - if (IsNameStartChar(c)) { state = State.Name; } - else if (IsWhitespace(c)) { /* Ignore */ } - else { state = State.Failed; } - break; - } - break; - - case State.Name: - if (IsNameChar(c)) { break; } - RewindChar(); - token = Token.Name; - state = State.Initial; - return; - - case State.SingleQuoteString: - if (c != '\'') { break; } - token = Token.StringLiteral; - state = State.Initial; - return; - - case State.DoubleQuoteString: - if (c != '\"') { break; } - token = Token.StringLiteral; - state = State.Initial; - return; - - case State.Failed: - token = Token.Error; - return; - } - } - } - - private char ReadChar() - { - return (++index < input.Length) - ? input[index] - : default(char); // EOF sentinel - } - - private void RewindChar() - { - --index; - } - - private static bool IsWhitespace(char c) - { - return XmlConvert.IsWhitespaceChar(c); - } - - private static bool IsNameStartChar(char c) - { - return XmlConvert.IsStartNCNameChar(c); - } - - private static bool IsNameChar(char c) - { - return XmlConvert.IsNCNameChar(c); - } - - private enum State - { - Initial = 0, - Name, - SingleQuoteString, - DoubleQuoteString, - Failed - } - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/XPathContext.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/XPathContext.cs deleted file mode 100644 index 925b216..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/XPathContext.cs +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System.Xml.XPath; - using System.Xml.Xsl; - - internal class XPathContext : XsltContext - { - private readonly XsltContext context; - - public XPathContext(XsltContext xpathContext) - { - this.context = xpathContext; - } - - public override string DefaultNamespace - { - // Must be empty, or XPath evaluation will break - get { return string.Empty; } - } - - public override string LookupNamespace(string prefix) - { - // Must return empty uri for empty prefix, or XPath evaluation will break - return string.IsNullOrEmpty(prefix) - ? string.Empty - : context.LookupNamespace(prefix); - } - - public override bool Whitespace - { - get { return context.Whitespace; } - } - - public override bool PreserveWhitespace(XPathNavigator node) - { - return context.PreserveWhitespace(node); - } - - public override int CompareDocument(string baseUri, string nextbaseUri) - { - return context.CompareDocument(baseUri, nextbaseUri); - } - - public override IXsltContextFunction ResolveFunction(string prefix, string name, XPathResultType[] argTypes) - { - return context.ResolveFunction(prefix, name, argTypes); - } - - public override IXsltContextVariable ResolveVariable(string prefix, string name) - { - return context.ResolveVariable(prefix, name); - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/XPathExtensions.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/XPathExtensions.cs deleted file mode 100644 index 18a24a4..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/XPathExtensions.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - using System.Xml; - using System.Xml.XPath; - - public static class XPathExtensions - { - public static XPathNavigator CreateNavigatorSafe(this IXPathNavigable source) - { - if (source == null) - throw Error.ArgumentNull(nameof(source)); - return source.CreateNavigator(); - } - - public static bool MoveToLastChild(this XPathNavigator navigator) - { - if (!navigator.MoveToFirstChild()) - return false; - - while (navigator.MoveToNext()) { } - - return true; - } - - public static bool MoveToLastAttribute(this XPathNavigator navigator) - { - if (!navigator.MoveToFirstAttribute()) - return false; - - while (navigator.MoveToNextAttribute()) { } - - return true; - } - - public static XPathNavigator GetRootElement(this XPathNavigator navigator) - { - navigator = navigator.Clone(); - navigator.MoveToRoot(); - if (navigator.NodeType == XPathNodeType.Root) - if (!navigator.MoveToFirstChild()) - throw Error.InvalidOperation(); - return navigator; - } - - public static XPathNavigator GetParent(this XPathNavigator navigator) - { - navigator = navigator.Clone(); - if (!navigator.MoveToParent()) - throw Error.InvalidOperation(); - return navigator; - } - - public static void DeleteChildren(this XPathNavigator node) - { - while (node.MoveToFirstChild()) - node.DeleteSelf(); - while (node.MoveToFirstAttribute()) - node.DeleteSelf(); - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/XPathMutableCursor.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/XPathMutableCursor.cs deleted file mode 100644 index 6d5e41f..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/XPathMutableCursor.cs +++ /dev/null @@ -1,415 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - using System.Xml; - using System.Xml.XPath; - - internal class XPathMutableCursor : XPathNode, IXmlCursor - { - private XPathBufferedNodeIterator iterator; - private CompiledXPathStep step; - private int depth; - - private readonly IXmlIncludedTypeMap knownTypes; - private readonly CursorFlags flags; - - public XPathMutableCursor(IXmlNode parent, CompiledXPath path, - IXmlIncludedTypeMap knownTypes, IXmlNamespaceSource namespaces, CursorFlags flags) - : base(path, namespaces, parent) - { - if (null == parent) - throw Error.ArgumentNull(nameof(parent)); - if (null == path) - throw Error.ArgumentNull(nameof(path)); - if (null == knownTypes) - throw Error.ArgumentNull(nameof(knownTypes)); - if (!path.IsCreatable) - throw Error.XPathNotCreatable(path); - - this.step = path.FirstStep; - this.knownTypes = knownTypes; - this.flags = flags; - - var source = parent.RequireRealizable(); - if (source.IsReal) - iterator = new XPathBufferedNodeIterator( - source.Value.Select(path.FirstStep.Path)); - } - - public override bool IsReal - { - get { return HasCurrent; } - } - - public bool HasCurrent - { - get { return depth == xpath.Depth; } - } - - public bool HasPartialOrCurrent - { - get { return null != node; } // (_depth > 0 works also) - } - - public override Type ClrType - { - get { return HasCurrent ? base.ClrType : knownTypes.Default.ClrType; } - } - - public override XmlName Name - { - get { return HasCurrent ? base.Name : XmlName.Empty; } - } - - public override XmlName XsiType - { - get { return HasCurrent ? base.XsiType : knownTypes.Default.XsiType; } - } - - public override bool IsElement - { - get { return HasCurrent ? base.IsElement : flags.IncludesElements(); } - } - - public override bool IsAttribute - { - get { return HasCurrent ? base.IsAttribute : !flags.IncludesElements(); } - } - - public override bool IsNil - { - get { return HasCurrent && base.IsNil; } - set { Realize(); base.IsNil = value; } - } - - public override string Value - { - get { return HasCurrent ? base.Value : string.Empty; } - set { base.Value = value; } // base sets IsNil, so no need to call Realize() here - } - - public override string Xml - { - get { return HasCurrent ? base.Xml : null; } - } - - public override object Evaluate(CompiledXPath path) - { - return HasCurrent ? base.Evaluate(path) : null; - } - - public bool MoveNext() - { - ResetCurrent(); - - for (;;) - { - var hasNext - = iterator != null - && iterator.MoveNext() - && Consume(iterator, flags.AllowsMultipleItems()); - - if (!hasNext) - return SetAtEnd(); - if (SeekCurrent()) - return true; - } - } - - private bool SeekCurrent() - { - while (depth < xpath.Depth) - { - var iterator = node.Select(step.Path); - if (!iterator.MoveNext()) - return true; // Sought as far as possible - if (!Consume(iterator, false)) - return false; // Problem: found multiple nodes - } - - IXmlIncludedType includedType; - if (!knownTypes.TryGet(XsiType, out includedType)) - return false; // Problem: unrecognized xsi:type - - type = includedType.ClrType; - return true; // Sought all the way - } - - private bool Consume(XPathNodeIterator iterator, bool multiple) - { - var candidate = iterator.Current; - if (!multiple && iterator.MoveNext()) - return false; - - node = candidate; - Descend(); - return true; - } - - private bool SetAtEnd() - { - ResetCurrent(); - return false; - } - - public void Reset() - { - ResetCurrent(); - iterator.Reset(); - } - - public void MoveToEnd() - { - ResetCurrent(); - iterator.MoveToEnd(); - } - - private void ResetCurrent() - { - node = null; - type = null; - ResetDepth(); - } - - private void ResetDepth() - { - step = xpath.FirstStep; - depth = 0; - } - - private int Descend() - { - step = step.NextStep; - return ++depth; - } - - public void MoveTo(IXmlNode position) - { - var source = position.AsRealizable(); - if (source == null || !source.IsReal) - throw Error.CursorCannotMoveToGivenNode(); - - var positionNode = source.Value; - - Reset(); - while (MoveNext()) - if (HasCurrent && node.IsSamePosition(positionNode)) - return; - - throw Error.CursorCannotMoveToGivenNode(); - } - - public override event EventHandler Realized; - protected virtual void OnRealized() - { - if (Realized != null) - Realized(this, EventArgs.Empty); - } - - protected override void Realize() - { - if (HasCurrent) - return; - if (!(iterator == null || iterator.IsEmpty || HasPartialOrCurrent)) - throw Error.CursorNotInRealizableState(); - Create(knownTypes.Default.ClrType); - OnRealized(); - } - - public void MakeNext(Type clrType) - { - if (MoveNext()) - Coerce(clrType); - else - Create(clrType); - } - - public void Coerce(Type clrType) - { - var includedType = knownTypes.Require(clrType); - this.SetXsiType(includedType.XsiType); - this.type = clrType; - } - - public void Create(Type type) - { - if (HasCurrent) - Insert(); - else if (HasPartialOrCurrent) - Complete(); - else - Append(); - - Coerce(type); - } - - private void Insert() - { - while (--depth > 0) - node.MoveToParent(); - ResetDepth(); - - using (var writer = node.InsertBefore()) - WriteNode(step, writer); - - var moved = node.MoveToPrevious(); - SeekCurrentAfterCreate(moved); - } - - private void Append() - { - node = Parent.AsRealizable().Value.Clone(); - Parent.IsNil = false; - Complete(); - } - - private void Complete() - { - using (var writer = CreateWriterForAppend()) - WriteNode(step, writer); - - var moved = step.IsAttribute - ? node.MoveToLastAttribute() - : node.MoveToLastChild(); - SeekCurrentAfterCreate(moved); - } - - private XmlWriter CreateWriterForAppend() - { - return step.IsAttribute - ? node.CreateAttributes() - : node.AppendChild(); - } - - private void WriteNode(CompiledXPathNode node, XmlWriter writer) - { - if (node.IsAttribute) - WriteAttribute(node, writer); - else if (node.IsSimple) - WriteSimpleElement(node, writer); - else - WriteComplexElement(node, writer); - } - - private void WriteAttribute(CompiledXPathNode node, XmlWriter writer) - { - writer.WriteStartAttribute(node.Prefix, node.LocalName, null); - WriteValue(node, writer); - writer.WriteEndAttribute(); - } - - private void WriteSimpleElement(CompiledXPathNode node, XmlWriter writer) - { - writer.WriteStartElement(node.Prefix, node.LocalName, null); - WriteValue(node, writer); - writer.WriteEndElement(); - } - - private void WriteComplexElement(CompiledXPathNode node, XmlWriter writer) - { - writer.WriteStartElement(node.Prefix, node.LocalName, null); - WriteSubnodes(node, writer, true); - WriteSubnodes(node, writer, false); - writer.WriteEndElement(); - } - - private void WriteSubnodes(CompiledXPathNode parent, XmlWriter writer, bool attributes) - { - var next = parent.NextNode; - if (next != null && next.IsAttribute == attributes) - WriteNode(next, writer); - - foreach (var node in parent.Dependencies) - if (node.IsAttribute == attributes) - WriteNode(node, writer); - } - - private void WriteValue(CompiledXPathNode node, XmlWriter writer) - { - if (node.Value == null) - return; - - var value = Parent.AsRealizable().Value.Evaluate(node.Value); - writer.WriteValue(value); - } - - private void SeekCurrentAfterCreate(bool moved) - { - RequireMoved(moved); - if (Descend() == xpath.Depth) - return; - - do - { - moved = step.IsAttribute - ? node.MoveToFirstAttribute() - : node.MoveToFirstChild(); - RequireMoved(moved); - } - while (Descend() < xpath.Depth); - } - - public void RemoveAllNext() - { - while (MoveNext()) - Remove(); - } - - public void Remove() - { - RequireRemovable(); - - var name = XmlName.Empty; - - if (!HasCurrent) - { - var namespaceUri = LookupNamespaceUri(step.Prefix) ?? node.NamespaceURI; - name = new XmlName(step.LocalName, namespaceUri); - } - - do - { - if (node.MoveToChild(name.LocalName, name.NamespaceUri)) - break; - - name = new XmlName(node.LocalName, node.NamespaceURI); - node.DeleteSelf(); - depth--; - } - while (depth > 0); - - ResetCurrent(); - } - - public override IXmlNode Save() - { - return HasCurrent ? new XPathNode(node.Clone(), type, Namespaces) : this; - } - - private void RequireRemovable() - { - if (!HasPartialOrCurrent) - throw Error.CursorNotInRemovableState(); - } - - private void RequireMoved(bool result) - { - if (!result) - throw Error.XPathNavigationFailed(step.Path); - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/XPathNode.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/XPathNode.cs deleted file mode 100644 index ea40616..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/XPathNode.cs +++ /dev/null @@ -1,233 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - using System.Xml; - using System.Xml.XPath; - - public class XPathNode : XmlNodeBase, IXmlNode, IRealizable - , IRealizable - { - protected XPathNavigator node; - protected readonly CompiledXPath xpath; - - protected XPathNode(CompiledXPath path, IXmlNamespaceSource namespaces, IXmlNode parent) - : base(namespaces, parent) - { - this.xpath = path; - } - - public XPathNode(XPathNavigator node, Type type, IXmlNamespaceSource namespaces) - : this(null, namespaces, null) - { - if (node == null) - throw Error.ArgumentNull(nameof(node)); - if (type == null) - throw Error.ArgumentNull(nameof(type)); - - this.node = node; - this.type = type; - } - - public object UnderlyingObject - { - get { return node; } - } - - XPathNavigator IRealizable.Value - { - get { Realize(); return node; } - } - - XmlNode IRealizable.Value - { - get { Realize(); return (XmlNode) node.UnderlyingObject; } - } - - public override CompiledXPath Path - { - get { return xpath; } - } - - public virtual XmlName Name - { - get { return new XmlName(node.LocalName, node.NamespaceURI); } - } - - public virtual XmlName XsiType - { - get { return this.GetXsiType(); } - } - - public virtual bool IsElement - { - get { return node.NodeType == XPathNodeType.Element; } - } - - public virtual bool IsAttribute - { - get { return node.NodeType == XPathNodeType.Attribute; } - } - - public virtual bool IsNil - { - get { return this.IsXsiNil(); } - set { this.SetXsiNil(value); } - } - - public virtual string Value - { - get { return node.Value; } - set { var nil = (value == null); IsNil = nil; if (!nil) node.SetValue(value); } - } - - public virtual string Xml - { - get { return node.OuterXml; } - } - - public string GetAttribute(XmlName name) - { - if (!IsReal || !node.MoveToAttribute(name.LocalName, name.NamespaceUri)) - return null; - - var value = node.Value; - node.MoveToParent(); - return string.IsNullOrEmpty(value) ? null : value; - } - - public void SetAttribute(XmlName name, string value) - { - if (string.IsNullOrEmpty(value)) - ClearAttribute(name); - else - SetAttributeCore(name, value); - } - - private void SetAttributeCore(XmlName name, string value) - { - if (!IsElement) - throw Error.CannotSetAttribute(this); - - Realize(); - - if (node.MoveToAttribute(name.LocalName, name.NamespaceUri)) - { - node.SetValue(value); - node.MoveToParent(); - } - else - { - var prefix = Namespaces.GetAttributePrefix(this, name.NamespaceUri); - node.CreateAttribute(prefix, name.LocalName, name.NamespaceUri, value); - } - } - - private void ClearAttribute(XmlName name) - { - if (IsReal && node.MoveToAttribute(name.LocalName, name.NamespaceUri)) - node.DeleteSelf(); - } - - public string LookupPrefix(string namespaceUri) - { - return node.LookupPrefix(namespaceUri); - } - - public string LookupNamespaceUri(string prefix) - { - return node.LookupNamespace(prefix); - } - - public void DefineNamespace(string prefix, string namespaceUri, bool root) - { - var target - = root ? node.GetRootElement() - : IsElement ? node - : IsAttribute ? node.GetParent() - : node.GetRootElement(); - - target.CreateAttribute(Xmlns.Prefix, prefix, Xmlns.NamespaceUri, namespaceUri); - } - - public bool UnderlyingPositionEquals(IXmlNode node) - { - var sysXmlNode = node.AsRealizable(); - if (sysXmlNode != null) - return sysXmlNode.IsReal - && sysXmlNode.Value == this.node.UnderlyingObject; - - var xPathNode = node.AsRealizable(); - if (xPathNode != null) - return xPathNode.IsReal - && xPathNode.Value.IsSamePosition(this.node); - - return false; - } - - public virtual IXmlNode Save() - { - return this; - } - - public IXmlCursor SelectSelf(Type clrType) - { - return new XmlSelfCursor(this, clrType); - } - - public IXmlCursor SelectChildren(IXmlKnownTypeMap knownTypes, IXmlNamespaceSource namespaces, CursorFlags flags) - { - return new SysXmlCursor(this, knownTypes, namespaces, flags); - } - - public IXmlIterator SelectSubtree() - { - return new SysXmlSubtreeIterator(this, Namespaces); - } - - public IXmlCursor Select(CompiledXPath path, IXmlIncludedTypeMap includedTypes, IXmlNamespaceSource namespaces, CursorFlags flags) - { - return flags.SupportsMutation() - ? (IXmlCursor) new XPathMutableCursor (this, path, includedTypes, namespaces, flags) - : (IXmlCursor) new XPathReadOnlyCursor(this, path, includedTypes, namespaces, flags); - } - - public virtual object Evaluate(CompiledXPath path) - { - return node.Evaluate(path.Path); - } - - public virtual XmlReader ReadSubtree() - { - return node.ReadSubtree(); - } - - public virtual XmlWriter WriteAttributes() - { - return node.CreateAttributes(); - } - - public virtual XmlWriter WriteChildren() - { - return node.AppendChild(); - } - - public virtual void Clear() - { - node.DeleteChildren(); - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/XPathReadOnlyCursor.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/XPathReadOnlyCursor.cs deleted file mode 100644 index cc2fc64..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Cursors/XPath/XPathReadOnlyCursor.cs +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - using System.Xml.XPath; - - public class XPathReadOnlyCursor : XPathNode, IXmlCursor - { - private XPathNodeIterator iterator; - private readonly IXmlIncludedTypeMap includedTypes; - private readonly CursorFlags flags; - - public XPathReadOnlyCursor(IXmlNode parent, CompiledXPath path, - IXmlIncludedTypeMap includedTypes, IXmlNamespaceSource namespaces, CursorFlags flags) - : base(path, namespaces, parent) - { - if (parent == null) - throw Error.ArgumentNull(nameof(parent)); - if (path == null) - throw Error.ArgumentNull(nameof(path)); - if (includedTypes == null) - throw Error.ArgumentNull(nameof(includedTypes)); - - this.includedTypes = includedTypes; - this.flags = flags; - - Reset(); - } - - public void Reset() - { - var source = Parent.RequireRealizable(); - if (source.IsReal) - iterator = source.Value.Select(xpath.Path); - } - - public bool MoveNext() - { - for (;;) - { - var hasNext - = iterator != null - && iterator.MoveNext() - && (flags.AllowsMultipleItems() || !iterator.MoveNext()); - - if (!hasNext) - return SetAtEnd(); - if (SetAtNext()) - return true; - } - } - - private bool SetAtEnd() - { - node = null; - type = null; - return false; - } - - private bool SetAtNext() - { - node = iterator.Current; - - IXmlIncludedType includedType; - if (!includedTypes.TryGet(XsiType, out includedType)) - return false; - - type = includedType.ClrType; - return true; - } - - public void MoveTo(IXmlNode position) - { - var source = position.AsRealizable(); - if (source == null || !source.IsReal) - throw Error.CursorCannotMoveToGivenNode(); - - var positionNode = source.Value; - - Reset(); - - if (iterator != null) - while (iterator.MoveNext()) - if (iterator.Current.IsSamePosition(positionNode)) - { SetAtNext(); return; } - - throw Error.CursorCannotMoveToGivenNode(); - } - - public void MoveToEnd() - { - if (iterator != null) - while (iterator.MoveNext()) ; - SetAtEnd(); - } - - public void MakeNext(Type type) - { - throw Error.CursorNotMutable(); - } - - public void Create(Type type) - { - throw Error.CursorNotMutable(); - } - - public void Coerce(Type type) - { - throw Error.CursorNotMutable(); - } - - public void Remove() - { - throw Error.CursorNotMutable(); - } - - public void RemoveAllNext() - { - throw Error.CursorNotMutable(); - } - - public override IXmlNode Save() - { - return new XPathNode(node.Clone(), type, Namespaces); - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Namespaces/Wsdl.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Namespaces/Wsdl.cs deleted file mode 100644 index e68ec85..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Namespaces/Wsdl.cs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - // Namespace for Guid type - public static class Wsdl - { - public const string - Prefix = "wsdl", - NamespaceUri = "http://microsoft.com/wsdl/types/"; - - internal static readonly XmlNamespaceAttribute - Namespace = new XmlNamespaceAttribute(NamespaceUri, Prefix) { Root = true }; - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Namespaces/XRef.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Namespaces/XRef.cs deleted file mode 100644 index c6540ac..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Namespaces/XRef.cs +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - using System.Collections.Generic; - - public static class XRef - { - public static string GetId(this IXmlNode node) - { - return node.GetAttribute(XRef.Id); - } - - public static void SetId(this IXmlCursor node, string id) - { - node.SetAttribute(XRef.Id, id); - } - - public static string GetReference(this IXmlNode node) - { - return node.GetAttribute(XRef.Ref); - } - - public static void SetReference(this IXmlCursor cursor, string id) - { - cursor.SetAttribute(XRef.Ref, id); - } - - public const string - Prefix = "x", - NamespaceUri = "urn:schemas-castle-org:xml-reference"; - - public static readonly XmlName - Id = new XmlName("id", NamespaceUri), - Ref = new XmlName("ref", NamespaceUri); - - internal static readonly XmlNamespaceAttribute - Namespace = new XmlNamespaceAttribute(NamespaceUri, Prefix) { Root = true }; - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Namespaces/Xmlns.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Namespaces/Xmlns.cs deleted file mode 100644 index bbfeb89..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Namespaces/Xmlns.cs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - public static class Xmlns - { - public const string - Prefix = "xmlns", - NamespaceUri = "http://www.w3.org/2000/xmlns/"; - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Namespaces/Xsd.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Namespaces/Xsd.cs deleted file mode 100644 index d27ed04..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Namespaces/Xsd.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - public static class Xsd - { - public const string - Prefix = "xsd", - NamespaceUri = "http://www.w3.org/2001/XMLSchema"; - - internal static readonly XmlNamespaceAttribute - Namespace = new XmlNamespaceAttribute(NamespaceUri, Prefix) { Root = true }; - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Namespaces/Xsi.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Namespaces/Xsi.cs deleted file mode 100644 index de1c05e..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Namespaces/Xsi.cs +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - - public static class Xsi - { - public static XmlName GetXsiType(this IXmlNode node) - { - var type = node.GetAttribute(Xsi.Type); - if (type == null) - return XmlName.Empty; - - var xsiType = XmlName.ParseQName(type); - if (xsiType.NamespaceUri != null) - { - var namespaceUri = node.LookupNamespaceUri(xsiType.NamespaceUri); - xsiType = xsiType.WithNamespaceUri(namespaceUri); - } - return xsiType; - } - - public static void SetXsiType(this IXmlNode node, XmlName xsiType) - { - if (xsiType.NamespaceUri != null) - { - var prefix = node.Namespaces.GetAttributePrefix(node, xsiType.NamespaceUri); - xsiType = xsiType.WithNamespaceUri(prefix); - } - node.SetAttribute(Xsi.Type, xsiType.ToString()); - } - - public static bool IsXsiNil(this IXmlNode node) - { - return node.GetAttribute(Xsi.Nil) == NilValue; - } - - public static void SetXsiNil(this IXmlNode node, bool nil) - { - string value; - if (nil) - { - node.Clear(); - value = NilValue; - } - else value = null; - node.SetAttribute(Xsi.Nil, value); - } - - public const string - Prefix = "xsi", - NamespaceUri = "http://www.w3.org/2001/XMLSchema-instance", - NilValue = "true"; - - public static readonly XmlName - Type = new XmlName("type", NamespaceUri), - Nil = new XmlName("nil", NamespaceUri); - - internal static readonly XmlNamespaceAttribute - Namespace = new XmlNamespaceAttribute(NamespaceUri, Prefix) { Root = true }; - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlArraySerializer.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlArraySerializer.cs deleted file mode 100644 index 89028d5..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlArraySerializer.cs +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - using System.Collections; - using System.Collections.Generic; - - public class XmlArraySerializer : XmlTypeSerializer - { - public static readonly XmlArraySerializer - Instance = new XmlArraySerializer(); - - protected XmlArraySerializer() { } - - public override XmlTypeKind Kind - { - get { return XmlTypeKind.Collection; } - } - - public override bool CanGetStub - { - get { return true; } - } - - public override object GetStub(IXmlNode node, IDictionaryAdapter parent, IXmlAccessor accessor) - { - var itemType = node.ClrType.GetElementType(); - - return Array.CreateInstance(itemType, 0); - } - - public override object GetValue(IXmlNode node, IDictionaryAdapter parent, IXmlAccessor accessor) - { - var items = new ArrayList(); - var itemType = node.ClrType.GetElementType(); - var references = XmlAdapter.For(parent).References; - - accessor - .GetCollectionAccessor(itemType) - .GetCollectionItems(node, parent, references, items); - - return items.ToArray(itemType); - } - - public override void SetValue(IXmlNode node, IDictionaryAdapter parent, IXmlAccessor accessor, object oldValue, ref object value) - { - var source = (Array) value; - var target = (Array) null; - var originals = (Array) oldValue; - var itemType = source.GetType().GetElementType(); - var subaccessor = accessor.GetCollectionAccessor(itemType); - var cursor = subaccessor.SelectCollectionItems(node, true); - var serializer = subaccessor.Serializer; - var references = XmlAdapter.For(parent).References; - - for (var i = 0; i < source.Length; i++) - { - var originalItem = GetItemSafe(originals, i); - var providedItem = source.GetValue(i); - var assignedItem = providedItem; - - subaccessor.SetValue(cursor, parent, references, cursor.MoveNext(), originalItem, ref assignedItem); - - if (target != null) - { - target.SetValue(assignedItem, i); - } - else if (!Equals(assignedItem, providedItem)) - { - target = Array.CreateInstance(itemType, source.Length); - Array.Copy(source, target, i); - target.SetValue(assignedItem, i); - } - } - - cursor.RemoveAllNext(); - - if (target != null) - value = target; - } - - private static object GetItemSafe(Array array, int index) - { - return array != null && index >= 0 && index < array.Length - ? array.GetValue(index) - : null; - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlCollectionSerializer.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlCollectionSerializer.cs deleted file mode 100644 index 4783681..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlCollectionSerializer.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - using System.Collections; - - public abstract class XmlCollectionSerializer : XmlTypeSerializer - { - protected XmlCollectionSerializer() { } - - public override XmlTypeKind Kind - { - get { return XmlTypeKind.Collection; } - } - - public override bool CanGetStub - { - get { return true; } - } - - public abstract Type ListTypeConstructor - { - get; // generic type constructor - } - - public override object GetStub(IXmlNode node, IDictionaryAdapter parent, IXmlAccessor accessor) - { - return GetValueCore(node, parent, accessor); - } - - public override object GetValue(IXmlNode node, IDictionaryAdapter parent, IXmlAccessor accessor) - { - return GetValueCore(node.Save(), parent, accessor); - } - - private object GetValueCore(IXmlNode node, IDictionaryAdapter parent, IXmlAccessor accessor) - { - var itemType = node.ClrType.GetGenericArguments()[0]; - var listType = ListTypeConstructor.MakeGenericType(itemType); - var subaccessor = accessor.GetCollectionAccessor(itemType); - return Activator.CreateInstance(listType, node, parent, subaccessor); - } - - public override void SetValue(IXmlNode node, IDictionaryAdapter parent, IXmlAccessor accessor, object oldValue, ref object value) - { - var current = value as IXmlNodeSource; - if (current != null && current.Node.PositionEquals(node)) - return; - - var newItems = value as IEnumerable; - if (newItems == null) - throw Error.NotSupported(); - - var oldCollection = oldValue as ICollectionProjection; - if (oldCollection != null) - oldCollection.ClearReferences(); - - var newCollection = (ICollectionProjection) GetValue(node, parent, accessor); - newCollection.Replace(newItems); - value = newCollection; - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlComponentSerializer.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlComponentSerializer.cs deleted file mode 100644 index 2c62847..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlComponentSerializer.cs +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - using System.Collections; - - public class XmlComponentSerializer : XmlTypeSerializer - { - public static readonly XmlComponentSerializer - Instance = new XmlComponentSerializer(); - - protected XmlComponentSerializer() { } - - public override XmlTypeKind Kind - { - get { return XmlTypeKind.Complex; } - } - - public override bool CanGetStub - { - get { return true; } - } - - public override object GetStub(IXmlNode node, IDictionaryAdapter parent, IXmlAccessor accessor) - { - // TODO: Refactor - var adapter = new XmlAdapter(node, XmlAdapter.For(parent).References); - return parent.CreateChildAdapter(accessor.ClrType, adapter); - } - - public override object GetValue(IXmlNode node, IDictionaryAdapter parent, IXmlAccessor accessor) - { - var adapter = new XmlAdapter(node.Save(), XmlAdapter.For(parent).References); - return parent.CreateChildAdapter(node.ClrType, adapter); - } - - public override void SetValue(IXmlNode node, IDictionaryAdapter parent, IXmlAccessor accessor, object oldValue, ref object value) - { - // Require a dictionary adapter - var source = value as IDictionaryAdapter; - if (source == null) - throw Error.NotDictionaryAdapter(nameof(value)); - - // Detect assignment of own value - var sourceAdapter = XmlAdapter.For(source, false); - if (sourceAdapter != null && node.PositionEquals(sourceAdapter.Node)) - return; - - // Create a fresh component - var targetAdapter = new XmlAdapter(node.Save(), XmlAdapter.For(parent).References); - if (sourceAdapter != null) - targetAdapter.References.UnionWith(sourceAdapter.References); - var component = (IDictionaryAdapter) parent.CreateChildAdapter(node.ClrType, targetAdapter); - - // Copy value onto fresh component - source.CopyTo(component); - value = component; - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlCustomSerializer.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlCustomSerializer.cs deleted file mode 100644 index 72d21fd..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlCustomSerializer.cs +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - using System.Xml.Serialization; - - public class XmlCustomSerializer : XmlTypeSerializer - { - public static readonly XmlCustomSerializer - Instance = new XmlCustomSerializer(); - - private XmlCustomSerializer() { } - - public override XmlTypeKind Kind - { - get { return XmlTypeKind.Complex; } - } - - public override object GetValue(IXmlNode node, IDictionaryAdapter parent, IXmlAccessor accessor) - { - var serializable = (IXmlSerializable) Activator.CreateInstance(node.ClrType); - - using (var reader = new XmlSubtreeReader(node, XmlDefaultSerializer.Root)) - { - // Do NOT pre-read containing element - // ...IXmlSerializable is not a symmetric contract - serializable.ReadXml(reader); - } - - return serializable; - } - - public override void SetValue(IXmlNode node, IDictionaryAdapter parent, IXmlAccessor accessor, object oldValue, ref object value) - { - var serializable = (IXmlSerializable) value; - var root = XmlDefaultSerializer.Root; - - using (var writer = new XmlSubtreeWriter(node)) - { - // Pre-write containing element - writer.WriteStartElement(string.Empty, root.ElementName, root.Namespace); - serializable.WriteXml(writer); - writer.WriteEndElement(); - } - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlDefaultSerializer.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlDefaultSerializer.cs deleted file mode 100644 index 5b13413..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlDefaultSerializer.cs +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - using System.Xml.Serialization; - - public class XmlDefaultSerializer : XmlTypeSerializer - { - private readonly XmlSerializer serializer; - - public XmlDefaultSerializer(Type type) - { - serializer = new XmlSerializer(type, Root); - } - - public override XmlTypeKind Kind - { - get { return XmlTypeKind.Complex; } - } - - public override object GetValue(IXmlNode node, IDictionaryAdapter parent, IXmlAccessor accessor) - { - using (var reader = new XmlSubtreeReader(node, Root)) - return serializer.CanDeserialize(reader) - ? serializer.Deserialize(reader) - : null; - } - - public override void SetValue(IXmlNode node, IDictionaryAdapter parent, IXmlAccessor accessor, object oldValue, ref object value) - { - using (var writer = new XmlSubtreeWriter(node)) - serializer.Serialize(writer, value); - } - - public static readonly XmlRootAttribute - Root = new XmlRootAttribute - { - ElementName = "Root", - Namespace = string.Empty - }; - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlDynamicSerializer.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlDynamicSerializer.cs deleted file mode 100644 index 565b990..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlDynamicSerializer.cs +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - public class XmlDynamicSerializer : XmlTypeSerializer - { - public static readonly XmlDynamicSerializer - Instance = new XmlDynamicSerializer(); - - protected XmlDynamicSerializer() { } - - public override XmlTypeKind Kind - { - get { return XmlTypeKind.Simple; } - } - - public override object GetValue(IXmlNode node, IDictionaryAdapter parent, IXmlAccessor accessor) - { - return node.ClrType == typeof(object) - ? new object() - : XmlTypeSerializer.For(node.ClrType).GetValue(node, parent, accessor); - } - - public override void SetValue(IXmlNode node, IDictionaryAdapter parent, IXmlAccessor accessor, object oldValue, ref object value) - { - if (node.ClrType != typeof(object)) - XmlTypeSerializer.For(node.ClrType).SetValue(node, parent, accessor, oldValue, ref value); - else - node.Clear(); - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlEnumerationSerializer.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlEnumerationSerializer.cs deleted file mode 100644 index 08013a2..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlEnumerationSerializer.cs +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - - public class XmlEnumerationSerializer : XmlStringSerializer - { - public static readonly new XmlEnumerationSerializer - Instance = new XmlEnumerationSerializer(); - - protected XmlEnumerationSerializer() { } - - public override XmlTypeKind Kind - { - get { return XmlTypeKind.Simple; } - } - - public override object GetValue(IXmlNode node, IDictionaryAdapter parent, IXmlAccessor accessor) - { - return Enum.Parse(node.ClrType, node.Value, true); - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlListSerializer.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlListSerializer.cs deleted file mode 100644 index 46341bd..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlListSerializer.cs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - - public class XmlListSerializer : XmlCollectionSerializer - { - public static readonly XmlListSerializer - Instance = new XmlListSerializer(); - - protected XmlListSerializer() { } - - public override Type ListTypeConstructor - { - get { return typeof(XmlNodeList<>); } - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlSetSerializer.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlSetSerializer.cs deleted file mode 100644 index 00003c0..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlSetSerializer.cs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - - public class XmlSetSerializer : XmlCollectionSerializer - { - public static readonly XmlSetSerializer - Instance = new XmlSetSerializer(); - - protected XmlSetSerializer() { } - - public override Type ListTypeConstructor - { - get { return typeof(XmlNodeSet<>); } - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlSimpleSerializer.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlSimpleSerializer.cs deleted file mode 100644 index 7eeff28..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlSimpleSerializer.cs +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - using System.Xml; - - public class XmlSimpleSerializer : XmlTypeSerializer - { - private readonly Func getString; - private readonly Func getObject; - - public XmlSimpleSerializer( - Func getString, - Func getObject) - { - this.getString = getString; - this.getObject = getObject; - } - - public override XmlTypeKind Kind - { - get { return XmlTypeKind.Simple; } - } - - public override object GetValue(IXmlNode node, IDictionaryAdapter parent, IXmlAccessor accessor) - { - return getObject(node.Value); - } - - public override void SetValue(IXmlNode node, IDictionaryAdapter parent, IXmlAccessor accessor, object oldValue, ref object value) - { - node.Value = getString((T) value); - } - } - - public static class XmlSimpleSerializer - { - public static readonly XmlTypeSerializer - ForBoolean = new XmlSimpleSerializer (XmlConvert.ToString, XmlConvert.ToBoolean), - ForChar = new XmlSimpleSerializer (XmlConvert.ToString, XmlConvert.ToChar), - ForSByte = new XmlSimpleSerializer (XmlConvert.ToString, XmlConvert.ToSByte), - ForInt16 = new XmlSimpleSerializer (XmlConvert.ToString, XmlConvert.ToInt16), - ForInt32 = new XmlSimpleSerializer (XmlConvert.ToString, XmlConvert.ToInt32), - ForInt64 = new XmlSimpleSerializer (XmlConvert.ToString, XmlConvert.ToInt64), - ForByte = new XmlSimpleSerializer (XmlConvert.ToString, XmlConvert.ToByte), - ForUInt16 = new XmlSimpleSerializer (XmlConvert.ToString, XmlConvert.ToUInt16), - ForUInt32 = new XmlSimpleSerializer (XmlConvert.ToString, XmlConvert.ToUInt32), - ForUInt64 = new XmlSimpleSerializer (XmlConvert.ToString, XmlConvert.ToUInt64), - ForSingle = new XmlSimpleSerializer (XmlConvert.ToString, XmlConvert.ToSingle), - ForDouble = new XmlSimpleSerializer (XmlConvert.ToString, XmlConvert.ToDouble), - ForDecimal = new XmlSimpleSerializer (XmlConvert.ToString, XmlConvert.ToDecimal), - ForTimeSpan = new XmlSimpleSerializer (XmlConvert.ToString, XmlConvert.ToTimeSpan), - ForDateTime = new XmlSimpleSerializer (XmlConvert_ToString, XmlConvert_ToDateTime), - ForDateTimeOffset = new XmlSimpleSerializer (XmlConvert.ToString, XmlConvert.ToDateTimeOffset), - ForGuid = new XmlSimpleSerializer (XmlConvert.ToString, XmlConvert.ToGuid), - ForByteArray = new XmlSimpleSerializer (Convert.ToBase64String, Convert.FromBase64String), - ForUri = new XmlSimpleSerializer (u => u.ToString(), s => new Uri(s, UriKind.RelativeOrAbsolute)); - - private static string XmlConvert_ToString(DateTime value) - { - return XmlConvert.ToString(value, XmlDateTimeSerializationMode.RoundtripKind); - } - - private static DateTime XmlConvert_ToDateTime(string value) - { - return XmlConvert.ToDateTime(value, XmlDateTimeSerializationMode.RoundtripKind); - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlStringSerializer.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlStringSerializer.cs deleted file mode 100644 index 0ddbf72..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlStringSerializer.cs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - public class XmlStringSerializer : XmlTypeSerializer - { - public static readonly XmlStringSerializer - Instance = new XmlStringSerializer(); - - protected XmlStringSerializer() { } - - public override XmlTypeKind Kind - { - get { return XmlTypeKind.Simple; } - } - - public override object GetValue(IXmlNode node, IDictionaryAdapter parent, IXmlAccessor accessor) - { - return node.Value; - } - - public override void SetValue(IXmlNode node, IDictionaryAdapter parent, IXmlAccessor accessor, object oldValue, ref object value) - { - node.Value = value.ToString(); - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlTypeKind.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlTypeKind.cs deleted file mode 100644 index c495b85..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlTypeKind.cs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - public enum XmlTypeKind - { - Simple, - Complex, - Collection - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlTypeSerializer.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlTypeSerializer.cs deleted file mode 100644 index 30b0896..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlTypeSerializer.cs +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - - public abstract class XmlTypeSerializer - { - protected XmlTypeSerializer() { } - - public abstract XmlTypeKind Kind - { - get; - } - - public virtual bool CanGetStub - { - get { return false; } - } - - public virtual object GetStub (IXmlNode node, IDictionaryAdapter parent, IXmlAccessor accessor) { throw Error.NotSupported(); } - public abstract object GetValue(IXmlNode node, IDictionaryAdapter parent, IXmlAccessor accessor); - public abstract void SetValue(IXmlNode node, IDictionaryAdapter parent, IXmlAccessor accessor, object oldValue, ref object value); - - public static XmlTypeSerializer For(Type type) - { - return XmlTypeSerializerCache.Instance[type]; - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlTypeSerializerCache.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlTypeSerializerCache.cs deleted file mode 100644 index df11f50..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlTypeSerializerCache.cs +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - using System.Collections.Generic; - using System.ComponentModel; - using System.Reflection; - using System.Xml.Serialization; - - internal class XmlTypeSerializerCache : SingletonDispenser - { - public static readonly XmlTypeSerializerCache - Instance = new XmlTypeSerializerCache(); - - private XmlTypeSerializerCache() - : base(CreateSerializer) - { - this[typeof(Object)] = XmlDynamicSerializer.Instance; - this[typeof(String)] = XmlStringSerializer.Instance; - this[typeof(Boolean)] = XmlSimpleSerializer.ForBoolean; - this[typeof(Char)] = XmlSimpleSerializer.ForChar; - this[typeof(SByte)] = XmlSimpleSerializer.ForSByte; - this[typeof(Int16)] = XmlSimpleSerializer.ForInt16; - this[typeof(Int32)] = XmlSimpleSerializer.ForInt32; - this[typeof(Int64)] = XmlSimpleSerializer.ForInt64; - this[typeof(Byte)] = XmlSimpleSerializer.ForByte; - this[typeof(UInt16)] = XmlSimpleSerializer.ForUInt16; - this[typeof(UInt32)] = XmlSimpleSerializer.ForUInt32; - this[typeof(UInt64)] = XmlSimpleSerializer.ForUInt64; - this[typeof(Single)] = XmlSimpleSerializer.ForSingle; - this[typeof(Double)] = XmlSimpleSerializer.ForDouble; - this[typeof(Decimal)] = XmlSimpleSerializer.ForDecimal; - this[typeof(TimeSpan)] = XmlSimpleSerializer.ForTimeSpan; - this[typeof(DateTime)] = XmlSimpleSerializer.ForDateTime; - this[typeof(DateTimeOffset)] = XmlSimpleSerializer.ForDateTimeOffset; - this[typeof(Guid)] = XmlSimpleSerializer.ForGuid; - this[typeof(Byte[])] = XmlSimpleSerializer.ForByteArray; - this[typeof(Uri)] = XmlSimpleSerializer.ForUri; - } - - private static XmlTypeSerializer CreateSerializer(Type type) - { - if (type.IsArray) - return XmlArraySerializer.Instance; - - if (type.IsGenericType) - { - var genericType = type.GetGenericTypeDefinition(); - if (genericType == typeof(IList<>) || - genericType == typeof(ICollection<>) || - genericType == typeof(IEnumerable<>) || - genericType == typeof(IBindingList<>)) - return XmlListSerializer.Instance; - if (genericType == typeof(ISet<>)) - return XmlSetSerializer.Instance; - if (// Dictionaries are not supported - genericType == typeof(IDictionary<,>) || - genericType == typeof(Dictionary<,>) || - genericType == typeof(SortedDictionary<,>) || - // Concrete list types are not supported - genericType == typeof(List<>) || - genericType == typeof(Stack<>) || - genericType == typeof(Queue<>) || - genericType == typeof(LinkedList<>) || - genericType == typeof(SortedList<,>) || - // Concrete set types are not supported - genericType == typeof(HashSet<>) || - genericType == typeof(SortedSet<>) || - // CLR binding list is not supported; use Castle version - genericType == typeof(BindingList<>)) - throw Error.UnsupportedCollectionType(type); - } - - if (type.IsInterface) - return XmlComponentSerializer.Instance; - if (type.IsEnum) - return XmlEnumerationSerializer.Instance; - if (type.IsCustomSerializable()) - return XmlCustomSerializer.Instance; - if (typeof(System.Xml.XmlNode).IsAssignableFrom(type)) - return XmlXmlNodeSerializer.Instance; - return new XmlDefaultSerializer(type); - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlXmlNodeSerializer.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlXmlNodeSerializer.cs deleted file mode 100644 index a693bcc..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Serializers/XmlXmlNodeSerializer.cs +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - using System.Xml; - - public class XmlXmlNodeSerializer : XmlTypeSerializer - { - public static readonly XmlXmlNodeSerializer - Instance = new XmlXmlNodeSerializer(); - - private XmlXmlNodeSerializer() { } - - public override XmlTypeKind Kind - { - get { return XmlTypeKind.Complex; } - } - - public override object GetValue(IXmlNode node, IDictionaryAdapter parent, IXmlAccessor accessor) - { - var source = node.AsRealizable(); - - return (source != null && source.IsReal) - ? source.Value - : null; - } - - public override void SetValue(IXmlNode node, IDictionaryAdapter parent, IXmlAccessor accessor, object oldValue, ref object value) - { - var newNode = (XmlNode) value; - - using (var writer = new XmlSubtreeWriter(node)) - newNode.WriteTo(writer); - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/IXmlIdentity.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/IXmlIdentity.cs deleted file mode 100644 index 22eff4e..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/IXmlIdentity.cs +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - public interface IXmlIdentity - { - XmlName Name { get; } - XmlName XsiType { get; } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/IXmlIncludedType.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/IXmlIncludedType.cs deleted file mode 100644 index 2039d60..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/IXmlIncludedType.cs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - - public interface IXmlIncludedType - { - XmlName XsiType { get; } - Type ClrType { get; } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/IXmlIncludedTypeMap.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/IXmlIncludedTypeMap.cs deleted file mode 100644 index 48b5488..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/IXmlIncludedTypeMap.cs +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - - public interface IXmlIncludedTypeMap - { - IXmlIncludedType Default { get; } - - bool TryGet(XmlName xsiType, out IXmlIncludedType includedType); - bool TryGet(Type clrType, out IXmlIncludedType includedType); - } - - public static class XmlIncludedTypeMapExtensions - { - public static IXmlIncludedType Require(this IXmlIncludedTypeMap includedTypes, Type clrType) - { - IXmlIncludedType includedType; - if (includedTypes.TryGet(clrType, out includedType)) - return includedType; - - throw Error.NotXmlKnownType(clrType); - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/IXmlKnownType.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/IXmlKnownType.cs deleted file mode 100644 index 3bbdfb3..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/IXmlKnownType.cs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - - public interface IXmlKnownType : IXmlIdentity - { - Type ClrType { get; } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/IXmlKnownTypeMap.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/IXmlKnownTypeMap.cs deleted file mode 100644 index 282b3af..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/IXmlKnownTypeMap.cs +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - - public interface IXmlKnownTypeMap - { - IXmlKnownType Default { get; } - - bool TryGet(IXmlIdentity xmlNode, out IXmlKnownType knownType); - bool TryGet(Type clrType, out IXmlKnownType knownType); - } - - public static class XmlKnownTypeMapExtensions - { - public static IXmlKnownType Require(this IXmlKnownTypeMap map, Type clrType) - { - IXmlKnownType knownType; - if (map.TryGet(clrType, out knownType)) - return knownType; - - throw Error.NotXmlKnownType(clrType); - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/XmlIncludedType.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/XmlIncludedType.cs deleted file mode 100644 index 9106a30..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/XmlIncludedType.cs +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - - public class XmlIncludedType : IXmlIncludedType - { - private readonly XmlName xsiType; - private readonly Type clrType; - - public XmlIncludedType(XmlName xsiType, Type clrType) - { - if (xsiType.LocalName == null) - throw Error.ArgumentNull("xsiType.LocalName"); - if (clrType == null) - throw Error.ArgumentNull(nameof(clrType)); - - this.xsiType = xsiType; - this.clrType = clrType; - } - - public XmlIncludedType(string localName, string namespaceUri, Type clrType) - : this(new XmlName(localName, namespaceUri), clrType) { } - - public XmlName XsiType - { - get { return xsiType; } - } - - public Type ClrType - { - get { return clrType; } - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/XmlIncludedTypeSet.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/XmlIncludedTypeSet.cs deleted file mode 100644 index edf6e73..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/XmlIncludedTypeSet.cs +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - using System.Collections; - using System.Collections.Generic; - - public class XmlIncludedTypeSet : IXmlIncludedTypeMap, IEnumerable - { - private readonly Dictionary itemsByXsiType; - private readonly Dictionary itemsByClrType; - - public XmlIncludedTypeSet() - { - itemsByXsiType = new Dictionary(); - itemsByClrType = new Dictionary(); - - foreach (var includedType in DefaultEntries) - Add(includedType); - } - - IXmlIncludedType IXmlIncludedTypeMap.Default - { - get { throw Error.NoDefaultKnownType(); } - } - - public void Add(IXmlIncludedType includedType) - { - // Allow only one item per xsi:type - itemsByXsiType.Add(includedType.XsiType, includedType); - - // Overwrite any prior entry for CLR type - itemsByClrType[includedType.ClrType] = includedType; - } - - public bool TryGet(XmlName xsiType, out IXmlIncludedType includedType) - { - return itemsByXsiType.TryGetValue(xsiType, out includedType); - } - - public bool TryGet(Type clrType, out IXmlIncludedType includedType) - { - return itemsByClrType.TryGetValue(clrType, out includedType); - } - - public IEnumerator GetEnumerator() - { - return itemsByXsiType.Values.GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - public static readonly IList DefaultEntries - = Array.AsReadOnly(new IXmlIncludedType[] - { - new XmlIncludedType("anyType", Xsd .NamespaceUri, typeof(object)), - new XmlIncludedType("string", Xsd .NamespaceUri, typeof(string)), - new XmlIncludedType("boolean", Xsd .NamespaceUri, typeof(bool)), - new XmlIncludedType("byte", Xsd .NamespaceUri, typeof(sbyte)), - new XmlIncludedType("unsignedByte", Xsd .NamespaceUri, typeof(byte)), - new XmlIncludedType("short", Xsd .NamespaceUri, typeof(short)), - new XmlIncludedType("unsignedShort", Xsd .NamespaceUri, typeof(ushort)), - new XmlIncludedType("int", Xsd .NamespaceUri, typeof(int)), - new XmlIncludedType("unsignedInt", Xsd .NamespaceUri, typeof(uint)), - new XmlIncludedType("long", Xsd .NamespaceUri, typeof(long)), - new XmlIncludedType("unsignedLong", Xsd .NamespaceUri, typeof(ulong)), - new XmlIncludedType("float", Xsd .NamespaceUri, typeof(float)), - new XmlIncludedType("double", Xsd .NamespaceUri, typeof(double)), - new XmlIncludedType("decimal", Xsd .NamespaceUri, typeof(decimal)), - new XmlIncludedType("guid", Wsdl.NamespaceUri, typeof(Guid)), - new XmlIncludedType("dateTime", Xsd .NamespaceUri, typeof(DateTime)), -// new XmlIncludedType("dateTime", Xsd .NamespaceUri, typeof(DateTimeOffset)), TODO: Find a way to enable this without duplicate key exception. - new XmlIncludedType("duration", Xsd .NamespaceUri, typeof(TimeSpan)), - new XmlIncludedType("base64Binary", Xsd .NamespaceUri, typeof(byte[])), - new XmlIncludedType("anyURI", Xsd .NamespaceUri, typeof(Uri)), - new XmlIncludedType("QName", Xsd .NamespaceUri, typeof(System.Xml.XmlQualifiedName)) - }); - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/XmlKnownType.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/XmlKnownType.cs deleted file mode 100644 index c1d4f7b..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/XmlKnownType.cs +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - - public class XmlKnownType : IXmlKnownType - { - private readonly XmlName name; - private readonly XmlName xsiType; - private readonly Type clrType; - - public XmlKnownType(XmlName name, XmlName xsiType, Type clrType) - { - if (name.LocalName == null) - throw Error.ArgumentNull("name.LocalName"); - if (clrType == null) - throw Error.ArgumentNull(nameof(clrType)); - - this.name = name; - this.xsiType = xsiType; - this.clrType = clrType; - } - - public XmlKnownType(string nameLocalName, string nameNamespaceUri, string xsiTypeLocalName, string xsiTypeNamespaceUri, Type clrType) - : this - ( - new XmlName(nameLocalName, nameNamespaceUri), - new XmlName(xsiTypeLocalName, xsiTypeNamespaceUri), - clrType - ) - { } - - public XmlName Name - { - get { return name; } - } - - public XmlName XsiType - { - get { return xsiType; } - } - - public Type ClrType - { - get { return clrType; } - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/XmlKnownTypeSet.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/XmlKnownTypeSet.cs deleted file mode 100644 index d29f139..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Types/XmlKnownTypeSet.cs +++ /dev/null @@ -1,176 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - using System.Collections; - using System.Collections.Generic; - using System.Linq; - - public class XmlKnownTypeSet : IXmlKnownTypeMap, IEnumerable - { - private readonly Dictionary itemsByXmlIdentity; - private readonly Dictionary itemsByClrType; - private readonly Type defaultType; - - public XmlKnownTypeSet(Type defaultType) - { - if (defaultType == null) - throw Error.ArgumentNull(nameof(defaultType)); - - itemsByXmlIdentity = new Dictionary(XmlIdentityComparer.Instance); - itemsByClrType = new Dictionary(); - this.defaultType = defaultType; - } - - public IXmlKnownType Default - { - get - { - IXmlKnownType knownType; - if (defaultType == null || !TryGet(defaultType, out knownType)) - throw Error.NoDefaultKnownType(); - return knownType; - } - } - - public void Add(IXmlKnownType knownType, bool overwrite) - { - // All XmlTypes are present here - if (overwrite || !itemsByXmlIdentity.ContainsKey(knownType)) - itemsByXmlIdentity[knownType] = knownType; - - // Only contains the default XmlType for each ClrType - var clrType = knownType.ClrType; - if (overwrite || !itemsByClrType.ContainsKey(clrType)) - itemsByClrType[clrType] = knownType; - } - - public void AddXsiTypeDefaults() - { - // If there is only one xsi:type possible for a known local name and namespace URI, - // add another XmlType to recognize nodes that don't provide the xsi:type. - - var bits = new Dictionary( - itemsByXmlIdentity.Count, - XmlKnownTypeNameComparer.Instance); - - foreach (var knownType in itemsByXmlIdentity.Values) - { - bool bit; - bits[knownType] = bits.TryGetValue(knownType, out bit) - ? false // another by same name; can't add a default - : knownType.XsiType != XmlName.Empty; // first by this name; can add a default, if not already in default form - } - - foreach (var pair in bits) - { - if (pair.Value) - { - var template = pair.Key; - var knownType = new XmlKnownType(template.Name, XmlName.Empty, template.ClrType); - Add(knownType, true); - } - } - } - - public bool TryGet(IXmlIdentity xmlIdentity, out IXmlKnownType knownType) - { - return itemsByXmlIdentity.TryGetValue(xmlIdentity, out knownType); - } - - public bool TryGet(Type clrType, out IXmlKnownType knownType) - { - return itemsByClrType.TryGetValue(clrType, out knownType); - } - - public IXmlKnownType[] ToArray() - { - return itemsByXmlIdentity.Values.ToArray(); - } - - public IEnumerator GetEnumerator() - { - return itemsByXmlIdentity.Values.GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return itemsByXmlIdentity.Values.GetEnumerator(); - } - - private sealed class XmlIdentityComparer : IEqualityComparer - { - public static readonly XmlIdentityComparer - Instance = new XmlIdentityComparer(); - - private XmlIdentityComparer() { } - - public bool Equals(IXmlIdentity x, IXmlIdentity y) - { - var nameX = x.Name; - var nameY = y.Name; - - if (!NameComparer.Equals(nameX.LocalName, nameY.LocalName)) - return false; - - if (!XsiTypeComparer.Equals(x.XsiType, y.XsiType)) - return false; - - return nameX.NamespaceUri == null - || nameY.NamespaceUri == null - || NameComparer.Equals(nameX.NamespaceUri, nameY.NamespaceUri); - } - - public int GetHashCode(IXmlIdentity name) - { - var code = NameComparer.GetHashCode(name.Name.LocalName); - - if (name.XsiType != XmlName.Empty) - code = (code << 7 | code >> 25) - ^ XsiTypeComparer.GetHashCode(name.XsiType); - - // DO NOT include NamespaceUri in hash code. - // That would break 'null means any' behavior. - - return code; - } - } - - private sealed class XmlKnownTypeNameComparer : IEqualityComparer - { - public static readonly XmlKnownTypeNameComparer - Instance = new XmlKnownTypeNameComparer(); - - private XmlKnownTypeNameComparer() { } - - public bool Equals(IXmlKnownType knownTypeA, IXmlKnownType knownTypeB) - { - return XmlNameComparer.IgnoreCase.Equals(knownTypeA.Name, knownTypeB.Name); - } - - public int GetHashCode(IXmlKnownType knownType) - { - return XmlNameComparer.IgnoreCase.GetHashCode(knownType.Name); - } - } - - private static readonly StringComparer - NameComparer = StringComparer.OrdinalIgnoreCase; - - private static readonly XmlNameComparer - XsiTypeComparer = XmlNameComparer.Default; - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/DictionaryAdapterExtensions.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/DictionaryAdapterExtensions.cs deleted file mode 100644 index 7281f9a..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/DictionaryAdapterExtensions.cs +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - using System.Linq; - using System.Collections; - - public static class DictionaryAdapterExtensions - { - public static object CreateChildAdapter(this IDictionaryAdapter parent, Type type, XmlAdapter adapter) - { - return CreateChildAdapter(parent, type, adapter, null); - } - - public static object CreateChildAdapter(this IDictionaryAdapter parent, Type type, XmlAdapter adapter, IDictionary dictionary) - { - if (null == dictionary) - dictionary = new Hashtable(); - - var descriptor = parent.Meta.CreateDescriptor(); - parent.This.Descriptor.CopyBehaviors(descriptor); - descriptor.AddBehavior(adapter); - - return parent.This.Factory.GetAdapter(type, dictionary, descriptor); - } - - public static bool HasAccessor(this PropertyDescriptor property) - { - return property.ExtendedProperties.Contains(XmlAccessorKey); - } - - public static XmlAccessor GetAccessor(this PropertyDescriptor property) - { - return (XmlAccessor) property.ExtendedProperties[XmlAccessorKey]; - } - - public static void SetAccessor(this PropertyDescriptor property, XmlAccessor accessor) - { - property.ExtendedProperties[XmlAccessorKey] = accessor; - } - - public static bool HasXmlMeta(this DictionaryAdapterMeta meta) - { - return meta.ExtendedProperties.Contains(XmlMetaKey); - } - - public static XmlMetadata GetXmlMeta(this DictionaryAdapterMeta meta) - { - return (XmlMetadata) meta.ExtendedProperties[XmlMetaKey]; - } - - public static void SetXmlMeta(this DictionaryAdapterMeta meta, XmlMetadata xmlMeta) - { - meta.ExtendedProperties[XmlMetaKey] = xmlMeta; - } - - public static bool HasXmlType(this DictionaryAdapterMeta meta) - { - return meta.ExtendedProperties.Contains(XmlTypeKey); - } - - public static string GetXmlType(this DictionaryAdapterMeta meta) - { - return (string) meta.ExtendedProperties[XmlTypeKey]; - } - - public static void SetXmlType(this DictionaryAdapterMeta meta, string value) - { - meta.ExtendedProperties[XmlTypeKey] = value; - } - - private const string - XmlAccessorKey = "XmlAccessor", - XmlMetaKey = "XmlMeta", - XmlTypeKey = "XmlType"; - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/Error.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/Error.cs deleted file mode 100644 index dc84631..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/Error.cs +++ /dev/null @@ -1,219 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - using SerializationException = System.Runtime.Serialization.SerializationException; - using System.Xml.XPath; - - internal static class Error - { - internal static Exception ArgumentNull(string paramName) - { - return new ArgumentNullException(paramName); - } - - internal static Exception ArgumentOutOfRange(string paramName) - { - return new ArgumentOutOfRangeException(paramName); - } - - internal static Exception InvalidOperation() - { - return new InvalidOperationException(); - } - - internal static Exception NotSupported() - { - return new NotSupportedException(); - } - - internal static Exception ObjectDisposed(string objectName) - { - return new ObjectDisposedException(objectName); - } - - internal static Exception AttributeConflict(string propertyName) - { - var message = string.Format - ( - "The behaviors defined for property '{0}' are ambiguous or conflicting.", - propertyName - ); - return new InvalidOperationException(message); - } - - internal static Exception SeparateGetterSetterOnComplexType(string propertyName) - { - var message = string.Format - ( - "Cannot apply getter/setter behaviors for property '{0}'. Separate getters/setters are supported for simple types only.", - propertyName - ); - return new InvalidOperationException(message); - } - - internal static Exception XmlMetadataNotAvailable(Type clrType) - { - var message = string.Format - ( - "XML metadata is not available for type '{0}'.", - clrType.FullName - ); - return new InvalidOperationException(message); - } - - internal static Exception NotDictionaryAdapter(string paramName) - { - var message = "The argument is not a dictionary adapter."; - return new ArgumentException(message, paramName); - } - - internal static Exception NoInstanceDescriptor(string paramName) - { - var message = "The dictionary adapter does not have an instance descriptor."; - return new ArgumentException(message, paramName); - } - - internal static Exception NoXmlAdapter(string paramName) - { - var message = "The dictionary adapter does not have XmlAdapter behavior."; - return new ArgumentException(message, paramName); - } - - internal static Exception NotRealizable() - { - var message = string.Format( - "The given node cannot provide an underlying object of type {0}.", - typeof(T).FullName); - return new NotSupportedException(message); - } - - internal static Exception CursorNotMutable() - { - var message = "The cursor does not support creation, removal, or modification of nodes."; - return new NotSupportedException(message); - } - - internal static Exception CursorNotInCreatableState() - { - var message = "The cursor cannot create nodes in its current state."; - return new InvalidOperationException(message); - } - - internal static Exception CursorNotInRemovableState() - { - var message = "The cursor cannot remove nodes in its current state."; - return new InvalidOperationException(message); - } - - internal static Exception CursorNotInCoercibleState() - { - var message = "The cursor cannot change node types in its current state."; - return new InvalidOperationException(message); - } - - internal static Exception CursorNotInRealizableState() - { - var message = "The cursor cannot realize virtual nodes in its current state"; - return new InvalidOperationException(message); - } - - internal static Exception CursorCannotMoveToGivenNode() - { - var message = "The cursor cannot move to the given node."; - return new InvalidOperationException(message); - } - - internal static Exception CannotSetAttribute(IXmlIdentity identity) - { - var message = string.Format - ( - "Cannot set attribute on node '{0}'.", - identity.Name.ToString() - ); - return new InvalidOperationException(message); - } - - internal static Exception NotXmlKnownType(Type clrType) - { - var message = string.Format - ( - "No XML type is defined for CLR type {0}.", - clrType.FullName - ); - return new SerializationException(message); - } - - internal static Exception UnsupportedCollectionType(Type clrType) - { - var message = string.Format - ( - "Unsupported collection type: {0}.", - clrType.FullName - ); - return new SerializationException(message); - } - - internal static Exception NotCollectionType(string paramName) - { - var message = "The argument is not a valid collection type."; - return new ArgumentException(message, paramName); - } - - - internal static Exception InvalidLocalName() - { - var message = "Invalid local name."; - return new FormatException(message); - } - - internal static Exception InvalidNamespaceUri() - { - var message = "Invalid namespace URI."; - return new FormatException(message); - } - - internal static Exception NoDefaultKnownType() - { - var message = "No default XML type exists in the given context."; - return new InvalidOperationException(message); - } - - internal static Exception XPathNotCreatable(CompiledXPath path) - { - var message = string.Format( - "The path '{0}' is not a creatable XPath expression.", - path.Path.Expression); - return new XPathException(message); - } - - internal static Exception XPathNavigationFailed(XPathExpression path) - { - var message = string.Format( - "Failed navigation to {0} element after creation.", - path.Expression); - return new XPathException(message); - } - - internal static Exception ObjectIdNotFound(string id) - { - var message = string.Format( - "No object with ID '{0}' was present in the XML.", - id); - return new SerializationException(message); - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/IConfigurable.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/IConfigurable.cs deleted file mode 100644 index f52250a..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/IConfigurable.cs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - public interface IConfigurable - { - void Configure(T value); - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/IRealizable.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/IRealizable.cs deleted file mode 100644 index 2ab75e7..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/IRealizable.cs +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - // OBSOLETE: This has been replaced with IVirtual. - - public interface IRealizable : IRealizableSource - { - bool IsReal { get; } - T Value { get; } - } - - public interface IRealizableSource - { - IRealizable AsRealizable(); - } - - public static class RealizableExtensions - { - public static IRealizable RequireRealizable(this IRealizableSource obj) - { - var realizable = obj.AsRealizable(); - if (realizable == null) - throw Error.NotRealizable(); - return realizable; - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/SingletonDispenser.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/SingletonDispenser.cs deleted file mode 100644 index c3a9a01..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/SingletonDispenser.cs +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - using System.Collections.Generic; - using System.Threading; - - public class SingletonDispenser - where TItem : class - { - private readonly ReaderWriterLockSlim locker; - private readonly Dictionary items; - private readonly Func factory; - - public SingletonDispenser(Func factory) - { - if (factory == null) - throw Error.ArgumentNull(nameof(factory)); - - this.locker = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion); - this.items = new Dictionary(); - this.factory = factory; - } - - public TItem this[TKey key] - { - get { return GetOrCreate(key); } - protected set { items[key] = value; } - } - - private TItem GetOrCreate(TKey key) - { - object item; - return TryGetExistingItem(key, out item) - ? item as TItem ?? WaitForCreate(key, item) - : Create(key, item); - } - - private bool TryGetExistingItem(TKey key, out object item) - { - locker.EnterReadLock(); - try - { - if (items.TryGetValue(key, out item)) - { - return true; - } - } - finally - { - locker.ExitReadLock(); - } - - locker.EnterUpgradeableReadLock(); - try - { - if (items.TryGetValue(key, out item)) - { - return true; - } - else - { - locker.EnterWriteLock(); - try - { - items[key] = item = new ManualResetEvent(false); - return false; - } - finally - { - locker.ExitWriteLock(); - } - } - } - finally - { - locker.ExitUpgradeableReadLock(); - } - } - - private TItem WaitForCreate(TKey key, object item) - { - var handle = (ManualResetEvent) item; - - handle.WaitOne(); - - locker.EnterReadLock(); - try - { - return (TItem)items[key]; - } - finally - { - locker.ExitReadLock(); - } - } - - private TItem Create(TKey key, object item) - { - var handle = (ManualResetEvent) item; - - var result = factory(key); - - locker.EnterWriteLock(); - try - { - items[key] = result; - } - finally - { - locker.ExitWriteLock(); - } - - handle.Set(); - return result; - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/StringExtensions.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/StringExtensions.cs deleted file mode 100644 index df756f1..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/StringExtensions.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - - internal static class StringExtensions - { - public static string NonEmpty(this string s) - { - return string.IsNullOrEmpty(s) ? null : s; - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/Try.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/Try.cs deleted file mode 100644 index 224da76..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/Try.cs +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System.Diagnostics; - - public static class Try - { - [DebuggerHidden] - public static bool Failure(out T result) - { - result = default(T); - return false; - } - - [DebuggerHidden] - public static bool Success(out T result, T value) - { - result = value; - return true; - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/TypeExtensions.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/TypeExtensions.cs deleted file mode 100644 index 2989ddc..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/TypeExtensions.cs +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.f -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - using System.Linq; - using System.Reflection; - using System.Xml.Serialization; - - public static class TypeExtensions - { - public static Type NonNullable(this Type type) - { - return type.IsGenericType - && type.GetGenericTypeDefinition() == typeof(Nullable<>) - ? type.GetGenericArguments()[0] - : type; - } - - public static Type GetCollectionItemType(this Type type) - { - if (type.IsArray) - return type.GetElementType(); - if (type.IsGenericType) - return type.GetGenericArguments().Single(); - throw Error.NotCollectionType(nameof(type)); - } - - public static Type GetComponentType(this object obj) - { - var adapter = obj as IDictionaryAdapter; - return (adapter == null) - ? obj.GetType() - : adapter.Meta.Type; - } - - internal static bool IsCustomSerializable(this Type type) - { - return typeof(IXmlSerializable).IsAssignableFrom(type); - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/XmlSubtreeReader.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/XmlSubtreeReader.cs deleted file mode 100644 index 66812b3..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/XmlSubtreeReader.cs +++ /dev/null @@ -1,227 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - using System.Threading; - using System.Xml; - using System.Xml.Serialization; - - public class XmlSubtreeReader : XmlReader - { - private readonly string rootLocalName; - private readonly string rootNamespaceURI; - private string underlyingNamespaceURI; - private XmlReader reader; - - public XmlSubtreeReader(IXmlNode node, XmlRootAttribute root) - : this(node, root.ElementName, root.Namespace) { } - - public XmlSubtreeReader(IXmlNode node, string rootLocalName, string rootNamespaceUri) - { - if (null == node) - throw Error.ArgumentNull(nameof(node)); - if (null == rootLocalName) - throw Error.ArgumentNull(nameof(rootLocalName)); - - this.reader = node.ReadSubtree(); - this.rootLocalName = reader.NameTable.Add(rootLocalName); - this.rootNamespaceURI = rootNamespaceUri ?? string.Empty; - } - - protected override void Dispose(bool managed) - { - try { if (managed) DisposeReader(); } - finally { base.Dispose(managed); } - } - - private void DisposeReader() - { - IDisposable value = Interlocked.Exchange(ref reader, null); - if (null != value) value.Dispose(); - } - - public bool IsDisposed - { - get { return null == reader; } - } - - private void RequireNotDisposed() - { - if (IsDisposed) - throw Error.ObjectDisposed("XmlSubtreeReader"); - } - - protected XmlReader Reader - { - get { RequireNotDisposed(); return reader; } - } - - public override ReadState ReadState - { - get { return IsDisposed ? ReadState.Closed : reader.ReadState; } - } - - public override int Depth - { - get { return Reader.Depth; } - } - - public override XmlNodeType NodeType - { - get { return Reader.NodeType; } - } - - public bool IsAtRootElement - { - get - { - RequireNotDisposed(); - return - reader.ReadState == ReadState.Interactive && - reader.Depth == 0 && - ( - reader.NodeType == XmlNodeType.Element || - reader.NodeType == XmlNodeType.EndElement - ); - } - } - - public override bool EOF - { - get { return Reader.EOF; } - } - - public override string Prefix - { - get { return Reader.Prefix; } - } - - public override string LocalName - { - get { return IsAtRootElement ? rootLocalName : Reader.LocalName; } - } - - public override string NamespaceURI - { - get { return IsAtRootElement ? CaptureNamespaceUri() : TranslateNamespaceURI(); } - } - - private string CaptureNamespaceUri() - { - if (underlyingNamespaceURI == null) - underlyingNamespaceURI = Reader.NamespaceURI; - return rootNamespaceURI; - } - - private string TranslateNamespaceURI() - { - var actualNamespaceURI = Reader.NamespaceURI; - return actualNamespaceURI == underlyingNamespaceURI - ? rootNamespaceURI - : actualNamespaceURI; - } - - public override string Value - { - get { return Reader.Value; } - } - - public override bool IsEmptyElement - { - get { return Reader.IsEmptyElement; } - } - - public override int AttributeCount - { - get { return Reader.AttributeCount; } - } - - public override string BaseURI - { - get { return Reader.BaseURI; } - } - - public override XmlNameTable NameTable - { - get { return Reader.NameTable; } - } - - public override bool Read() - { - return Reader.Read(); - } - - public override bool MoveToElement() - { - return Reader.MoveToElement(); - } - - public override bool MoveToFirstAttribute() - { - return Reader.MoveToFirstAttribute(); - } - - public override bool MoveToNextAttribute() - { - return Reader.MoveToNextAttribute(); - } - - public override bool MoveToAttribute(string name) - { - return Reader.MoveToAttribute(name); - } - - public override bool MoveToAttribute(string name, string ns) - { - return Reader.MoveToAttribute(name, ns); - } - - public override bool ReadAttributeValue() - { - return Reader.ReadAttributeValue(); - } - - public override string GetAttribute(int i) - { - return Reader.GetAttribute(i); - } - - public override string GetAttribute(string name) - { - return Reader.GetAttribute(name); - } - - public override string GetAttribute(string name, string namespaceURI) - { - return Reader.GetAttribute(name, namespaceURI); - } - - public override string LookupNamespace(string prefix) - { - return Reader.LookupNamespace(prefix); - } - - public override void ResolveEntity() - { - Reader.ResolveEntity(); - } - - public override void Close() - { - if (!IsDisposed) reader.Close(); - } - } -} diff --git a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/XmlSubtreeWriter.cs b/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/XmlSubtreeWriter.cs deleted file mode 100644 index 1b44172..0000000 --- a/Castle.Core/Components.DictionaryAdapter/Xml/Internal/Utilities/XmlSubtreeWriter.cs +++ /dev/null @@ -1,355 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Components.DictionaryAdapter.Xml -{ - using System; - using System.Threading; - using System.Xml; - - // DEPTH: ROOT STATES: - // 0: [Start, Prolog] - // 1: [Element, Attribute] - // 2: ... [Content] - - public class XmlSubtreeWriter : XmlWriter - { - private readonly IXmlNode node; - private XmlWriter rootWriter; - private XmlWriter childWriter; - private WriteState state; - private int depth; - - public XmlSubtreeWriter(IXmlNode node) - { - if (node == null) - throw Error.ArgumentNull(nameof(node)); - - this.node = node; - } - - protected override void Dispose(bool managed) - { - try - { - if (managed) - { - Reset(WriteState.Closed); - DisposeWriter(ref rootWriter); - DisposeWriter(ref childWriter); - } - } - finally - { - base.Dispose(managed); - } - } - - private void DisposeWriter(ref XmlWriter writer) - { - var value = Interlocked.Exchange(ref writer, null); - if (null != value) value.Close(); - } - - private XmlWriter RootWriter - { - get { return rootWriter ?? (rootWriter = node.WriteAttributes()); } - } - - private XmlWriter ChildWriter - { - get { return childWriter ?? (childWriter = node.WriteChildren()); } - } - - private bool IsInRootAttribute - { - get { return state == WriteState.Attribute; } - } - - private bool IsInRoot - { - get { return depth > 0; } - } - - private bool IsInChild - { - get { return depth > 1; } - } - - public override WriteState WriteState - { - get { return (IsInRoot && state == WriteState.Content) ? childWriter.WriteState : state; } - } - - public override void WriteStartDocument(bool standalone) - { - WriteStartDocument(); - } - - public override void WriteStartDocument() - { - RequireState(WriteState.Start); - state = WriteState.Prolog; - // (do not write anything) - } - - public override void WriteDocType(string name, string pubid, string sysid, string subset) - { - RequireState(WriteState.Start, WriteState.Prolog); - state = WriteState.Prolog; - // (do not write anything) - } - - public override void WriteStartElement(string prefix, string localName, string ns) - { - try - { - if (IsInRoot) - { - ChildWriter.WriteStartElement(prefix, localName, ns); - state = WriteState.Content; - } - else // is in prolog - { - RequireState(WriteState.Start, WriteState.Prolog); - node.Clear(); - state = WriteState.Element; - } - depth++; - } - catch { Reset(WriteState.Error); throw; } - } - - private void WriteEndElement(Action action) - { - try - { - if (IsInChild) - { - action(ChildWriter); - state = WriteState.Content; - } - else // is in root (or prolog) - { - RequireState(WriteState.Element, WriteState.Content); - state = WriteState.Prolog; - } - depth--; - } - catch { Reset(WriteState.Error); throw; } - } - - public override void WriteEndElement() - { - WriteEndElement(w => w.WriteEndElement()); - } - - public override void WriteFullEndElement() - { - WriteEndElement(w => w.WriteFullEndElement()); - } - - private void WriteAttribute(Action action, WriteState entryState, WriteState exitState) - { - try - { - if (IsInChild) - { - action(ChildWriter); - } - else // is in root (or prolog) - { - RequireState(entryState); - action(RootWriter); - state = exitState; - } - } - catch { Reset(WriteState.Error); throw; } - } - - public override void WriteStartAttribute(string prefix, string localName, string ns) - { - WriteAttribute(w => w.WriteStartAttribute(prefix, localName, ns), - entryState: WriteState.Element, - exitState: WriteState.Attribute); - } - - public override void WriteEndAttribute() - { - WriteAttribute(w => w.WriteEndAttribute(), - entryState: WriteState.Attribute, - exitState: WriteState.Element); - } - - private void WriteElementOrAttributeContent(Action action) - { - try - { - if (IsInChild) - action(ChildWriter); - else if (IsInRootAttribute) - action(RootWriter); - else // is in root (or prolog) - { - RequireState(WriteState.Element, WriteState.Content); - action(ChildWriter); - state = WriteState.Content; - } - } - catch { Reset(WriteState.Error); throw; } - } - - public override void WriteString(string text) - { - WriteElementOrAttributeContent(w => w.WriteString(text)); - } - - public override void WriteCharEntity(char ch) - { - WriteElementOrAttributeContent(w => w.WriteCharEntity(ch)); - } - - public override void WriteSurrogateCharEntity(char lowChar, char highChar) - { - WriteElementOrAttributeContent(w => w.WriteSurrogateCharEntity(lowChar, highChar)); - } - - public override void WriteEntityRef(string name) - { - WriteElementOrAttributeContent(w => w.WriteEntityRef(name)); - } - - public override void WriteChars(char[] buffer, int index, int count) - { - WriteElementOrAttributeContent(w => w.WriteChars(buffer, index, count)); - } - - public override void WriteBase64(byte[] buffer, int index, int count) - { - WriteElementOrAttributeContent(w => w.WriteBase64(buffer, index, count)); - } - - public override void WriteRaw(string data) - { - WriteElementOrAttributeContent(w => w.WriteRaw(data)); - } - - public override void WriteRaw(char[] buffer, int index, int count) - { - WriteElementOrAttributeContent(w => w.WriteRaw(buffer, index, count)); - } - - private void WriteElementContent(Action action) - { - try - { - RequireState(WriteState.Element, WriteState.Content); - action(ChildWriter); - state = WriteState.Content; - } - catch { Reset(WriteState.Error); throw; } - } - - public override void WriteCData(string text) - { - WriteElementContent(w => w.WriteCData(text)); - } - - public override void WriteProcessingInstruction(string name, string text) - { - WriteElementContent(w => w.WriteProcessingInstruction(name, text)); - } - - public override void WriteComment(string text) - { - WriteElementContent(w => w.WriteComment(text)); - } - - public override void WriteWhitespace(string ws) - { - WriteElementContent(w => w.WriteWhitespace(ws)); - } - - private void WithWriters(Action action, bool worksIfClosed = false, WriteState? resetTo = null) - { - try - { - if (! worksIfClosed ) RequireNotClosed(); - if (null != rootWriter ) action(rootWriter); - if (null != childWriter) action(childWriter); - if (null != resetTo ) Reset(resetTo.Value); - } - catch { Reset(WriteState.Error); throw; } - } - - public override void Flush() - { - WithWriters(w => w.Flush()); - } - - public override void WriteEndDocument() - { - WithWriters(w => w.WriteEndDocument(), resetTo: WriteState.Start); - } - - public override void Close() - { - WithWriters(w => w.Close(), resetTo: WriteState.Closed, worksIfClosed: true); - } - - public override string LookupPrefix(string ns) - { - // This one is the oddball - try - { - string prefix; - return - ( // Try child writer first - null != childWriter && - null != (prefix = childWriter.LookupPrefix(ns)) - ) ? prefix : - ( // Try root writer next - null != rootWriter && - null != (prefix = rootWriter.LookupPrefix(ns)) - ) ? prefix : - null; - } - catch { Reset(WriteState.Error); throw; } - } - - private void RequireNotClosed() - { - if (state == WriteState.Closed || state == WriteState.Error) - throw Error.InvalidOperation(); - } - - private void RequireState(WriteState state) - { - if (this.state != state) - throw Error.InvalidOperation(); - } - - private void RequireState(WriteState state1, WriteState state2) - { - if (state != state1 && state != state2) - throw Error.InvalidOperation(); - } - - private void Reset(WriteState state) - { - this.depth = 0; - this.state = state; - } - } -} diff --git a/Castle.Core/Core/Configuration/AbstractConfiguration.cs b/Castle.Core/Core/Configuration/AbstractConfiguration.cs deleted file mode 100644 index d1120a4..0000000 --- a/Castle.Core/Core/Configuration/AbstractConfiguration.cs +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Core.Configuration -{ - using System; - using System.Globalization; - - /// - /// This is an abstract implementation - /// that deals with methods that can be abstracted away - /// from underlying implementations. - /// - /// - /// AbstractConfiguration makes easier to implementers - /// to create a new version of - /// -#if FEATURE_SERIALIZATION - [Serializable] -#endif - public abstract class AbstractConfiguration : IConfiguration - { - private readonly ConfigurationAttributeCollection attributes = new ConfigurationAttributeCollection(); - private readonly ConfigurationCollection children = new ConfigurationCollection(); - - /// - /// Gets node attributes. - /// - /// - /// All attributes of the node. - /// - public virtual ConfigurationAttributeCollection Attributes - { - get { return attributes; } - } - - /// - /// Gets all child nodes. - /// - /// The of child nodes. - public virtual ConfigurationCollection Children - { - get { return children; } - } - - /// - /// Gets the name of the . - /// - /// - /// The Name of the . - /// - public string Name { get; protected set; } - - /// - /// Gets the value of . - /// - /// - /// The Value of the . - /// - public string Value { get; protected set; } - - /// - /// Gets the value of the node and converts it - /// into specified . - /// - /// The - /// - /// The Default value returned if the conversion fails. - /// - /// The Value converted into the specified type. - public virtual object GetValue(Type type, object defaultValue) - { - if (type == null) - { - throw new ArgumentNullException(nameof(type)); - } - - try - { - return Convert.ChangeType(Value, type, CultureInfo.CurrentCulture); - } - catch (InvalidCastException) - { - return defaultValue; - } - } - } -} \ No newline at end of file diff --git a/Castle.Core/Core/Configuration/ConfigurationAttributeCollection.cs b/Castle.Core/Core/Configuration/ConfigurationAttributeCollection.cs deleted file mode 100644 index fbd8e13..0000000 --- a/Castle.Core/Core/Configuration/ConfigurationAttributeCollection.cs +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Core.Configuration -{ -#if FEATURE_SERIALIZATION - using System; - using System.Runtime.Serialization; -#endif - -#if FEATURE_SERIALIZATION - [Serializable] -#endif - public class ConfigurationAttributeCollection - : System.Collections.Specialized.NameValueCollection - { - public ConfigurationAttributeCollection() - { - } - -#if FEATURE_SERIALIZATION - protected ConfigurationAttributeCollection(SerializationInfo info, StreamingContext context) : base(info, context) - { - } -#endif - } -} \ No newline at end of file diff --git a/Castle.Core/Core/Configuration/ConfigurationCollection.cs b/Castle.Core/Core/Configuration/ConfigurationCollection.cs deleted file mode 100644 index 8c9b34f..0000000 --- a/Castle.Core/Core/Configuration/ConfigurationCollection.cs +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Core.Configuration -{ - using System; - using System.Collections.Generic; - - /// - /// A collection of objects. - /// -#if FEATURE_SERIALIZATION - [Serializable] -#endif - public class ConfigurationCollection : List - { - /// - /// Creates a new instance of ConfigurationCollection. - /// - public ConfigurationCollection() - { - } - - /// - /// Creates a new instance of ConfigurationCollection. - /// - public ConfigurationCollection(IEnumerable value) : base(value) - { - } - - public IConfiguration this[string name] - { - get - { - foreach(IConfiguration config in this) - { - if (name.Equals(config.Name)) - { - return config; - } - } - - return null; - } - } - } -} \ No newline at end of file diff --git a/Castle.Core/Core/Configuration/IConfiguration.cs b/Castle.Core/Core/Configuration/IConfiguration.cs deleted file mode 100644 index 935b9e4..0000000 --- a/Castle.Core/Core/Configuration/IConfiguration.cs +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Core.Configuration -{ - using System; - using System.Collections; - - /// - /// is a interface encapsulating a configuration node - /// used to retrieve configuration values. - /// - public interface IConfiguration - { - /// - /// Gets the name of the node. - /// - /// - /// The Name of the node. - /// - string Name { get; } - - /// - /// Gets the value of the node. - /// - /// - /// The Value of the node. - /// - string Value { get; } - - /// - /// Gets an of - /// elements containing all node children. - /// - /// The Collection of child nodes. - ConfigurationCollection Children { get; } - - /// - /// Gets an of the configuration attributes. - /// - ConfigurationAttributeCollection Attributes { get; } - - /// - /// Gets the value of the node and converts it - /// into specified . - /// - /// The - /// - /// The Default value returned if the conversion fails. - /// - /// The Value converted into the specified type. - object GetValue(Type type, object defaultValue); - } -} \ No newline at end of file diff --git a/Castle.Core/Core/Configuration/MutableConfiguration.cs b/Castle.Core/Core/Configuration/MutableConfiguration.cs deleted file mode 100644 index f21ea90..0000000 --- a/Castle.Core/Core/Configuration/MutableConfiguration.cs +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Core.Configuration -{ - using System; - -#if FEATURE_SERIALIZATION - [Serializable] -#endif - public class MutableConfiguration : AbstractConfiguration - { - /// - /// Initializes a new instance of the class. - /// - /// The name. - public MutableConfiguration(string name) : this(name, null) - { - } - - public MutableConfiguration(string name, string value) - { - Name = name; - Value = value; - } - - /// - /// Gets the value of . - /// - /// - /// The Value of the . - /// - public new string Value - { - get { return base.Value; } - set { base.Value = value; } - } - - public static MutableConfiguration Create(string name) - { - return new MutableConfiguration(name); - } - - public MutableConfiguration Attribute(string name, string value) - { - Attributes[name] = value; - return this; - } - - public MutableConfiguration CreateChild(string name) - { - MutableConfiguration child = new MutableConfiguration(name); - Children.Add(child); - return child; - } - - public MutableConfiguration CreateChild(string name, string value) - { - MutableConfiguration child = new MutableConfiguration(name, value); - Children.Add(child); - return child; - } - } -} \ No newline at end of file diff --git a/Castle.Core/Core/Configuration/Xml/XmlConfigurationDeserializer.cs b/Castle.Core/Core/Configuration/Xml/XmlConfigurationDeserializer.cs deleted file mode 100644 index 322f996..0000000 --- a/Castle.Core/Core/Configuration/Xml/XmlConfigurationDeserializer.cs +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Core.Configuration.Xml -{ - using System.Text; - using System.Xml; - - public class XmlConfigurationDeserializer - { - /// - /// Deserializes the specified node into an abstract representation of configuration. - /// - /// The node. - public IConfiguration Deserialize(XmlNode node) - { - return GetDeserializedNode(node); - } - - /// - /// If a config value is an empty string we return null, this is to keep - /// backward compatibility with old code - /// - public static string GetConfigValue(string value) - { - if (value == string.Empty) - { - return null; - } - return value; - } - - public static IConfiguration GetDeserializedNode(XmlNode node) - { - var configChilds = new ConfigurationCollection(); - - var configValue = new StringBuilder(); - if (node.HasChildNodes) - { - foreach (XmlNode child in node.ChildNodes) - { - if (IsTextNode(child)) - { - configValue.Append(child.Value); - } - else if (child.NodeType == XmlNodeType.Element) - { - configChilds.Add(GetDeserializedNode(child)); - } - } - } - - var config = new MutableConfiguration(node.Name, GetConfigValue(configValue.ToString())); - foreach (XmlAttribute attribute in node.Attributes) - { - config.Attributes.Add(attribute.Name, attribute.Value); - } - - config.Children.AddRange(configChilds); - - return config; - } - - public static bool IsTextNode(XmlNode node) - { - return node.NodeType == XmlNodeType.Text || node.NodeType == XmlNodeType.CDATA; - } - } -} diff --git a/Castle.Core/Core/IServiceEnabledComponent.cs b/Castle.Core/Core/IServiceEnabledComponent.cs deleted file mode 100644 index 4e0acec..0000000 --- a/Castle.Core/Core/IServiceEnabledComponent.cs +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Core -{ - using System; - - /// - /// Defines that the implementation wants a - /// in order to - /// access other components. The creator must be aware - /// that the component might (or might not) implement - /// the interface. - /// - /// - /// Used by Castle Project components to, for example, - /// gather logging factories - /// - public interface IServiceEnabledComponent - { - void Service(IServiceProvider provider); - } -} \ No newline at end of file diff --git a/Castle.Core/Core/IServiceProviderEx.cs b/Castle.Core/Core/IServiceProviderEx.cs deleted file mode 100644 index 8e81158..0000000 --- a/Castle.Core/Core/IServiceProviderEx.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Core -{ - using System; - - /// - /// Increments IServiceProvider with a generic service resolution operation. - /// - public interface IServiceProviderEx : IServiceProvider - { - T GetService() where T : class; - } -} diff --git a/Castle.Core/Core/IServiceProviderExAccessor.cs b/Castle.Core/Core/IServiceProviderExAccessor.cs deleted file mode 100644 index 6e04b8c..0000000 --- a/Castle.Core/Core/IServiceProviderExAccessor.cs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Core -{ - /// - /// This interface should be implemented by classes - /// that are available in a bigger context, exposing - /// the container to different areas in the same application. - /// - /// For example, in Web application, the (global) HttpApplication - /// subclasses should implement this interface to expose - /// the configured container - /// - /// - public interface IServiceProviderExAccessor - { - IServiceProviderEx ServiceProvider { get; } - } -} \ No newline at end of file diff --git a/Castle.Core/Core/Internal/AttributesUtil.cs b/Castle.Core/Core/Internal/AttributesUtil.cs deleted file mode 100644 index 0455420..0000000 --- a/Castle.Core/Core/Internal/AttributesUtil.cs +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Core.Internal -{ - using System; - using System.Collections.Generic; - using System.ComponentModel; - using System.Linq; - using System.Reflection; - - /// - /// Helper class for retrieving attributes. - /// - public static class AttributesUtil - { - /// - /// Gets the attribute. - /// - /// The type. - /// The type attribute. - public static T GetAttribute(this Type type) where T : Attribute - { - return GetAttributes(type).FirstOrDefault(); - } - - /// - /// Gets the attributes. Does not consider inherited attributes! - /// - /// The type. - /// The type attributes. - public static IEnumerable GetAttributes(this Type type) where T : Attribute - { - foreach (T a in type.GetCustomAttributes(typeof(T), false)) - { - yield return a; - } - } - - /// - /// Gets the attribute. - /// - /// The member. - /// The member attribute. - public static T GetAttribute(this MemberInfo member) where T : Attribute - { - return GetAttributes(member).FirstOrDefault(); - } - - /// - /// Gets the attributes. Does not consider inherited attributes! - /// - /// The member. - /// The member attributes. - public static IEnumerable GetAttributes(this MemberInfo member) where T : Attribute - { - foreach (T a in member.GetCustomAttributes(typeof(T), false)) - { - yield return a; - } - } - - /// - /// Gets the type attribute. - /// - /// The type. - /// The type attribute. - public static T GetTypeAttribute(this Type type) where T : Attribute - { - var attribute = GetAttribute(type); - - if (attribute == null) - { - foreach (var baseInterface in type.GetInterfaces()) - { - attribute = GetTypeAttribute(baseInterface); - if (attribute != null) - { - break; - } - } - } - - return attribute; - } - - /// - /// Gets the type attributes. - /// - /// The type. - /// The type attributes. - public static T[] GetTypeAttributes(Type type) where T : Attribute - { - var attributes = GetAttributes(type).ToArray(); - - if (attributes.Length == 0) - { - foreach (var baseInterface in type.GetInterfaces()) - { - attributes = GetTypeAttributes(baseInterface); - if (attributes.Length > 0) - { - break; - } - } - } - - return attributes; - } - - public static AttributeUsageAttribute GetAttributeUsage(this Type attributeType) - { - var attributes = attributeType.GetCustomAttributes(true).ToArray(); - return attributes.Length != 0 ? attributes[0] : DefaultAttributeUsage; - } - - private static readonly AttributeUsageAttribute DefaultAttributeUsage = new AttributeUsageAttribute(AttributeTargets.All); - - /// - /// Gets the type converter. - /// - /// The member. - public static Type GetTypeConverter(MemberInfo member) - { - var attrib = GetAttribute(member); - - if (attrib != null) - { - return Type.GetType(attrib.ConverterTypeName); - } - - return null; - } - } -} \ No newline at end of file diff --git a/Castle.Core/Core/Internal/InterfaceAttributeUtil.cs b/Castle.Core/Core/Internal/InterfaceAttributeUtil.cs deleted file mode 100644 index 8943bf2..0000000 --- a/Castle.Core/Core/Internal/InterfaceAttributeUtil.cs +++ /dev/null @@ -1,190 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Core.Internal -{ - using System; - using System.Collections.Generic; - using System.Diagnostics; - using System.Linq; - using System.Reflection; - - internal sealed class InterfaceAttributeUtil - { - private readonly Aged[] types; // in order from most to least derived - private readonly Dictionary> singletons; - private readonly List results; - - private int index; - - private Type CurrentType - { - get { return types[index].Value; } - } - - private int CurrentAge - { - get { return types[index].Age; } - } - - private bool IsMostDerivedType - { - get { return index == 0; } - } - - public static object[] GetAttributes(Type type, bool inherit) - { - if (type.IsInterface == false) - throw new ArgumentOutOfRangeException(nameof(type)); - - var attributes = type.GetCustomAttributes(false).ToArray(); - var baseTypes = type.GetInterfaces(); - - if (baseTypes.Length == 0 || !inherit) - return attributes; - - return new InterfaceAttributeUtil(type, baseTypes) - .GetAttributes(attributes); - } - - private InterfaceAttributeUtil(Type derivedType, Type[] baseTypes) - { - types = CollectTypes(derivedType, baseTypes); - singletons = new Dictionary>(); - results = new List(); - } - - private Aged[] CollectTypes(Type derivedType, Type[] baseTypes) - { - var ages = new Dictionary(); - int age; - - ages[derivedType] = 0; - - foreach (var baseType in baseTypes) - if (ShouldConsiderType(baseType)) - ages[baseType] = 1; - - foreach (var baseType in baseTypes) - if (ages.ContainsKey(baseType)) - foreach (var type in baseType.GetInterfaces()) - if (ages.TryGetValue(type, out age)) - ages[type] = ++age; - - return ages - .Select (a => new Aged(a.Key, a.Value)) - .OrderBy(t => t.Age) - .ToArray(); - } - - private object[] GetAttributes(object[] attributes) - { - for (index = types.Length - 1; index > 0; index--) - ProcessType(CurrentType.GetCustomAttributes(false).ToArray()); - - ProcessType(attributes); - - CollectSingletons(); - return results.ToArray(); - } - - private void ProcessType(object[] attributes) - { - foreach (var attribute in attributes) - { - var attributeType = attribute.GetType(); - var attributeUsage = attributeType.GetAttributeUsage(); - - if (IsMostDerivedType || attributeUsage.Inherited) - { - if (attributeUsage.AllowMultiple) - results.Add(attribute); - else - AddSingleton(attribute, attributeType); - } - } - } - - private void AddSingleton(object attribute, Type attributeType) - { - Aged singleton; - if (singletons.TryGetValue(attributeType, out singleton)) - { - if (singleton.Age == CurrentAge) - { - if (singleton.Value == ConflictMarker) - return; // already in conflict - else - attribute = ConflictMarker; - } - } - - singletons[attributeType] = MakeAged(attribute); - } - - private void CollectSingletons() - { - foreach (var entry in singletons) - { - var attribute = entry.Value.Value; - - if (attribute == ConflictMarker) - HandleAttributeConflict(entry.Key); - else - results.Add(attribute); - } - } - - private void HandleAttributeConflict(Type attributeType) - { - var message = string.Format - ( - "Cannot determine inherited attributes for interface type {0}. " + - "Conflicting attributes of type {1} exist in the inheritance graph.", - CurrentType .FullName, - attributeType.FullName - ); - - throw new InvalidOperationException(message); - } - - private static bool ShouldConsiderType(Type type) - { - var ns = type.Namespace; - return ns != "Castle.Components.DictionaryAdapter" - && ns != "System.ComponentModel"; - } - - private Aged MakeAged(T value) - { - return new Aged(value, CurrentAge); - } - - [DebuggerDisplay("{Value}, Age: {Age}")] - private sealed class Aged - { - public readonly T Value; - public readonly int Age; - - public Aged(T value, int age) - { - Value = value; - Age = age; - } - } - - private static readonly object - ConflictMarker = new object(); - } -} diff --git a/Castle.Core/Core/Internal/InternalsVisible.cs b/Castle.Core/Core/Internal/InternalsVisible.cs deleted file mode 100644 index d735a6d..0000000 --- a/Castle.Core/Core/Internal/InternalsVisible.cs +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Core.Internal -{ - public class InternalsVisible - { - /// - /// Constant to use when making assembly internals visible to Castle.Core - /// [assembly: InternalsVisibleTo(CoreInternalsVisible.ToCastleCore)] - /// - public const string ToCastleCore = - "Castle.Core, PublicKey=002400000480000094000000060200000024000052534131000400000100010077F5E87030DADCCCE6902C6ADAB7A987BD69CB5819991531F560785EACFC89B6FCDDF6BB2A00743A7194E454C0273447FC6EEC36474BA8E5A3823147D214298E4F9A631B1AFEE1A51FFEAE4672D498F14B000E3D321453CDD8AC064DE7E1CF4D222B7E81F54D4FD46725370D702A05B48738CC29D09228F1AA722AE1A9CA02FB"; - - /// - /// Constant to use when making assembly internals visible to proxy types generated by DynamicProxy. Required when proxying internal types. - /// [assembly: InternalsVisibleTo(CoreInternalsVisible.ToDynamicProxyGenAssembly2)] - /// - public const string ToDynamicProxyGenAssembly2 = - "DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7"; - - internal static readonly byte[] DynamicProxyGenAssembly2PublicKey = - { - 0x00, 0x24, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x06, 0x02, 0x00, 0x00, - 0x00, 0x24, 0x00, 0x00, 0x52, 0x53, 0x41, 0x31, 0x00, 0x04, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, - 0xc5, 0x47, 0xca, 0xc3, 0x7a, 0xbd, 0x99, 0xc8, 0xdb, 0x22, 0x5e, 0xf2, 0xf6, 0xc8, 0xa3, 0x60, - 0x2f, 0x3b, 0x36, 0x06, 0xcc, 0x98, 0x91, 0x60, 0x5d, 0x02, 0xba, 0xa5, 0x61, 0x04, 0xf4, 0xcf, - 0xc0, 0x73, 0x4a, 0xa3, 0x9b, 0x93, 0xbf, 0x78, 0x52, 0xf7, 0xd9, 0x26, 0x66, 0x54, 0x75, 0x3c, - 0xc2, 0x97, 0xe7, 0xd2, 0xed, 0xfe, 0x0b, 0xac, 0x1c, 0xdc, 0xf9, 0xf7, 0x17, 0x24, 0x15, 0x50, - 0xe0, 0xa7, 0xb1, 0x91, 0x19, 0x5b, 0x76, 0x67, 0xbb, 0x4f, 0x64, 0xbc, 0xb8, 0xe2, 0x12, 0x13, - 0x80, 0xfd, 0x1d, 0x9d, 0x46, 0xad, 0x2d, 0x92, 0xd2, 0xd1, 0x56, 0x05, 0x09, 0x39, 0x24, 0xcc, - 0xea, 0xf7, 0x4c, 0x48, 0x61, 0xef, 0xf6, 0x2a, 0xbf, 0x69, 0xb9, 0x29, 0x1e, 0xd0, 0xa3, 0x40, - 0xe1, 0x13, 0xbe, 0x11, 0xe6, 0xa7, 0xd3, 0x11, 0x3e, 0x92, 0x48, 0x4c, 0xf7, 0x04, 0x5c, 0xc7 - }; - } -} \ No newline at end of file diff --git a/Castle.Core/Core/Internal/SynchronizedDictionary.cs b/Castle.Core/Core/Internal/SynchronizedDictionary.cs deleted file mode 100644 index 4f354f3..0000000 --- a/Castle.Core/Core/Internal/SynchronizedDictionary.cs +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Core.Internal -{ - using System; - using System.Collections.Generic; - using System.Threading; - - internal sealed class SynchronizedDictionary : IDisposable - { - private Dictionary items; - private ReaderWriterLockSlim itemsLock; - - public SynchronizedDictionary() - { - items = new Dictionary(); - itemsLock = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion); - } - - public void AddOrUpdateWithoutTakingLock(TKey key, TValue value) - { - items[key] = value; - } - - public void Dispose() - { - itemsLock.Dispose(); - } - - public TValue GetOrAdd(TKey key, Func valueFactory) - { - TValue value; - - itemsLock.EnterReadLock(); - try - { - if (items.TryGetValue(key, out value)) - { - return value; - } - } - finally - { - itemsLock.ExitReadLock(); - } - - itemsLock.EnterUpgradeableReadLock(); - try - { - if (items.TryGetValue(key, out value)) - { - return value; - } - else - { - value = valueFactory.Invoke(key); - - itemsLock.EnterWriteLock(); - try - { - items.Add(key, value); - return value; - } - finally - { - itemsLock.ExitWriteLock(); - } - } - } - finally - { - itemsLock.ExitUpgradeableReadLock(); - } - } - - public TValue GetOrAddWithoutTakingLock(TKey key, Func valueFactory) - { - TValue value; - - if (items.TryGetValue(key, out value)) - { - return value; - } - else - { - value = valueFactory.Invoke(key); - items.Add(key, value); - return value; - } - } - - public void ForEach(Action action) - { - itemsLock.EnterReadLock(); - try - { - foreach (var item in items) - { - action.Invoke(item.Key, item.Value); - } - } - finally - { - itemsLock.ExitReadLock(); - } - } - } -} diff --git a/Castle.Core/Core/Internal/TypeExtensions.cs b/Castle.Core/Core/Internal/TypeExtensions.cs deleted file mode 100644 index a89e1d9..0000000 --- a/Castle.Core/Core/Internal/TypeExtensions.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Core.Internal -{ - using System; - using System.Reflection; - - internal static class TypeExtensions - { - /// - /// Find the best available name to describe a type. - /// - /// - /// Usually the best name will be , but - /// sometimes that's null (see http://msdn.microsoft.com/en-us/library/system.type.fullname%28v=vs.110%29.aspx) - /// in which case the method falls back to . - /// - /// the type to name - /// the best name - public static string GetBestName(this Type type) - { - return type.FullName ?? type.Name; - } - } -} diff --git a/Castle.Core/Core/Internal/WeakKey.cs b/Castle.Core/Core/Internal/WeakKey.cs deleted file mode 100644 index 26de6a1..0000000 --- a/Castle.Core/Core/Internal/WeakKey.cs +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Core.Internal -{ - using System; - - internal sealed class WeakKey : WeakReference - { - private readonly int hashCode; - - public WeakKey(object target, int hashCode) - : base(target) - { - this.hashCode = hashCode; - } - - public override object Target - { - get { return base.Target; } - set { throw new NotSupportedException("Dictionary keys are read-only."); } - } - - public override int GetHashCode() - { - return hashCode; - } - - public override bool Equals(object other) - { - return WeakKeyComparer.Default.Equals(this, other); - } - } -} \ No newline at end of file diff --git a/Castle.Core/Core/Internal/WeakKeyComparer.cs b/Castle.Core/Core/Internal/WeakKeyComparer.cs deleted file mode 100644 index 369a103..0000000 --- a/Castle.Core/Core/Internal/WeakKeyComparer.cs +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Core.Internal -{ - using System; - using System.Collections.Generic; - - internal class WeakKeyComparer : IEqualityComparer - where TKey : class - { - public static readonly WeakKeyComparer - Default = new WeakKeyComparer(EqualityComparer.Default); - - private readonly IEqualityComparer comparer; - - public WeakKeyComparer(IEqualityComparer comparer) - { - if (comparer == null) - throw new ArgumentNullException(nameof(comparer)); - - this.comparer = comparer; - } - - public object Wrap(TKey key) - { - return new WeakKey(key, comparer.GetHashCode(key)); - } - - public TKey Unwrap(object obj) - { - var weak = obj as WeakKey; - return (weak != null) - ? (TKey) weak.Target - : (TKey) obj; - } - - public int GetHashCode(object obj) - { - var weak = obj as WeakKey; - return (weak != null) - ? weak .GetHashCode() - : comparer.GetHashCode((TKey) obj); - } - - public new bool Equals(object objA, object objB) - { - var keyA = Unwrap(objA); - var keyB = Unwrap(objB); - - return (keyA != null) - ? (keyB != null) - ? comparer.Equals(keyA, keyB) - : false // live object cannot equal a collected object - : (keyB != null) - ? false // live object cannot equal a collected object - : ReferenceEquals(objA, objB); - } - } -} \ No newline at end of file diff --git a/Castle.Core/Core/Internal/WeakKeyDictionary.cs b/Castle.Core/Core/Internal/WeakKeyDictionary.cs deleted file mode 100644 index a96ad10..0000000 --- a/Castle.Core/Core/Internal/WeakKeyDictionary.cs +++ /dev/null @@ -1,246 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Core.Internal -{ - using System; - using System.Collections; - using System.Collections.Generic; - - internal class WeakKeyDictionary : IDictionary - where TKey : class - { - private readonly Dictionary dictionary; - private readonly WeakKeyComparer comparer; - private KeyCollection keys; - - private int age; // Incremented by operations - private const int AgeThreshold = 128; // Age at which to trim dead objects - - public WeakKeyDictionary() - : this(0, EqualityComparer.Default) { } - - public WeakKeyDictionary(int capacity) - : this(capacity, EqualityComparer.Default) { } - - public WeakKeyDictionary(IEqualityComparer comparer) - : this(0, comparer) { } - - public WeakKeyDictionary(int capacity, IEqualityComparer comparer) - { - this.comparer = new WeakKeyComparer(comparer); - this.dictionary = new Dictionary(capacity, this.comparer); - } - - public int Count - { - get { Age(1); return dictionary.Count; } - } - - bool ICollection>.IsReadOnly - { - get { return false; } - } - - public ICollection Keys - { - get { return keys ?? (keys = new KeyCollection(dictionary.Keys)); } - } - - public ICollection Values - { - get { return dictionary.Values; } - } - - public TValue this[TKey key] - { - get { Age(1); return dictionary[key]; } - set { Age(4); dictionary[comparer.Wrap(key)] = value; } - } - - public bool ContainsKey(TKey key) - { - Age(1); - return dictionary.ContainsKey(key); - } - - bool ICollection>.Contains(KeyValuePair item) - { - Age(1); - TValue candidate; - return dictionary.TryGetValue(item.Key, out candidate) - && EqualityComparer.Default.Equals(candidate, item.Value); - } - - public bool TryGetValue(TKey key, out TValue value) - { - Age(1); - return dictionary.TryGetValue(key, out value); - } - - public IEnumerator> GetEnumerator() - { - var hasDeadObjects = false; - - foreach (var wrapped in dictionary) - { - var item = new KeyValuePair - ( - comparer.Unwrap(wrapped.Key), - wrapped.Value - ); - - if (item.Key == null) - hasDeadObjects = true; - else - yield return item; - } - - if (hasDeadObjects) - TrimDeadObjects(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - public void CopyTo(KeyValuePair[] array, int index) - { - foreach (var item in this) - array[index++] = item; - } - - public void Add(TKey key, TValue value) - { - Age(2); - dictionary.Add(comparer.Wrap(key), value); - } - - void ICollection>.Add(KeyValuePair item) - { - Add(item.Key, item.Value); - } - - public bool Remove(TKey key) - { - Age(4); - return dictionary.Remove(key); - } - - bool ICollection>.Remove(KeyValuePair item) - { - ICollection> collection = this; - return collection.Contains(item) && Remove(item.Key); - } - - public void Clear() - { - age = 0; - dictionary.Clear(); - } - - private void Age(int amount) - { - if ((age += amount) > AgeThreshold) - TrimDeadObjects(); - } - - public void TrimDeadObjects() - { - age = 0; - var removals = null as List; - - foreach (var key in dictionary.Keys) - { - if (comparer.Unwrap(key) == null) - { - if (removals == null) - removals = new List(); - removals.Add(key); - } - } - - if (removals != null) - foreach (var key in removals) - dictionary.Remove(key); - } - - private class KeyCollection : ICollection - { - private readonly ICollection keys; - - public KeyCollection(ICollection keys) - { - this.keys = keys; - } - - public int Count - { - get { return keys.Count; } - } - - bool ICollection.IsReadOnly - { - get { return true; } - } - - public bool Contains(TKey item) - { - return keys.Contains(item); - } - - public IEnumerator GetEnumerator() - { - foreach (var key in keys) - { - var target = (TKey) ((WeakKey) key).Target; - if (target != null) - yield return target; - } - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - public void CopyTo(TKey[] array, int index) - { - foreach (var key in this) - array[index++] = key; - } - - void ICollection.Add(TKey item) - { - throw ReadOnlyCollectionError(); - } - - bool ICollection.Remove(TKey item) - { - throw ReadOnlyCollectionError(); - } - - void ICollection.Clear() - { - throw ReadOnlyCollectionError(); - } - - private static Exception ReadOnlyCollectionError() - { - return new NotSupportedException("The collection is read-only."); - } - } - } -} \ No newline at end of file diff --git a/Castle.Core/Core/Logging/AbstractExtendedLoggerFactory.cs b/Castle.Core/Core/Logging/AbstractExtendedLoggerFactory.cs deleted file mode 100644 index 8e7f423..0000000 --- a/Castle.Core/Core/Logging/AbstractExtendedLoggerFactory.cs +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Core.Logging -{ - using System; - using System.IO; - - public abstract class AbstractExtendedLoggerFactory : IExtendedLoggerFactory - { - /// - /// Creates a new extended logger, getting the logger name from the specified type. - /// - public virtual IExtendedLogger Create(Type type) - { - if (type == null) - { - throw new ArgumentNullException(nameof(type)); - } - - return Create(type.FullName); - } - - /// - /// Creates a new extended logger. - /// - public abstract IExtendedLogger Create(string name); - - /// - /// Creates a new extended logger, getting the logger name from the specified type. - /// - public virtual IExtendedLogger Create(Type type, LoggerLevel level) - { - if (type == null) - { - throw new ArgumentNullException(nameof(type)); - } - - return Create(type.FullName, level); - } - - /// - /// Creates a new extended logger. - /// - public abstract IExtendedLogger Create(string name, LoggerLevel level); - - /// - /// Creates a new logger, getting the logger name from the specified type. - /// - ILogger ILoggerFactory.Create(Type type) - { - return Create(type); - } - - /// - /// Creates a new logger. - /// - ILogger ILoggerFactory.Create(string name) - { - return Create(name); - } - - /// - /// Creates a new logger, getting the logger name from the specified type. - /// - ILogger ILoggerFactory.Create(Type type, LoggerLevel level) - { - return Create(type, level); - } - - /// - /// Creates a new logger. - /// - ILogger ILoggerFactory.Create(string name, LoggerLevel level) - { - return Create(name, level); - } - - /// - /// Gets the configuration file. - /// - /// i.e. log4net.config - protected static FileInfo GetConfigFile(string fileName) - { - FileInfo result; - - if (Path.IsPathRooted(fileName)) - { - result = new FileInfo(fileName); - } - else - { - string baseDirectory = AppDomain.CurrentDomain.BaseDirectory; - result = new FileInfo(Path.Combine(baseDirectory, fileName)); - } - - return result; - } - } -} \ No newline at end of file diff --git a/Castle.Core/Core/Logging/AbstractLoggerFactory.cs b/Castle.Core/Core/Logging/AbstractLoggerFactory.cs deleted file mode 100644 index f5da938..0000000 --- a/Castle.Core/Core/Logging/AbstractLoggerFactory.cs +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Core.Logging -{ - using System; - using System.IO; - -#if FEATURE_SERIALIZATION - [Serializable] -#endif - public abstract class AbstractLoggerFactory : ILoggerFactory - { - public virtual ILogger Create(Type type) - { - if (type == null) - { - throw new ArgumentNullException(nameof(type)); - } - - return Create(type.FullName); - } - - public virtual ILogger Create(Type type, LoggerLevel level) - { - if (type == null) - { - throw new ArgumentNullException(nameof(type)); - } - - return Create(type.FullName, level); - } - - public abstract ILogger Create(string name); - - public abstract ILogger Create(string name, LoggerLevel level); - - /// - /// Gets the configuration file. - /// - /// i.e. log4net.config - protected static FileInfo GetConfigFile(string fileName) - { - FileInfo result; - - if (Path.IsPathRooted(fileName)) - { - result = new FileInfo(fileName); - } - else - { - string baseDirectory = AppDomain.CurrentDomain.BaseDirectory; - result = new FileInfo(Path.Combine(baseDirectory, fileName)); - } - - return result; - } - } -} \ No newline at end of file diff --git a/Castle.Core/Core/Logging/ConsoleFactory.cs b/Castle.Core/Core/Logging/ConsoleFactory.cs deleted file mode 100644 index c456888..0000000 --- a/Castle.Core/Core/Logging/ConsoleFactory.cs +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Core.Logging -{ - using System; - -#if FEATURE_SERIALIZATION - [Serializable] -#endif - public class ConsoleFactory : ILoggerFactory - { - private LoggerLevel? level; - - public ConsoleFactory() - { - } - - public ConsoleFactory(LoggerLevel level) - { - this.level = level; - } - - public ILogger Create(Type type) - { - return Create(type.FullName); - } - - public ILogger Create(string name) - { - if (level.HasValue) - { - return Create(name, level.Value); - } - return new ConsoleLogger(name); - } - - public ILogger Create(Type type, LoggerLevel level) - { - return new ConsoleLogger(type.Name, level); - } - - public ILogger Create(string name, LoggerLevel level) - { - return new ConsoleLogger(name, level); - } - } -} \ No newline at end of file diff --git a/Castle.Core/Core/Logging/ConsoleLogger.cs b/Castle.Core/Core/Logging/ConsoleLogger.cs deleted file mode 100644 index 277b48f..0000000 --- a/Castle.Core/Core/Logging/ConsoleLogger.cs +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Core.Logging -{ - using System; - using System.Globalization; - - /// - /// The Logger sending everything to the standard output streams. - /// This is mainly for the cases when you have a utility that - /// does not have a logger to supply. - /// -#if FEATURE_SERIALIZATION - [Serializable] -#endif - public class ConsoleLogger : LevelFilteredLogger - { - /// - /// Creates a new ConsoleLogger with the Level - /// set to LoggerLevel.Debug and the Name - /// set to string.Empty. - /// - public ConsoleLogger() : this(string.Empty, LoggerLevel.Debug) - { - } - - /// - /// Creates a new ConsoleLogger with the Name - /// set to string.Empty. - /// - /// The logs Level. - public ConsoleLogger(LoggerLevel logLevel) : this(string.Empty, logLevel) - { - } - - /// - /// Creates a new ConsoleLogger with the Level - /// set to LoggerLevel.Debug. - /// - /// The logs Name. - public ConsoleLogger(string name) : this(name, LoggerLevel.Debug) - { - } - - /// - /// Creates a new ConsoleLogger. - /// - /// The logs Name. - /// The logs Level. - public ConsoleLogger(string name, LoggerLevel logLevel) : base(name, logLevel) - { - } - - /// - /// A Common method to log. - /// - /// The level of logging - /// The name of the logger - /// The Message - /// The Exception - protected override void Log(LoggerLevel loggerLevel, string loggerName, string message, Exception exception) - { - Console.Out.WriteLine("[{0}] '{1}' {2}", loggerLevel, loggerName, message); - - if (exception != null) - { - Console.Out.WriteLine("[{0}] '{1}' {2}: {3} {4}", loggerLevel, loggerName, exception.GetType().FullName, - exception.Message, exception.StackTrace); - } - } - - /// - /// Returns a new ConsoleLogger with the name - /// added after this loggers name, with a dot in between. - /// - ///The added hierarchical name. - ///A new ConsoleLogger. - public override ILogger CreateChildLogger(string loggerName) - { - if (loggerName == null) - { - throw new ArgumentNullException(nameof(loggerName), "To create a child logger you must supply a non null name"); - } - - return new ConsoleLogger(string.Format(CultureInfo.CurrentCulture, "{0}.{1}", Name, loggerName), Level); - } - } -} \ No newline at end of file diff --git a/Castle.Core/Core/Logging/DiagnosticsLogger.cs b/Castle.Core/Core/Logging/DiagnosticsLogger.cs deleted file mode 100644 index 259747b..0000000 --- a/Castle.Core/Core/Logging/DiagnosticsLogger.cs +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Core.Logging -{ - using System; - using System.Diagnostics; - using System.Globalization; - - /// - /// The Logger using standard Diagnostics namespace. - /// -#if FEATURE_SERIALIZATION - [Serializable] -#endif - public class DiagnosticsLogger : LevelFilteredLogger, IDisposable - { -#if FEATURE_SERIALIZATION - [NonSerialized] -#endif - private EventLog eventLog; - - /// - /// Creates a logger based on . - /// - /// - public DiagnosticsLogger(string logName) : this(logName, "default") - { - } - - /// - /// Creates a logger based on . - /// - /// - /// - public DiagnosticsLogger(string logName, string source) : base(LoggerLevel.Trace) - { - // Create the source, if it does not already exist. - if (!EventLog.SourceExists(source)) - { - EventLog.CreateEventSource(source, logName); - } - - eventLog = new EventLog(logName); - eventLog.Source = source; - } - - /// - /// Creates a logger based on . - /// - /// - /// - /// - public DiagnosticsLogger(string logName, string machineName, string source) - { - // Create the source, if it does not already exist. - if (!EventLog.SourceExists(source, machineName)) - { - var eventSourceCreationData = new EventSourceCreationData(source, logName); - eventSourceCreationData.MachineName = machineName; - EventLog.CreateEventSource(eventSourceCreationData); - } - - eventLog = new EventLog(logName, machineName, source); - } - - public override ILogger CreateChildLogger(string loggerName) - { - return new DiagnosticsLogger(eventLog.Log, eventLog.MachineName, eventLog.Source); - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - protected virtual void Dispose(bool disposing) - { - if (disposing) - { - if (eventLog != null) - { - eventLog.Close(); - eventLog = null; - } - } - } - - protected override void Log(LoggerLevel loggerLevel, string loggerName, string message, Exception exception) - { - if (eventLog == null) - { - return; // just in case it was disposed - } - - var type = TranslateLevel(loggerLevel); - - string contentToLog; - - if (exception == null) - { - contentToLog = string.Format(CultureInfo.CurrentCulture, "[{0}] '{1}' message: {2}", loggerLevel, loggerName, - message); - } - else - { - contentToLog = string.Format(CultureInfo.CurrentCulture, "[{0}] '{1}' message: {2} exception: {3} {4} {5}", - loggerLevel, loggerName, message, exception.GetType(), exception.Message, - exception.StackTrace); - } - - eventLog.WriteEntry(contentToLog, type); - } - - ~DiagnosticsLogger() - { - Dispose(false); - } - - private static EventLogEntryType TranslateLevel(LoggerLevel level) - { - switch (level) - { - case LoggerLevel.Error: - case LoggerLevel.Fatal: - return EventLogEntryType.Error; - case LoggerLevel.Warn: - return EventLogEntryType.Warning; - default: - return EventLogEntryType.Information; - } - } - } -} diff --git a/Castle.Core/Core/Logging/DiagnosticsLoggerFactory.cs b/Castle.Core/Core/Logging/DiagnosticsLoggerFactory.cs deleted file mode 100644 index 78731f1..0000000 --- a/Castle.Core/Core/Logging/DiagnosticsLoggerFactory.cs +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Core.Logging -{ - using System; - -#if FEATURE_SERIALIZATION - [Serializable] -#endif - public class DiagnosticsLoggerFactory : AbstractLoggerFactory - { - private const string DefaultLogName = "CastleDefaultLogger"; - - public override ILogger Create(string name) - { - return new DiagnosticsLogger(DefaultLogName, name); - } - - public override ILogger Create(string name, LoggerLevel level) - { - var logger = new DiagnosticsLogger(DefaultLogName, name); - logger.Level = level; - return logger; - } - } -} diff --git a/Castle.Core/Core/Logging/IContextProperties.cs b/Castle.Core/Core/Logging/IContextProperties.cs deleted file mode 100644 index 9944c53..0000000 --- a/Castle.Core/Core/Logging/IContextProperties.cs +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Core.Logging -{ - /// - /// Interface for Context Properties implementations - /// - /// - /// - /// This interface defines a basic property get set accessor. - /// - /// - /// Based on the ContextPropertiesBase of log4net, by Nicko Cadell. - /// - /// - public interface IContextProperties - { - /// - /// Gets or sets the value of a property - /// - /// - /// The value for the property with the specified key - /// - /// - /// - /// Gets or sets the value of a property - /// - /// - object this[string key] { get; set; } - } -} \ No newline at end of file diff --git a/Castle.Core/Core/Logging/IContextStack.cs b/Castle.Core/Core/Logging/IContextStack.cs deleted file mode 100644 index 9d214a9..0000000 --- a/Castle.Core/Core/Logging/IContextStack.cs +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Core.Logging -{ - using System; - - public interface IContextStack - { - int Count { get; } - - void Clear(); - - string Pop(); - - IDisposable Push(string message); - } -} \ No newline at end of file diff --git a/Castle.Core/Core/Logging/IContextStacks.cs b/Castle.Core/Core/Logging/IContextStacks.cs deleted file mode 100644 index 6b8f2f4..0000000 --- a/Castle.Core/Core/Logging/IContextStacks.cs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Core.Logging -{ - public interface IContextStacks - { - IContextStack this[string key] { get; } - } -} \ No newline at end of file diff --git a/Castle.Core/Core/Logging/IExtendedLogger.cs b/Castle.Core/Core/Logging/IExtendedLogger.cs deleted file mode 100644 index 65b13dd..0000000 --- a/Castle.Core/Core/Logging/IExtendedLogger.cs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Core.Logging -{ - /// - /// Provides an interface that supports and - /// allows the storage and retrieval of Contexts. These are supported in - /// both log4net and NLog. - /// - public interface IExtendedLogger : ILogger - { - /// - /// Exposes the Global Context of the extended logger. - /// - IContextProperties GlobalProperties { get; } - - /// - /// Exposes the Thread Context of the extended logger. - /// - IContextProperties ThreadProperties { get; } - - /// - /// Exposes the Thread Stack of the extended logger. - /// - IContextStacks ThreadStacks { get; } - } -} \ No newline at end of file diff --git a/Castle.Core/Core/Logging/IExtendedLoggerFactory.cs b/Castle.Core/Core/Logging/IExtendedLoggerFactory.cs deleted file mode 100644 index d0b63b2..0000000 --- a/Castle.Core/Core/Logging/IExtendedLoggerFactory.cs +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Core.Logging -{ - using System; - - /// - /// Provides a factory that can produce either or - /// classes. - /// - public interface IExtendedLoggerFactory : ILoggerFactory - { - /// - /// Creates a new extended logger, getting the logger name from the specified type. - /// - new IExtendedLogger Create(Type type); - - /// - /// Creates a new extended logger. - /// - new IExtendedLogger Create(string name); - - /// - /// Creates a new extended logger, getting the logger name from the specified type. - /// - new IExtendedLogger Create(Type type, LoggerLevel level); - - /// - /// Creates a new extended logger. - /// - new IExtendedLogger Create(string name, LoggerLevel level); - } -} \ No newline at end of file diff --git a/Castle.Core/Core/Logging/ILogger.cs b/Castle.Core/Core/Logging/ILogger.cs deleted file mode 100644 index 036b9b3..0000000 --- a/Castle.Core/Core/Logging/ILogger.cs +++ /dev/null @@ -1,374 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Core.Logging -{ - using System; - - /// - /// Manages logging. - /// - /// - /// This is a facade for the different logging subsystems. - /// It offers a simplified interface that follows IOC patterns - /// and a simplified priority/level/severity abstraction. - /// - public interface ILogger - { - /// - /// Determines if messages of priority "trace" will be logged. - /// - /// True if "trace" messages will be logged. - bool IsTraceEnabled { get; } - - /// - /// Determines if messages of priority "debug" will be logged. - /// - /// True if "debug" messages will be logged. - bool IsDebugEnabled { get; } - - /// - /// Determines if messages of priority "error" will be logged. - /// - /// True if "error" messages will be logged. - bool IsErrorEnabled { get; } - - /// - /// Determines if messages of priority "fatal" will be logged. - /// - /// True if "fatal" messages will be logged. - bool IsFatalEnabled { get; } - - /// - /// Determines if messages of priority "info" will be logged. - /// - /// True if "info" messages will be logged. - bool IsInfoEnabled { get; } - - /// - /// Determines if messages of priority "warn" will be logged. - /// - /// True if "warn" messages will be logged. - bool IsWarnEnabled { get; } - - /// - /// Create a new child logger. - /// The name of the child logger is [current-loggers-name].[passed-in-name] - /// - /// The Subname of this logger. - /// The New ILogger instance. - /// If the name has an empty element name. - ILogger CreateChildLogger(string loggerName); - - /// - /// Logs a trace message. - /// - /// The message to log - void Trace(string message); - - /// - /// Logs a trace message with lazily constructed message. The message will be constructed only if the is true. - /// - void Trace(Func messageFactory); - - /// - /// Logs a trace message. - /// - /// The exception to log - /// The message to log - void Trace(string message, Exception exception); - - /// - /// Logs a trace message. - /// - /// Format string for the message to log - /// Format arguments for the message to log - void TraceFormat(string format, params object[] args); - - /// - /// Logs a trace message. - /// - /// The exception to log - /// Format string for the message to log - /// Format arguments for the message to log - void TraceFormat(Exception exception, string format, params object[] args); - - /// - /// Logs a trace message. - /// - /// The format provider to use - /// Format string for the message to log - /// Format arguments for the message to log - void TraceFormat(IFormatProvider formatProvider, string format, params object[] args); - - /// - /// Logs a trace message. - /// - /// The exception to log - /// The format provider to use - /// Format string for the message to log - /// Format arguments for the message to log - void TraceFormat(Exception exception, IFormatProvider formatProvider, string format, params object[] args); - - /// - /// Logs a debug message. - /// - /// The message to log - void Debug(string message); - - /// - /// Logs a debug message with lazily constructed message. The message will be constructed only if the is true. - /// - void Debug(Func messageFactory); - - /// - /// Logs a debug message. - /// - /// The exception to log - /// The message to log - void Debug(string message, Exception exception); - - /// - /// Logs a debug message. - /// - /// Format string for the message to log - /// Format arguments for the message to log - void DebugFormat(string format, params object[] args); - - /// - /// Logs a debug message. - /// - /// The exception to log - /// Format string for the message to log - /// Format arguments for the message to log - void DebugFormat(Exception exception, string format, params object[] args); - - /// - /// Logs a debug message. - /// - /// The format provider to use - /// Format string for the message to log - /// Format arguments for the message to log - void DebugFormat(IFormatProvider formatProvider, string format, params object[] args); - - /// - /// Logs a debug message. - /// - /// The exception to log - /// The format provider to use - /// Format string for the message to log - /// Format arguments for the message to log - void DebugFormat(Exception exception, IFormatProvider formatProvider, string format, params object[] args); - - /// - /// Logs an error message. - /// - /// The message to log - void Error(string message); - - /// - /// Logs an error message with lazily constructed message. The message will be constructed only if the is true. - /// - void Error(Func messageFactory); - - /// - /// Logs an error message. - /// - /// The exception to log - /// The message to log - void Error(string message, Exception exception); - - /// - /// Logs an error message. - /// - /// Format string for the message to log - /// Format arguments for the message to log - void ErrorFormat(string format, params object[] args); - - /// - /// Logs an error message. - /// - /// The exception to log - /// Format string for the message to log - /// Format arguments for the message to log - void ErrorFormat(Exception exception, string format, params object[] args); - - /// - /// Logs an error message. - /// - /// The format provider to use - /// Format string for the message to log - /// Format arguments for the message to log - void ErrorFormat(IFormatProvider formatProvider, string format, params object[] args); - - /// - /// Logs an error message. - /// - /// The exception to log - /// The format provider to use - /// Format string for the message to log - /// Format arguments for the message to log - void ErrorFormat(Exception exception, IFormatProvider formatProvider, string format, params object[] args); - - /// - /// Logs a fatal message. - /// - /// The message to log - void Fatal(string message); - - /// - /// Logs a fatal message with lazily constructed message. The message will be constructed only if the is true. - /// - void Fatal(Func messageFactory); - - /// - /// Logs a fatal message. - /// - /// The exception to log - /// The message to log - void Fatal(string message, Exception exception); - - /// - /// Logs a fatal message. - /// - /// Format string for the message to log - /// Format arguments for the message to log - void FatalFormat(string format, params object[] args); - - /// - /// Logs a fatal message. - /// - /// The exception to log - /// Format string for the message to log - /// Format arguments for the message to log - void FatalFormat(Exception exception, string format, params object[] args); - - /// - /// Logs a fatal message. - /// - /// The format provider to use - /// Format string for the message to log - /// Format arguments for the message to log - void FatalFormat(IFormatProvider formatProvider, string format, params object[] args); - - /// - /// Logs a fatal message. - /// - /// The exception to log - /// The format provider to use - /// Format string for the message to log - /// Format arguments for the message to log - void FatalFormat(Exception exception, IFormatProvider formatProvider, string format, params object[] args); - - /// - /// Logs an info message. - /// - /// The message to log - void Info(string message); - - /// - /// Logs a info message with lazily constructed message. The message will be constructed only if the is true. - /// - void Info(Func messageFactory); - - /// - /// Logs an info message. - /// - /// The exception to log - /// The message to log - void Info(string message, Exception exception); - - /// - /// Logs an info message. - /// - /// Format string for the message to log - /// Format arguments for the message to log - void InfoFormat(string format, params object[] args); - - /// - /// Logs an info message. - /// - /// The exception to log - /// Format string for the message to log - /// Format arguments for the message to log - void InfoFormat(Exception exception, string format, params object[] args); - - /// - /// Logs an info message. - /// - /// The format provider to use - /// Format string for the message to log - /// Format arguments for the message to log - void InfoFormat(IFormatProvider formatProvider, string format, params object[] args); - - /// - /// Logs an info message. - /// - /// The exception to log - /// The format provider to use - /// Format string for the message to log - /// Format arguments for the message to log - void InfoFormat(Exception exception, IFormatProvider formatProvider, string format, params object[] args); - - /// - /// Logs a warn message. - /// - /// The message to log - void Warn(string message); - - /// - /// Logs a warn message with lazily constructed message. The message will be constructed only if the is true. - /// - void Warn(Func messageFactory); - - /// - /// Logs a warn message. - /// - /// The exception to log - /// The message to log - void Warn(string message, Exception exception); - - /// - /// Logs a warn message. - /// - /// Format string for the message to log - /// Format arguments for the message to log - void WarnFormat(string format, params object[] args); - - /// - /// Logs a warn message. - /// - /// The exception to log - /// Format string for the message to log - /// Format arguments for the message to log - void WarnFormat(Exception exception, string format, params object[] args); - - /// - /// Logs a warn message. - /// - /// The format provider to use - /// Format string for the message to log - /// Format arguments for the message to log - void WarnFormat(IFormatProvider formatProvider, string format, params object[] args); - - /// - /// Logs a warn message. - /// - /// The exception to log - /// The format provider to use - /// Format string for the message to log - /// Format arguments for the message to log - void WarnFormat(Exception exception, IFormatProvider formatProvider, string format, params object[] args); - } -} \ No newline at end of file diff --git a/Castle.Core/Core/Logging/ILoggerFactory.cs b/Castle.Core/Core/Logging/ILoggerFactory.cs deleted file mode 100644 index 7648bd6..0000000 --- a/Castle.Core/Core/Logging/ILoggerFactory.cs +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Core.Logging -{ - using System; - - /// - /// Manages the instantiation of s. - /// - public interface ILoggerFactory - { - /// - /// Creates a new logger, getting the logger name from the specified type. - /// - ILogger Create(Type type); - - /// - /// Creates a new logger. - /// - ILogger Create(string name); - - /// - /// Creates a new logger, getting the logger name from the specified type. - /// - ILogger Create(Type type, LoggerLevel level); - - /// - /// Creates a new logger. - /// - ILogger Create(string name, LoggerLevel level); - } -} \ No newline at end of file diff --git a/Castle.Core/Core/Logging/LevelFilteredLogger.cs b/Castle.Core/Core/Logging/LevelFilteredLogger.cs deleted file mode 100644 index c0437fe..0000000 --- a/Castle.Core/Core/Logging/LevelFilteredLogger.cs +++ /dev/null @@ -1,787 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Core.Logging -{ - using System; - using System.Globalization; - - /// - /// The Level Filtered Logger class. This is a base class which - /// provides a LogLevel attribute and reroutes all functions into - /// one Log method. - /// -#if FEATURE_SERIALIZATION - [Serializable] -#endif - public abstract class LevelFilteredLogger : ILogger - { - private LoggerLevel level = LoggerLevel.Off; - private string name = "unnamed"; - - /// - /// Creates a new LevelFilteredLogger. - /// - protected LevelFilteredLogger() - { - } - - protected LevelFilteredLogger(string name) - { - ChangeName(name); - } - - protected LevelFilteredLogger(LoggerLevel loggerLevel) - { - level = loggerLevel; - } - - protected LevelFilteredLogger(string loggerName, LoggerLevel loggerLevel) : this(loggerLevel) - { - ChangeName(loggerName); - } - - public abstract ILogger CreateChildLogger(string loggerName); - - /// - /// The LoggerLevel that this logger - /// will be using. Defaults to LoggerLevel.Off - /// - public LoggerLevel Level - { - get { return level; } - set { level = value; } - } - - /// - /// The name that this logger will be using. - /// Defaults to string.Empty - /// - public string Name - { - get { return name; } - } - - #region ILogger implementation - - #region Trace - - /// - /// Logs a trace message. - /// - /// The message to log - public void Trace(string message) - { - if (IsTraceEnabled) - { - Log(LoggerLevel.Trace, message, null); - } - } - - /// - /// Logs a trace message. - /// - /// A functor to create the message - public void Trace(Func messageFactory) - { - if (IsTraceEnabled) - { - Log(LoggerLevel.Trace, messageFactory.Invoke(), null); - } - } - - /// - /// Logs a trace message. - /// - /// The exception to log - /// The message to log - public void Trace(string message, Exception exception) - { - if (IsTraceEnabled) - { - Log(LoggerLevel.Trace, message, exception); - } - } - - /// - /// Logs a trace message. - /// - /// Format string for the message to log - /// Format arguments for the message to log - public void TraceFormat(string format, params object[] args) - { - if (IsTraceEnabled) - { - Log(LoggerLevel.Trace, string.Format(CultureInfo.CurrentCulture, format, args), null); - } - } - - /// - /// Logs a trace message. - /// - /// The exception to log - /// Format string for the message to log - /// Format arguments for the message to log - public void TraceFormat(Exception exception, string format, params object[] args) - { - if (IsTraceEnabled) - { - Log(LoggerLevel.Trace, string.Format(CultureInfo.CurrentCulture, format, args), exception); - } - } - - /// - /// Logs a trace message. - /// - /// The format provider to use - /// Format string for the message to log - /// Format arguments for the message to log - public void TraceFormat(IFormatProvider formatProvider, string format, params object[] args) - { - if (IsTraceEnabled) - { - Log(LoggerLevel.Trace, string.Format(formatProvider, format, args), null); - } - } - - /// - /// Logs a trace message. - /// - /// The exception to log - /// The format provider to use - /// Format string for the message to log - /// Format arguments for the message to log - public void TraceFormat(Exception exception, IFormatProvider formatProvider, string format, params object[] args) - { - if (IsTraceEnabled) - { - Log(LoggerLevel.Trace, string.Format(formatProvider, format, args), exception); - } - } - - #endregion - - #region Debug - - /// - /// Logs a debug message. - /// - /// The message to log - public void Debug(string message) - { - if (!IsDebugEnabled) - { - return; - } - - Log(LoggerLevel.Debug, message, null); - } - - public void Debug(Func messageFactory) - { - if (!IsDebugEnabled) - { - return; - } - - Log(LoggerLevel.Debug, messageFactory.Invoke(), null); - } - - /// - /// Logs a debug message. - /// - /// The exception to log - /// The message to log - public void Debug(string message, Exception exception) - { - if (!IsDebugEnabled) - { - return; - } - - Log(LoggerLevel.Debug, message, exception); - } - - /// - /// Logs a debug message. - /// - /// Format string for the message to log - /// Format arguments for the message to log - public void DebugFormat(string format, params object[] args) - { - if (!IsDebugEnabled) - { - return; - } - - Log(LoggerLevel.Debug, string.Format(CultureInfo.CurrentCulture, format, args), null); - } - - /// - /// Logs a debug message. - /// - /// The exception to log - /// Format string for the message to log - /// Format arguments for the message to log - public void DebugFormat(Exception exception, string format, params object[] args) - { - if (!IsDebugEnabled) - { - return; - } - - Log(LoggerLevel.Debug, string.Format(CultureInfo.CurrentCulture, format, args), exception); - } - - /// - /// Logs a debug message. - /// - /// The format provider to use - /// Format string for the message to log - /// Format arguments for the message to log - public void DebugFormat(IFormatProvider formatProvider, string format, params object[] args) - { - if (!IsDebugEnabled) - { - return; - } - - Log(LoggerLevel.Debug, string.Format(formatProvider, format, args), null); - } - - /// - /// Logs a debug message. - /// - /// The exception to log - /// The format provider to use - /// Format string for the message to log - /// Format arguments for the message to log - public void DebugFormat(Exception exception, IFormatProvider formatProvider, string format, params object[] args) - { - if (!IsDebugEnabled) - { - return; - } - - Log(LoggerLevel.Debug, string.Format(formatProvider, format, args), exception); - } - - #endregion - - #region Info - - /// - /// Logs an info message. - /// - /// The message to log - public void Info(string message) - { - if (!IsInfoEnabled) - { - return; - } - - Log(LoggerLevel.Info, message, null); - } - - public void Info(Func messageFactory) - { - if (!IsInfoEnabled) - { - return; - } - - Log(LoggerLevel.Info, messageFactory.Invoke(), null); - } - - /// - /// Logs an info message. - /// - /// The exception to log - /// The message to log - public void Info(string message, Exception exception) - { - if (!IsInfoEnabled) - { - return; - } - - Log(LoggerLevel.Info, message, exception); - } - - /// - /// Logs an info message. - /// - /// Format string for the message to log - /// Format arguments for the message to log - public void InfoFormat(string format, params object[] args) - { - if (!IsInfoEnabled) - { - return; - } - - Log(LoggerLevel.Info, string.Format(CultureInfo.CurrentCulture, format, args), null); - } - - /// - /// Logs an info message. - /// - /// The exception to log - /// Format string for the message to log - /// Format arguments for the message to log - public void InfoFormat(Exception exception, string format, params object[] args) - { - if (!IsInfoEnabled) - { - return; - } - - Log(LoggerLevel.Info, string.Format(CultureInfo.CurrentCulture, format, args), exception); - } - - /// - /// Logs an info message. - /// - /// The format provider to use - /// Format string for the message to log - /// Format arguments for the message to log - public void InfoFormat(IFormatProvider formatProvider, string format, params object[] args) - { - if (!IsInfoEnabled) - { - return; - } - - Log(LoggerLevel.Info, string.Format(formatProvider, format, args), null); - } - - /// - /// Logs an info message. - /// - /// The exception to log - /// The format provider to use - /// Format string for the message to log - /// Format arguments for the message to log - public void InfoFormat(Exception exception, IFormatProvider formatProvider, string format, params object[] args) - { - if (!IsInfoEnabled) - { - return; - } - - Log(LoggerLevel.Info, string.Format(formatProvider, format, args), exception); - } - - #endregion - - #region Warn - - /// - /// Logs a warn message. - /// - /// The message to log - public void Warn(string message) - { - if (!IsWarnEnabled) - { - return; - } - - Log(LoggerLevel.Warn, message, null); - } - - public void Warn(Func messageFactory) - { - if (!IsWarnEnabled) - { - return; - } - - Log(LoggerLevel.Warn, messageFactory.Invoke(), null); - } - - /// - /// Logs a warn message. - /// - /// The exception to log - /// The message to log - public void Warn(string message, Exception exception) - { - if (!IsWarnEnabled) - { - return; - } - - Log(LoggerLevel.Warn, message, exception); - } - - /// - /// Logs a warn message. - /// - /// Format string for the message to log - /// Format arguments for the message to log - public void WarnFormat(string format, params object[] args) - { - if (!IsWarnEnabled) - { - return; - } - - Log(LoggerLevel.Warn, string.Format(CultureInfo.CurrentCulture, format, args), null); - } - - /// - /// Logs a warn message. - /// - /// The exception to log - /// Format string for the message to log - /// Format arguments for the message to log - public void WarnFormat(Exception exception, string format, params object[] args) - { - if (!IsWarnEnabled) - { - return; - } - - Log(LoggerLevel.Warn, string.Format(CultureInfo.CurrentCulture, format, args), exception); - } - - /// - /// Logs a warn message. - /// - /// The format provider to use - /// Format string for the message to log - /// Format arguments for the message to log - public void WarnFormat(IFormatProvider formatProvider, string format, params object[] args) - { - if (!IsWarnEnabled) - { - return; - } - - Log(LoggerLevel.Warn, string.Format(formatProvider, format, args), null); - } - - /// - /// Logs a warn message. - /// - /// The exception to log - /// The format provider to use - /// Format string for the message to log - /// Format arguments for the message to log - public void WarnFormat(Exception exception, IFormatProvider formatProvider, string format, params object[] args) - { - if (!IsWarnEnabled) - { - return; - } - - Log(LoggerLevel.Warn, string.Format(formatProvider, format, args), exception); - } - - #endregion - - #region Error - - /// - /// Logs an error message. - /// - /// The message to log - public void Error(string message) - { - if (!IsErrorEnabled) - { - return; - } - - Log(LoggerLevel.Error, message, null); - } - - public void Error(Func messageFactory) - { - if (!IsErrorEnabled) - { - return; - } - - Log(LoggerLevel.Error, messageFactory.Invoke(), null); - } - - /// - /// Logs an error message. - /// - /// The exception to log - /// The message to log - public void Error(string message, Exception exception) - { - if (!IsErrorEnabled) - { - return; - } - - Log(LoggerLevel.Error, message, exception); - } - - /// - /// Logs an error message. - /// - /// Format string for the message to log - /// Format arguments for the message to log - public void ErrorFormat(string format, params object[] args) - { - if (!IsErrorEnabled) - { - return; - } - - Log(LoggerLevel.Error, string.Format(CultureInfo.CurrentCulture, format, args), null); - } - - /// - /// Logs an error message. - /// - /// The exception to log - /// Format string for the message to log - /// Format arguments for the message to log - public void ErrorFormat(Exception exception, string format, params object[] args) - { - if (!IsErrorEnabled) - { - return; - } - - Log(LoggerLevel.Error, string.Format(CultureInfo.CurrentCulture, format, args), exception); - } - - /// - /// Logs an error message. - /// - /// The format provider to use - /// Format string for the message to log - /// Format arguments for the message to log - public void ErrorFormat(IFormatProvider formatProvider, string format, params object[] args) - { - if (!IsErrorEnabled) - { - return; - } - - Log(LoggerLevel.Error, string.Format(formatProvider, format, args), null); - } - - /// - /// Logs an error message. - /// - /// The exception to log - /// The format provider to use - /// Format string for the message to log - /// Format arguments for the message to log - public void ErrorFormat(Exception exception, IFormatProvider formatProvider, string format, params object[] args) - { - if (!IsErrorEnabled) - { - return; - } - - Log(LoggerLevel.Error, string.Format(formatProvider, format, args), exception); - } - - #endregion - - #region Fatal - - /// - /// Logs a fatal message. - /// - /// The message to log - public void Fatal(string message) - { - if (!IsFatalEnabled) - { - return; - } - - Log(LoggerLevel.Fatal, message, null); - } - - public void Fatal(Func messageFactory) - { - if (!IsFatalEnabled) - { - return; - } - - Log(LoggerLevel.Fatal, messageFactory.Invoke(), null); - } - - /// - /// Logs a fatal message. - /// - /// The exception to log - /// The message to log - public void Fatal(string message, Exception exception) - { - if (!IsFatalEnabled) - { - return; - } - - Log(LoggerLevel.Fatal, message, exception); - } - - /// - /// Logs a fatal message. - /// - /// Format string for the message to log - /// Format arguments for the message to log - public void FatalFormat(string format, params object[] args) - { - if (!IsFatalEnabled) - { - return; - } - - Log(LoggerLevel.Fatal, string.Format(CultureInfo.CurrentCulture, format, args), null); - } - - /// - /// Logs a fatal message. - /// - /// The exception to log - /// Format string for the message to log - /// Format arguments for the message to log - public void FatalFormat(Exception exception, string format, params object[] args) - { - if (!IsFatalEnabled) - { - return; - } - - Log(LoggerLevel.Fatal, string.Format(CultureInfo.CurrentCulture, format, args), exception); - } - - /// - /// Logs a fatal message. - /// - /// The format provider to use - /// Format string for the message to log - /// Format arguments for the message to log - public void FatalFormat(IFormatProvider formatProvider, string format, params object[] args) - { - if (!IsFatalEnabled) - { - return; - } - - Log(LoggerLevel.Fatal, string.Format(formatProvider, format, args), null); - } - - /// - /// Logs a fatal message. - /// - /// The exception to log - /// The format provider to use - /// Format string for the message to log - /// Format arguments for the message to log - public void FatalFormat(Exception exception, IFormatProvider formatProvider, string format, params object[] args) - { - if (!IsFatalEnabled) - { - return; - } - - Log(LoggerLevel.Fatal, string.Format(formatProvider, format, args), exception); - } - - #endregion - - /// - /// Determines if messages of priority "trace" will be logged. - /// - /// true if log level flags include the bit - public bool IsTraceEnabled - { - get { return (Level >= LoggerLevel.Trace); } - } - - /// - /// Determines if messages of priority "debug" will be logged. - /// - /// true if log level flags include the bit - public bool IsDebugEnabled - { - get { return (Level >= LoggerLevel.Debug); } - } - - /// - /// Determines if messages of priority "info" will be logged. - /// - /// true if log level flags include the bit - public bool IsInfoEnabled - { - get { return (Level >= LoggerLevel.Info); } - } - - /// - /// Determines if messages of priority "warn" will be logged. - /// - /// true if log level flags include the bit - public bool IsWarnEnabled - { - get { return (Level >= LoggerLevel.Warn); } - } - - /// - /// Determines if messages of priority "error" will be logged. - /// - /// true if log level flags include the bit - public bool IsErrorEnabled - { - get { return (Level >= LoggerLevel.Error); } - } - - /// - /// Determines if messages of priority "fatal" will be logged. - /// - /// true if log level flags include the bit - public bool IsFatalEnabled - { - get { return (Level >= LoggerLevel.Fatal); } - } - - #endregion - - /// - /// Implementors output the log content by implementing this method only. - /// Note that exception can be null - /// - protected abstract void Log(LoggerLevel loggerLevel, string loggerName, string message, Exception exception); - - protected void ChangeName(string newName) - { - if (newName == null) - { - throw new ArgumentNullException(nameof(newName)); - } - - name = newName; - } - - private void Log(LoggerLevel loggerLevel, string message, Exception exception) - { - Log(loggerLevel, Name, message, exception); - } - } -} \ No newline at end of file diff --git a/Castle.Core/Core/Logging/LoggerException.cs b/Castle.Core/Core/Logging/LoggerException.cs deleted file mode 100644 index cf99979..0000000 --- a/Castle.Core/Core/Logging/LoggerException.cs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Core.Logging -{ - using System; - using System.Runtime.Serialization; - - [Serializable] - public class LoggerException : Exception - { - public LoggerException() - { - } - - public LoggerException(string message) : base(message) - { - } - - public LoggerException(string message, Exception innerException) : base(message, innerException) - { - } - - protected LoggerException(SerializationInfo info, StreamingContext context) : base(info, context) - { - } - } -} \ No newline at end of file diff --git a/Castle.Core/Core/Logging/LoggerLevel.cs b/Castle.Core/Core/Logging/LoggerLevel.cs deleted file mode 100644 index 3ae8bb0..0000000 --- a/Castle.Core/Core/Logging/LoggerLevel.cs +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Core.Logging -{ - /// - /// Supporting Logger levels. - /// - public enum LoggerLevel - { - /// - /// Logging will be off - /// - Off = 0, - /// - /// Fatal logging level - /// - Fatal = 1, - /// - /// Error logging level - /// - Error = 2, - /// - /// Warn logging level - /// - Warn = 3, - /// - /// Info logging level - /// - Info = 4, - /// - /// Debug logging level - /// - Debug = 5, - /// - /// Trace logging level - /// - Trace = 6 - } -} \ No newline at end of file diff --git a/Castle.Core/Core/Logging/NullLogFactory.cs b/Castle.Core/Core/Logging/NullLogFactory.cs deleted file mode 100644 index 37479e2..0000000 --- a/Castle.Core/Core/Logging/NullLogFactory.cs +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Core.Logging -{ - using System; - - /// - /// NullLogFactory used when logging is turned off. - /// -#if FEATURE_SERIALIZATION - [Serializable] -#endif - public class NullLogFactory : AbstractLoggerFactory - { - /// - /// Creates an instance of ILogger with the specified name. - /// - /// Name. - public override ILogger Create(string name) - { - return NullLogger.Instance; - } - - /// - /// Creates an instance of ILogger with the specified name and LoggerLevel. - /// - /// Name. - /// Level. - public override ILogger Create(string name, LoggerLevel level) - { - return NullLogger.Instance; - } - } -} \ No newline at end of file diff --git a/Castle.Core/Core/Logging/NullLogger.cs b/Castle.Core/Core/Logging/NullLogger.cs deleted file mode 100644 index b871dc3..0000000 --- a/Castle.Core/Core/Logging/NullLogger.cs +++ /dev/null @@ -1,532 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Core.Logging -{ - using System; - - /// - /// The Null Logger class. This is useful for implementations where you need - /// to provide a logger to a utility class, but do not want any output from it. - /// It also helps when you have a utility that does not have a logger to supply. - /// - public class NullLogger : IExtendedLogger - { - public static readonly NullLogger Instance = new NullLogger(); - - /// - /// Returns empty context properties. - /// - public IContextProperties GlobalProperties - { - get { return NullContextProperties.Instance; } - } - - /// - /// Returns empty context properties. - /// - public IContextProperties ThreadProperties - { - get { return NullContextProperties.Instance; } - } - - /// - /// Returns empty context stacks. - /// - public IContextStacks ThreadStacks - { - get { return NullContextStacks.Instance; } - } - - /// - /// No-op. - /// - /// false - public bool IsTraceEnabled - { - get { return false; } - } - - /// - /// No-op. - /// - /// false - public bool IsDebugEnabled - { - get { return false; } - } - - /// - /// No-op. - /// - /// false - public bool IsErrorEnabled - { - get { return false; } - } - - /// - /// No-op. - /// - /// false - public bool IsFatalEnabled - { - get { return false; } - } - - /// - /// No-op. - /// - /// false - public bool IsInfoEnabled - { - get { return false; } - } - - /// - /// No-op. - /// - /// false - public bool IsWarnEnabled - { - get { return false; } - } - - /// - /// Returns this NullLogger. - /// - /// Ignored - /// This ILogger instance. - public ILogger CreateChildLogger(string loggerName) - { - return this; - } - - /// - /// No-op. - /// - /// Ignored - public void Trace(string message) - { - } - - public void Trace(Func messageFactory) - { - } - - /// - /// No-op. - /// - /// Ignored - /// Ignored - public void Trace(string message, Exception exception) - { - } - - /// - /// No-op. - /// - /// Ignored - /// Ignored - public void TraceFormat(string format, params object[] args) - { - } - - /// - /// No-op. - /// - /// Ignored - /// Ignored - /// Ignored - public void TraceFormat(Exception exception, string format, params object[] args) - { - } - - /// - /// No-op. - /// - /// Ignored - /// Ignored - /// Ignored - public void TraceFormat(IFormatProvider formatProvider, string format, params object[] args) - { - } - - /// - /// No-op. - /// - /// Ignored - /// Ignored - /// Ignored - /// Ignored - public void TraceFormat(Exception exception, IFormatProvider formatProvider, string format, params object[] args) - { - } - - /// - /// No-op. - /// - /// Ignored - public void Debug(string message) - { - } - - public void Debug(Func messageFactory) - { - } - - /// - /// No-op. - /// - /// Ignored - /// Ignored - public void Debug(string message, Exception exception) - { - } - - /// - /// No-op. - /// - /// Ignored - /// Ignored - public void DebugFormat(string format, params object[] args) - { - } - - /// - /// No-op. - /// - /// Ignored - /// Ignored - /// Ignored - public void DebugFormat(Exception exception, string format, params object[] args) - { - } - - /// - /// No-op. - /// - /// Ignored - /// Ignored - /// Ignored - public void DebugFormat(IFormatProvider formatProvider, string format, params object[] args) - { - } - - /// - /// No-op. - /// - /// Ignored - /// Ignored - /// Ignored - /// Ignored - public void DebugFormat(Exception exception, IFormatProvider formatProvider, string format, params object[] args) - { - } - - /// - /// No-op. - /// - /// Ignored - public void Error(string message) - { - } - - public void Error(Func messageFactory) - { - } - - /// - /// No-op. - /// - /// Ignored - /// Ignored - public void Error(string message, Exception exception) - { - } - - /// - /// No-op. - /// - /// Ignored - /// Ignored - public void ErrorFormat(string format, params object[] args) - { - } - - /// - /// No-op. - /// - /// Ignored - /// Ignored - /// Ignored - public void ErrorFormat(Exception exception, string format, params object[] args) - { - } - - /// - /// No-op. - /// - /// Ignored - /// Ignored - /// Ignored - public void ErrorFormat(IFormatProvider formatProvider, string format, params object[] args) - { - } - - /// - /// No-op. - /// - /// Ignored - /// Ignored - /// Ignored - /// Ignored - public void ErrorFormat(Exception exception, IFormatProvider formatProvider, string format, params object[] args) - { - } - - /// - /// No-op. - /// - /// Ignored - public void Fatal(string message) - { - } - - public void Fatal(Func messageFactory) - { - } - - /// - /// No-op. - /// - /// Ignored - /// Ignored - public void Fatal(string message, Exception exception) - { - } - - /// - /// No-op. - /// - /// Ignored - /// Ignored - public void FatalFormat(string format, params object[] args) - { - } - - /// - /// No-op. - /// - /// Ignored - /// Ignored - /// Ignored - public void FatalFormat(Exception exception, string format, params object[] args) - { - } - - /// - /// No-op. - /// - /// Ignored - /// Ignored - /// Ignored - public void FatalFormat(IFormatProvider formatProvider, string format, params object[] args) - { - } - - /// - /// No-op. - /// - /// Ignored - /// Ignored - /// Ignored - /// Ignored - public void FatalFormat(Exception exception, IFormatProvider formatProvider, string format, params object[] args) - { - } - - /// - /// No-op. - /// - /// Ignored - public void Info(string message) - { - } - - public void Info(Func messageFactory) - { - } - - /// - /// No-op. - /// - /// Ignored - /// Ignored - public void Info(string message, Exception exception) - { - } - - /// - /// No-op. - /// - /// Ignored - /// Ignored - public void InfoFormat(string format, params object[] args) - { - } - - /// - /// No-op. - /// - /// Ignored - /// Ignored - /// Ignored - public void InfoFormat(Exception exception, string format, params object[] args) - { - } - - /// - /// No-op. - /// - /// Ignored - /// Ignored - /// Ignored - public void InfoFormat(IFormatProvider formatProvider, string format, params object[] args) - { - } - - /// - /// No-op. - /// - /// Ignored - /// Ignored - /// Ignored - /// Ignored - public void InfoFormat(Exception exception, IFormatProvider formatProvider, string format, params object[] args) - { - } - - /// - /// No-op. - /// - /// Ignored - public void Warn(string message) - { - } - - public void Warn(Func messageFactory) - { - } - - /// - /// No-op. - /// - /// Ignored - /// Ignored - public void Warn(string message, Exception exception) - { - } - - /// - /// No-op. - /// - /// Ignored - /// Ignored - public void WarnFormat(string format, params object[] args) - { - } - - /// - /// No-op. - /// - /// Ignored - /// Ignored - /// Ignored - public void WarnFormat(Exception exception, string format, params object[] args) - { - } - - /// - /// No-op. - /// - /// Ignored - /// Ignored - /// Ignored - public void WarnFormat(IFormatProvider formatProvider, string format, params object[] args) - { - } - - /// - /// No-op. - /// - /// Ignored - /// Ignored - /// Ignored - /// Ignored - public void WarnFormat(Exception exception, IFormatProvider formatProvider, string format, params object[] args) - { - } - - private class NullContextProperties : IContextProperties - { - public static readonly NullContextProperties Instance = new NullContextProperties(); - - public object this[string key] - { - get { return null; } - set { } - } - } - - private class NullContextStack : IContextStack, IDisposable - { - public static readonly NullContextStack Instance = new NullContextStack(); - - public int Count - { - get { return 0; } - } - - public void Clear() - { - } - - public string Pop() - { - return null; - } - - public IDisposable Push(string message) - { - return this; - } - - public void Dispose() - { - GC.SuppressFinalize(this); - } - } - - private class NullContextStacks : IContextStacks - { - public static readonly NullContextStacks Instance = new NullContextStacks(); - - public IContextStack this[string key] - { - get { return NullContextStack.Instance; } - } - } - } -} \ No newline at end of file diff --git a/Castle.Core/Core/Logging/StreamLogger.cs b/Castle.Core/Core/Logging/StreamLogger.cs deleted file mode 100644 index 91e1b8c..0000000 --- a/Castle.Core/Core/Logging/StreamLogger.cs +++ /dev/null @@ -1,160 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Core.Logging -{ - using System; - using System.IO; - using System.Text; - - /// - /// The Stream Logger class. This class can stream log information - /// to any stream, it is suitable for storing a log file to disk, - /// or to a MemoryStream for testing your components. - /// - /// - /// This logger is not thread safe. - /// -#if FEATURE_SERIALIZATION - [Serializable] -#endif - public class StreamLogger : LevelFilteredLogger, IDisposable - { - private StreamWriter writer; - - /// - /// Creates a new StreamLogger with default encoding - /// and buffer size. Initial Level is set to Debug. - /// - /// - /// The name of the log. - /// - /// - /// The stream that will be used for logging, - /// seeking while the logger is alive - /// - public StreamLogger(string name, Stream stream) : this(name, new StreamWriter(stream)) - { - } - - /// - /// Creates a new StreamLogger with default buffer size. - /// Initial Level is set to Debug. - /// - /// - /// The name of the log. - /// - /// - /// The stream that will be used for logging, - /// seeking while the logger is alive - /// - /// - /// The encoding that will be used for this stream. - /// - /// - public StreamLogger(string name, Stream stream, Encoding encoding) : this(name, new StreamWriter(stream, encoding)) - { - } - - /// - /// Creates a new StreamLogger. - /// Initial Level is set to Debug. - /// - /// - /// The name of the log. - /// - /// - /// The stream that will be used for logging, - /// seeking while the logger is alive - /// - /// - /// The encoding that will be used for this stream. - /// - /// - /// - /// The buffer size that will be used for this stream. - /// - /// - public StreamLogger(string name, Stream stream, Encoding encoding, int bufferSize) - : this(name, new StreamWriter(stream, encoding, bufferSize)) - { - } - - ~StreamLogger() - { - Dispose(false); - } - - #region IDisposable Members - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - #endregion - - protected virtual void Dispose(bool disposing) - { - if (disposing) - { - if (writer != null) - { - writer.Dispose(); - writer = null; - } - } - } - - /// - /// Creates a new StreamLogger with - /// Debug as default Level. - /// - /// The name of the log. - /// The StreamWriter the log will write to. - protected StreamLogger(string name, StreamWriter writer) : base(name, LoggerLevel.Trace) - { - this.writer = writer; - writer.AutoFlush = true; - } - - protected override void Log(LoggerLevel loggerLevel, string loggerName, string message, Exception exception) - { - if (writer == null) - { - return; // just in case it's been disposed - } - - writer.WriteLine("[{0}] '{1}' {2}", loggerLevel, loggerName, message); - - if (exception != null) - { - writer.WriteLine("[{0}] '{1}' {2}: {3} {4}", - loggerLevel, - loggerName, - exception.GetType().FullName, - exception.Message, - exception.StackTrace); - } - } - - public override ILogger CreateChildLogger(string loggerName) - { - // TODO: We could create a ChildStreamLogger that didn't take ownership of the stream - - throw new NotSupportedException("A streamlogger does not support child loggers"); - } - } -} \ No newline at end of file diff --git a/Castle.Core/Core/Logging/StreamLoggerFactory.cs b/Castle.Core/Core/Logging/StreamLoggerFactory.cs deleted file mode 100644 index 78077f1..0000000 --- a/Castle.Core/Core/Logging/StreamLoggerFactory.cs +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Core.Logging -{ - using System; - using System.IO; - using System.Text; - - /// - /// Creates outputting - /// to files. The name of the file is derived from the log name - /// plus the 'log' extension. - /// -#if FEATURE_SERIALIZATION - [Serializable] -#endif - public class StreamLoggerFactory : AbstractLoggerFactory - { - public override ILogger Create(string name) - { - return new StreamLogger(name, new FileStream(name + ".log", FileMode.Append, FileAccess.Write)); - } - - public override ILogger Create(string name, LoggerLevel level) - { - var logger = - new StreamLogger(name, new FileStream(name + ".log", FileMode.Append, FileAccess.Write)); - logger.Level = level; - return logger; - } - } -} diff --git a/Castle.Core/Core/Logging/TraceLogger.cs b/Castle.Core/Core/Logging/TraceLogger.cs deleted file mode 100644 index 1584577..0000000 --- a/Castle.Core/Core/Logging/TraceLogger.cs +++ /dev/null @@ -1,227 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Core.Logging -{ - using System; - using System.Diagnostics; - using System.Collections.Generic; - - /// - /// The TraceLogger sends all logging to the System.Diagnostics.TraceSource - /// built into the .net framework. - /// - /// - /// Logging can be configured in the system.diagnostics configuration - /// section. - /// - /// If logger doesn't find a source name with a full match it will - /// use source names which match the namespace partially. For example you can - /// configure from all castle components by adding a source name with the - /// name "Castle". - /// - /// If no portion of the namespace matches the source named "Default" will - /// be used. - /// - public class TraceLogger : LevelFilteredLogger - { - private static readonly Dictionary cache = new Dictionary(); - - private TraceSource traceSource; - - /// - /// Build a new trace logger based on the named TraceSource - /// - /// The name used to locate the best TraceSource. In most cases comes from the using type's fullname. - public TraceLogger(string name) - : base(name) - { - Initialize(); - Level = MapLoggerLevel(traceSource.Switch.Level); - } - - /// - /// Build a new trace logger based on the named TraceSource - /// - /// The name used to locate the best TraceSource. In most cases comes from the using type's fullname. - /// The default logging level at which this source should write messages. In almost all cases this - /// default value will be overridden in the config file. - public TraceLogger(string name, LoggerLevel level) - : base(name, level) - { - Initialize(); - Level = MapLoggerLevel(traceSource.Switch.Level); - } - - /// - /// Create a new child logger. - /// The name of the child logger is [current-loggers-name].[passed-in-name] - /// - /// The Subname of this logger. - /// The New ILogger instance. - public override ILogger CreateChildLogger(string loggerName) - { - return InternalCreateChildLogger(loggerName); - } - - private ILogger InternalCreateChildLogger(string loggerName) - { - return new TraceLogger(string.Concat(Name, ".", loggerName), Level); - } - - protected override void Log(LoggerLevel loggerLevel, string loggerName, string message, Exception exception) - { - if (exception == null) - { - traceSource.TraceEvent(MapTraceEventType(loggerLevel), 0, message); - } - else - { - traceSource.TraceData(MapTraceEventType(loggerLevel), 0, message, exception); - } - } - - private void Initialize() - { - lock (cache) - { - // because TraceSource is meant to be used as a static member, and because - // building up the configuration inheritance is non-trivial, the instances - // themselves are cached for so multiple TraceLogger instances will reuse - // the named TraceSources which have been created - - if (cache.TryGetValue(Name, out traceSource)) - { - return; - } - - var defaultLevel = MapSourceLevels(Level); - traceSource = new TraceSource(Name, defaultLevel); - - // no further action necessary when the named source is configured - if (IsSourceConfigured(traceSource)) - { - cache.Add(Name, traceSource); - return; - } - - // otherwise hunt for a shorter source that been configured - var foundSource = new TraceSource("Default", defaultLevel); - - var searchName = ShortenName(Name); - while (!string.IsNullOrEmpty(searchName)) - { - var searchSource = new TraceSource(searchName, defaultLevel); - if (IsSourceConfigured(searchSource)) - { - foundSource = searchSource; - break; - } - - searchName = ShortenName(searchName); - } - - // reconfigure the created source to act like the found source - traceSource.Switch = foundSource.Switch; - traceSource.Listeners.Clear(); - foreach (TraceListener listener in foundSource.Listeners) - { - traceSource.Listeners.Add(listener); - } - - cache.Add(Name, traceSource); - } - } - - private static string ShortenName(string name) - { - var lastDot = name.LastIndexOf('.'); - if (lastDot != -1) - { - return name.Substring(0, lastDot); - } - return null; - } - - private static bool IsSourceConfigured(TraceSource source) - { - if (source.Listeners.Count == 1 && - source.Listeners[0] is DefaultTraceListener && - source.Listeners[0].Name == "Default") - { - return false; - } - return true; - } - - private static LoggerLevel MapLoggerLevel(SourceLevels level) - { - switch (level) - { - case SourceLevels.All: - return LoggerLevel.Trace; - case SourceLevels.Verbose: - return LoggerLevel.Debug; - case SourceLevels.Information: - return LoggerLevel.Info; - case SourceLevels.Warning: - return LoggerLevel.Warn; - case SourceLevels.Error: - return LoggerLevel.Error; - case SourceLevels.Critical: - return LoggerLevel.Fatal; - } - return LoggerLevel.Off; - } - - private static SourceLevels MapSourceLevels(LoggerLevel level) - { - switch (level) - { - case LoggerLevel.Trace: - return SourceLevels.All; - case LoggerLevel.Debug: - return SourceLevels.Verbose; - case LoggerLevel.Info: - return SourceLevels.Information; - case LoggerLevel.Warn: - return SourceLevels.Warning; - case LoggerLevel.Error: - return SourceLevels.Error; - case LoggerLevel.Fatal: - return SourceLevels.Critical; - } - return SourceLevels.Off; - } - - private static TraceEventType MapTraceEventType(LoggerLevel level) - { - switch (level) - { - case LoggerLevel.Trace: - case LoggerLevel.Debug: - return TraceEventType.Verbose; - case LoggerLevel.Info: - return TraceEventType.Information; - case LoggerLevel.Warn: - return TraceEventType.Warning; - case LoggerLevel.Error: - return TraceEventType.Error; - case LoggerLevel.Fatal: - return TraceEventType.Critical; - } - return TraceEventType.Verbose; - } - } -} \ No newline at end of file diff --git a/Castle.Core/Core/Logging/TraceLoggerFactory.cs b/Castle.Core/Core/Logging/TraceLoggerFactory.cs deleted file mode 100644 index 06dfea0..0000000 --- a/Castle.Core/Core/Logging/TraceLoggerFactory.cs +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Core.Logging -{ - /// - /// Used to create the TraceLogger implementation of ILogger interface. See . - /// - public class TraceLoggerFactory : AbstractLoggerFactory - { - private readonly LoggerLevel? level; - - public TraceLoggerFactory() - { - } - - public TraceLoggerFactory(LoggerLevel level) - { - this.level = level; - } - - public override ILogger Create(string name) - { - if (level.HasValue) - { - return Create(name, level.Value); - } - return InternalCreate(name); - } - - private ILogger InternalCreate(string name) - { - return new TraceLogger(name); - } - - public override ILogger Create(string name, LoggerLevel level) - { - return InternalCreate(name, level); - } - - private ILogger InternalCreate(string name, LoggerLevel level) - { - return new TraceLogger(name, level); - } - } -} \ No newline at end of file diff --git a/Castle.Core/Core/ProxyServices.cs b/Castle.Core/Core/ProxyServices.cs deleted file mode 100644 index 04e239f..0000000 --- a/Castle.Core/Core/ProxyServices.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Core -{ - using System; - using System.Reflection; - - /// - /// List of utility methods related to dynamic proxy operations - /// - public static class ProxyServices - { - /// - /// Determines whether the specified type is a proxy generated by - /// DynamicProxy (1 or 2). - /// - /// The type. - /// - /// true if it is a proxy; otherwise, false. - /// - public static bool IsDynamicProxy(Type type) - { - string assemblyName = type.Assembly.FullName; - - return (assemblyName.StartsWith("DynamicAssemblyProxyGen", StringComparison.Ordinal) || - assemblyName.StartsWith("DynamicProxyGenAssembly2", StringComparison.Ordinal)); - } - } -} diff --git a/Castle.Core/Core/ReferenceEqualityComparer.cs b/Castle.Core/Core/ReferenceEqualityComparer.cs deleted file mode 100644 index 3b91551..0000000 --- a/Castle.Core/Core/ReferenceEqualityComparer.cs +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Core -{ - using System; - using System.Collections; - using System.Collections.Generic; - using System.Runtime.CompilerServices; - -#if FEATURE_SERIALIZATION - [Serializable] -#endif - public class ReferenceEqualityComparer : IEqualityComparer, IEqualityComparer - { - private static readonly ReferenceEqualityComparer instance = new ReferenceEqualityComparer(); - - private ReferenceEqualityComparer() - { - } - - public int GetHashCode(object obj) - { - return RuntimeHelpers.GetHashCode(obj); - } - - bool IEqualityComparer.Equals(object x, object y) - { - return ReferenceEquals(x, y); - } - - bool IEqualityComparer.Equals(T x, T y) - { - return ReferenceEquals(x, y); - } - - int IEqualityComparer.GetHashCode(T obj) - { - return RuntimeHelpers.GetHashCode(obj); - } - - public static ReferenceEqualityComparer Instance - { - get { return instance; } - } - } -} \ No newline at end of file diff --git a/Castle.Core/Core/ReflectionBasedDictionaryAdapter.cs b/Castle.Core/Core/ReflectionBasedDictionaryAdapter.cs deleted file mode 100644 index 3080f05..0000000 --- a/Castle.Core/Core/ReflectionBasedDictionaryAdapter.cs +++ /dev/null @@ -1,299 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Core -{ - using System; - using System.Collections; - using System.Collections.Generic; - using System.Linq; - using System.Reflection; - - /// - /// Readonly implementation of which uses an anonymous object as its source. Uses names of properties as keys, and property values as... well - values. Keys are not case sensitive. - /// - public sealed class ReflectionBasedDictionaryAdapter : IDictionary - { - private readonly Dictionary properties = - new Dictionary(StringComparer.OrdinalIgnoreCase); - - /// - /// Initializes a new instance of the class. - /// - /// The target. - public ReflectionBasedDictionaryAdapter(object target) - { - if (target == null) - { - throw new ArgumentNullException(nameof(target)); - } - Read(properties, target); - } - - /// - /// Gets the number of elements contained in the . - /// - /// The number of elements contained in the . - public int Count - { - get { return properties.Count; } - } - - /// - /// Gets a value indicating whether access to the is synchronized (thread safe). - /// - /// true if access to the is synchronized (thread safe); otherwise, false. - public bool IsSynchronized - { - get { return false; } - } - - /// - /// Gets an object that can be used to synchronize access to the . - /// - /// An object that can be used to synchronize access to the . - public object SyncRoot - { - get { return properties; } - } - - /// - /// Gets a value indicating whether the object is read-only. - /// - /// true if the object is read-only; otherwise, false. - public bool IsReadOnly - { - get { return true; } - } - - /// - /// Gets or sets the with the specified key. - /// - public object this[object key] - { - get - { - object value; - properties.TryGetValue(key.ToString(), out value); - return value; - } - set { throw new NotImplementedException(); } - } - - /// - /// Gets an object containing the keys of the object. - /// - /// An object containing the keys of the object. - public ICollection Keys - { - get { return properties.Keys; } - } - - /// - /// Gets an object containing the values in the object. - /// - /// An object containing the values in the object. - public ICollection Values - { - get { return properties.Values; } - } - - /// - /// Gets a value indicating whether the object has a fixed size. - /// - /// true if the object has a fixed size; otherwise, false. - bool IDictionary.IsFixedSize - { - get { throw new NotImplementedException(); } - } - - /// - /// Adds an element with the provided key and value to the object. - /// - /// The to use as the key of the element to add. - /// The to use as the value of the element to add. - /// - /// is null. - /// An element with the same key already exists in the object. - /// The is read-only.-or- The has a fixed size. - public void Add(object key, object value) - { - throw new NotImplementedException(); - } - - /// - /// Removes all elements from the object. - /// - /// The object is read-only. - public void Clear() - { - throw new NotImplementedException(); - } - - /// - /// Determines whether the object contains an element with the specified key. - /// - /// The key to locate in the object. - /// - /// true if the contains an element with the key; otherwise, false. - /// - /// - /// is null. - public bool Contains(object key) - { - return properties.ContainsKey(key.ToString()); - } - - /// - /// Removes the element with the specified key from the object. - /// - /// The key of the element to remove. - /// - /// is null. - /// The object is read-only.-or- The has a fixed size. - public void Remove(object key) - { - } - - /// - /// Returns an enumerator that iterates through a collection. - /// - /// - /// An object that can be used to iterate through the collection. - /// - public IEnumerator GetEnumerator() - { - return new DictionaryEntryEnumeratorAdapter(properties.GetEnumerator()); - } - - /// - /// Copies the elements of the to an , starting at a particular index. - /// - /// The one-dimensional that is the destination of the elements copied from . The must have zero-based indexing. - /// The zero-based index in at which copying begins. - /// - /// is null. - /// - /// is less than zero. - /// - /// is multidimensional.-or- is equal to or greater than the length of .-or- The number of elements in the source is greater than the available space from to the end of the destination . - /// The type of the source cannot be cast automatically to the type of the destination . - void ICollection.CopyTo(Array array, int index) - { - throw new NotImplementedException(); - } - - /// - /// Returns an object for the object. - /// - /// - /// An object for the object. - /// - IDictionaryEnumerator IDictionary.GetEnumerator() - { - return new DictionaryEntryEnumeratorAdapter(properties.GetEnumerator()); - } - - /// - /// Reads values of properties from and inserts them into using property names as keys. - /// - public static void Read(IDictionary targetDictionary, object valuesAsAnonymousObject) - { - var targetType = valuesAsAnonymousObject.GetType(); - foreach (var property in GetReadableProperties(targetType)) - { - var value = GetPropertyValue(valuesAsAnonymousObject, property); - targetDictionary[property.Name] = value; - } - } - - private static object GetPropertyValue(object target, PropertyInfo property) - { - return property.GetValue(target, null); - } - - private static IEnumerable GetReadableProperties(Type targetType) - { - return targetType.GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(IsReadable); - } - - private static bool IsReadable(PropertyInfo property) - { - return property.CanRead && property.GetIndexParameters().Length == 0; - } - - private class DictionaryEntryEnumeratorAdapter : IDictionaryEnumerator - { - private readonly IDictionaryEnumerator enumerator; - private KeyValuePair current; - - public DictionaryEntryEnumeratorAdapter(IDictionaryEnumerator enumerator) - { - this.enumerator = enumerator; - } - - public DictionaryEntry Entry - { - get { return new DictionaryEntry(Key, Value); } - } - - public object Key - { - get { return current.Key; } - } - - public object Value - { - get { return current.Value; } - } - - public object Current - { - get { return new DictionaryEntry(Key, Value); } - } - - public bool MoveNext() - { - var moved = enumerator.MoveNext(); - - if (moved) - { - current = (KeyValuePair)enumerator.Current; - } - - return moved; - } - - public void Reset() - { - enumerator.Reset(); - } - } - } -} \ No newline at end of file diff --git a/Castle.Core/Core/Resource/AbstractResource.cs b/Castle.Core/Core/Resource/AbstractResource.cs deleted file mode 100644 index e339cd4..0000000 --- a/Castle.Core/Core/Resource/AbstractResource.cs +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Core.Resource -{ - using System; - using System.IO; - using System.Text; - - public abstract class AbstractResource : IResource - { - protected static readonly string DefaultBasePath = AppDomain.CurrentDomain.BaseDirectory; - - public virtual string FileBasePath - { - get { return DefaultBasePath; } - } - - public abstract TextReader GetStreamReader(); - - public abstract TextReader GetStreamReader(Encoding encoding); - - public abstract IResource CreateRelative(string relativePath); - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - protected virtual void Dispose(bool disposing) - { - } - } -} diff --git a/Castle.Core/Core/Resource/AbstractStreamResource.cs b/Castle.Core/Core/Resource/AbstractStreamResource.cs deleted file mode 100644 index 3afa4c8..0000000 --- a/Castle.Core/Core/Resource/AbstractStreamResource.cs +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Core.Resource -{ - using System.IO; - using System.Text; - - public delegate Stream StreamFactory(); - - /// - /// - /// - public abstract class AbstractStreamResource : AbstractResource - { - /// - /// This returns a new stream instance each time it is called. - /// It is the responsibility of the caller to dispose of this stream - /// - private StreamFactory createStream; - - ~AbstractStreamResource() - { - Dispose(false); - } - - public StreamFactory CreateStream - { - get { return createStream; } - set { createStream = value; } - } - - public override TextReader GetStreamReader() - { - return new StreamReader(CreateStream()); - } - - public override TextReader GetStreamReader(Encoding encoding) - { - return new StreamReader(CreateStream(), encoding); - } - } -} \ No newline at end of file diff --git a/Castle.Core/Core/Resource/AssemblyBundleResource.cs b/Castle.Core/Core/Resource/AssemblyBundleResource.cs deleted file mode 100644 index 272c036..0000000 --- a/Castle.Core/Core/Resource/AssemblyBundleResource.cs +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Core.Resource -{ - using System; - using System.Globalization; - using System.IO; - using System.Reflection; - using System.Resources; - using System.Text; - - public class AssemblyBundleResource : AbstractResource - { - private readonly CustomUri resource; - - public AssemblyBundleResource(CustomUri resource) - { - this.resource = resource; - } - - public override TextReader GetStreamReader() - { - var assembly = ObtainAssembly(resource.Host); - - var paths = resource.Path.Split(new[] {'/'}, StringSplitOptions.RemoveEmptyEntries); - if (paths.Length != 2) - { - throw new ResourceException("AssemblyBundleResource does not support paths with more than 2 levels in depth. See " + - resource.Path); - } - - var rm = new ResourceManager(paths[0], assembly); - - return new StringReader(rm.GetString(paths[1])); - } - - public override TextReader GetStreamReader(Encoding encoding) - { - return GetStreamReader(); - } - - public override IResource CreateRelative(string relativePath) - { - throw new NotImplementedException(); - } - - private static Assembly ObtainAssembly(string assemblyName) - { - try - { - return Assembly.Load(assemblyName); - } - catch (Exception ex) - { - var message = string.Format(CultureInfo.InvariantCulture, "The assembly {0} could not be loaded", assemblyName); - throw new ResourceException(message, ex); - } - } - } -} \ No newline at end of file diff --git a/Castle.Core/Core/Resource/AssemblyResource.cs b/Castle.Core/Core/Resource/AssemblyResource.cs deleted file mode 100644 index 08882f2..0000000 --- a/Castle.Core/Core/Resource/AssemblyResource.cs +++ /dev/null @@ -1,156 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Core.Resource -{ - using System; - using System.Globalization; - using System.IO; - using System.Reflection; - - public class AssemblyResource : AbstractStreamResource - { - private string assemblyName; - private string resourcePath; - private string basePath; - - public AssemblyResource(CustomUri resource) - { - CreateStream = delegate - { - return CreateResourceFromUri(resource, null); - }; - } - - public AssemblyResource(CustomUri resource, string basePath) - { - CreateStream = delegate - { - return CreateResourceFromUri(resource, basePath); - }; - } - - public AssemblyResource(string resource) - { - CreateStream = delegate - { - return CreateResourceFromPath(resource, basePath); - }; - } - - public override IResource CreateRelative(string relativePath) - { - throw new NotImplementedException(); - } - - public override string ToString() - { - return string.Format(CultureInfo.CurrentCulture, "AssemblyResource: [{0}] [{1}]", assemblyName, resourcePath); - } - - private Stream CreateResourceFromPath(string resource, string path) - { - if (!resource.StartsWith("assembly" + CustomUri.SchemeDelimiter, StringComparison.CurrentCulture)) - { - resource = "assembly" + CustomUri.SchemeDelimiter + resource; - } - - return CreateResourceFromUri(new CustomUri(resource), path); - } - - private Stream CreateResourceFromUri(CustomUri resourcex, string path) - { - if (resourcex == null) throw new ArgumentNullException(nameof(resourcex)); - - assemblyName = resourcex.Host; - resourcePath = ConvertToResourceName(assemblyName, resourcex.Path); - - Assembly assembly = ObtainAssembly(assemblyName); - - string[] names = assembly.GetManifestResourceNames(); - - string nameFound = GetNameFound(names); - - if (nameFound == null) - { - resourcePath = resourcex.Path.Replace('/', '.').Substring(1); - nameFound = GetNameFound(names); - } - - if (nameFound == null) - { - string message = string.Format(CultureInfo.InvariantCulture, "The assembly resource {0} could not be located", resourcePath); - throw new ResourceException(message); - } - - basePath = ConvertToPath(resourcePath); - - return assembly.GetManifestResourceStream(nameFound); - } - - private string GetNameFound(string[] names) - { - string nameFound = null; - foreach(string name in names) - { - if (string.Compare(resourcePath, name, StringComparison.OrdinalIgnoreCase) == 0) - { - nameFound = name; - break; - } - } - return nameFound; - } - - private string ConvertToResourceName(string assembly, string resource) - { - assembly = GetSimpleName(assembly); - // TODO: use path for relative name construction - return string.Format(CultureInfo.CurrentCulture, "{0}{1}", assembly, resource.Replace('/', '.')); - } - - private string GetSimpleName(string assembly) - { - int indexOfComma = assembly.IndexOf(','); - if(indexOfComma<0) - { - return assembly; - } - return assembly.Substring(0, indexOfComma); - } - - private string ConvertToPath(string resource) - { - string path = resource.Replace('.', '/'); - if (path[0] != '/') - { - path = string.Format(CultureInfo.CurrentCulture, "/{0}", path); - } - return path; - } - - private static Assembly ObtainAssembly(string assemblyName) - { - try - { - return Assembly.Load(assemblyName); - } - catch (Exception ex) - { - string message = string.Format(CultureInfo.InvariantCulture, "The assembly {0} could not be loaded", assemblyName); - throw new ResourceException(message, ex); - } - } - } -} diff --git a/Castle.Core/Core/Resource/AssemblyResourceFactory.cs b/Castle.Core/Core/Resource/AssemblyResourceFactory.cs deleted file mode 100644 index 1122c44..0000000 --- a/Castle.Core/Core/Resource/AssemblyResourceFactory.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Core.Resource -{ - using System; - - public class AssemblyResourceFactory : IResourceFactory - { - public bool Accept(CustomUri uri) - { - return "assembly".Equals(uri.Scheme); - } - - public IResource Create(CustomUri uri) - { - return Create(uri, null); - } - - public IResource Create(CustomUri uri, string basePath) - { - if (basePath == null) - { - return new AssemblyResource(uri); - } - - return new AssemblyResource(uri, basePath); - } - } -} \ No newline at end of file diff --git a/Castle.Core/Core/Resource/ConfigResource.cs b/Castle.Core/Core/Resource/ConfigResource.cs deleted file mode 100644 index cdefe0d..0000000 --- a/Castle.Core/Core/Resource/ConfigResource.cs +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#if FEATURE_SYSTEM_CONFIGURATION - -namespace Castle.Core.Resource -{ - using System; - using System.Configuration; - using System.Globalization; - using System.IO; - using System.Text; - using System.Xml; - - public class ConfigResource : AbstractResource - { - private readonly XmlNode configSectionNode; - private readonly string sectionName; - - public ConfigResource() : this("castle") - { - } - - public ConfigResource(CustomUri uri) : this(uri.Host) - { - } - - public ConfigResource(string sectionName) - { - this.sectionName = sectionName; - - XmlNode node = (XmlNode) ConfigurationManager.GetSection(sectionName); - - if (node == null) - { - string message = string.Format(CultureInfo.InvariantCulture, - "Could not find section '{0}' in the configuration file associated with this domain.", sectionName); - throw new ConfigurationErrorsException(message); - } - - // TODO: Check whether it's CData section - configSectionNode = node; - } - - public override TextReader GetStreamReader() - { - return new StringReader(configSectionNode.OuterXml); - } - - public override TextReader GetStreamReader(Encoding encoding) - { - throw new NotSupportedException("Encoding is not supported"); - } - - public override IResource CreateRelative(string relativePath) - { - return new ConfigResource(relativePath); - } - - public override string ToString() - { - return string.Format(CultureInfo.CurrentCulture, "ConfigResource: [{0}]", sectionName); - } - } -} - -#endif \ No newline at end of file diff --git a/Castle.Core/Core/Resource/ConfigResourceFactory.cs b/Castle.Core/Core/Resource/ConfigResourceFactory.cs deleted file mode 100644 index bb94c75..0000000 --- a/Castle.Core/Core/Resource/ConfigResourceFactory.cs +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#if FEATURE_SYSTEM_CONFIGURATION - -namespace Castle.Core.Resource -{ - using System; - - public class ConfigResourceFactory : IResourceFactory - { - public ConfigResourceFactory() - { - } - - public bool Accept(CustomUri uri) - { - return "config".Equals(uri.Scheme); - } - - public IResource Create(CustomUri uri) - { - return new ConfigResource(uri); - } - - public IResource Create(CustomUri uri, string basePath) - { - return Create(uri); - } - } -} - -#endif \ No newline at end of file diff --git a/Castle.Core/Core/Resource/CustomUri.cs b/Castle.Core/Core/Resource/CustomUri.cs deleted file mode 100644 index fe19ab1..0000000 --- a/Castle.Core/Core/Resource/CustomUri.cs +++ /dev/null @@ -1,139 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Core.Resource -{ - using System; - using System.Text; - -#if FEATURE_SERIALIZATION - [Serializable] -#endif - public sealed class CustomUri - { - public static readonly string SchemeDelimiter = "://"; - public static readonly string UriSchemeFile = "file"; - public static readonly string UriSchemeAssembly = "assembly"; - - private string scheme; - private string host; - private string path; - private bool isUnc; - private bool isFile; - private bool isAssembly; - - public CustomUri(string resourceIdentifier) - { - if (resourceIdentifier == null) - { - throw new ArgumentNullException(nameof(resourceIdentifier)); - } - if (resourceIdentifier == string.Empty) - { - throw new ArgumentException("Empty resource identifier is not allowed", nameof(resourceIdentifier)); - } - - ParseIdentifier(resourceIdentifier); - } - - public bool IsUnc - { - get { return isUnc; } - } - - public bool IsFile - { - get { return isFile; } - } - - public bool IsAssembly - { - get { return isAssembly; } - } - - public string Scheme - { - get { return scheme; } - } - - public string Host - { - get { return host; } - } - - public string Path - { - get { return path; } - } - - private void ParseIdentifier(string identifier) - { - int comma = identifier.IndexOf(':'); - - if (comma == -1 && !(identifier[0] == '\\' && identifier[1] == '\\') && identifier[0] != '/') - { - throw new ArgumentException("Invalid Uri: no scheme delimiter found on " + identifier); - } - - bool translateSlashes = true; - - if (identifier[0] == '\\' && identifier[1] == '\\') - { - // Unc - - isUnc = true; - isFile = true; - scheme = UriSchemeFile; - translateSlashes = false; - } - else if (identifier[comma + 1] == '/' && identifier[comma + 2] == '/') - { - // Extract scheme - - scheme = identifier.Substring(0, comma); - - isFile = (scheme == UriSchemeFile); - isAssembly = (scheme == UriSchemeAssembly); - - identifier = identifier.Substring(comma + SchemeDelimiter.Length); - } - else - { - isFile = true; - scheme = UriSchemeFile; - } - - var sb = new StringBuilder(); - foreach(char ch in identifier.ToCharArray()) - { - if (translateSlashes && (ch == '\\' || ch == '/')) - { - if (host == null && !IsFile) - { - host = sb.ToString(); - sb.Length = 0; - } - - sb.Append('/'); - } - else - { - sb.Append(ch); - } - } - - path = Environment.ExpandEnvironmentVariables(sb.ToString()); - } - } -} \ No newline at end of file diff --git a/Castle.Core/Core/Resource/FileResource.cs b/Castle.Core/Core/Resource/FileResource.cs deleted file mode 100644 index 39854ba..0000000 --- a/Castle.Core/Core/Resource/FileResource.cs +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Core.Resource -{ - using System; - using System.Globalization; - using System.IO; - - /// - /// - /// - public class FileResource : AbstractStreamResource - { - private string filePath; - private string basePath; - - public FileResource(CustomUri resource) - { - CreateStream = delegate - { - return CreateStreamFromUri(resource, DefaultBasePath); - }; - } - - public FileResource(CustomUri resource, string basePath) - { - CreateStream = delegate - { - return CreateStreamFromUri(resource, basePath); - }; - } - - public FileResource(string resourceName) - { - CreateStream = delegate - { - return CreateStreamFromPath(resourceName, DefaultBasePath); - }; - } - - public FileResource(string resourceName, string basePath) - { - CreateStream = delegate - { - return CreateStreamFromPath(resourceName, basePath); - }; - } - - public override string ToString() - { - return string.Format(CultureInfo.CurrentCulture, "FileResource: [{0}] [{1}]", filePath, basePath); - } - - public override string FileBasePath - { - get { return basePath; } - } - - public override IResource CreateRelative(string relativePath) - { - return new FileResource(relativePath, basePath); - } - - private Stream CreateStreamFromUri(CustomUri resource, string rootPath) - { - if (resource == null) throw new ArgumentNullException(nameof(resource)); - if (rootPath == null) throw new ArgumentNullException(nameof(rootPath)); - - if (!resource.IsFile) - throw new ArgumentException("The specified resource is not a file", nameof(resource)); - - return CreateStreamFromPath(resource.Path, rootPath); - } - - private Stream CreateStreamFromPath(string resourcePath, string rootPath) - { - if (resourcePath == null) - throw new ArgumentNullException(nameof(resourcePath)); - if (rootPath == null) - throw new ArgumentNullException(nameof(rootPath)); - - if (!Path.IsPathRooted(resourcePath) || !File.Exists(resourcePath)) - { - // For a relative path, we use the basePath to - // resolve the full path - - resourcePath = Path.Combine(rootPath, resourcePath); - } - - CheckFileExists(resourcePath); - - this.filePath = Path.GetFileName(resourcePath); - this.basePath = Path.GetDirectoryName(resourcePath); - - return File.OpenRead(resourcePath); - } - - private static void CheckFileExists(string path) - { - if (!File.Exists(path)) - { - string message = string.Format(CultureInfo.InvariantCulture, "File {0} could not be found", new FileInfo(path).FullName); - throw new ResourceException(message); - } - } - } -} \ No newline at end of file diff --git a/Castle.Core/Core/Resource/FileResourceFactory.cs b/Castle.Core/Core/Resource/FileResourceFactory.cs deleted file mode 100644 index 2d8fead..0000000 --- a/Castle.Core/Core/Resource/FileResourceFactory.cs +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Core.Resource -{ - using System; - - /// - /// - /// - public class FileResourceFactory : IResourceFactory - { - public FileResourceFactory() - { - } - - public bool Accept(CustomUri uri) - { - return "file".Equals(uri.Scheme); - } - - public IResource Create(CustomUri uri) - { - return Create(uri, null); - } - - public IResource Create(CustomUri uri, string basePath) - { - if (basePath != null) - return new FileResource(uri, basePath); - else - return new FileResource(uri); - } - } -} diff --git a/Castle.Core/Core/Resource/IResource.cs b/Castle.Core/Core/Resource/IResource.cs deleted file mode 100644 index 9651ed2..0000000 --- a/Castle.Core/Core/Resource/IResource.cs +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Core.Resource -{ - using System; - using System.IO; - using System.Text; - - /// - /// Represents a 'streamable' resource. Can - /// be a file, a resource in an assembly. - /// - public interface IResource : IDisposable - { - /// - /// Only valid for resources that - /// can be obtained through relative paths - /// - string FileBasePath { get; } - - /// - /// Returns a reader for the stream - /// - /// - /// It's up to the caller to dispose the reader. - /// - TextReader GetStreamReader(); - - /// - /// Returns a reader for the stream - /// - /// - /// It's up to the caller to dispose the reader. - /// - TextReader GetStreamReader(Encoding encoding); - - /// - /// Returns an instance of - /// created according to the relativePath - /// using itself as the root. - /// - IResource CreateRelative(string relativePath); - } -} \ No newline at end of file diff --git a/Castle.Core/Core/Resource/IResourceFactory.cs b/Castle.Core/Core/Resource/IResourceFactory.cs deleted file mode 100644 index 7950da1..0000000 --- a/Castle.Core/Core/Resource/IResourceFactory.cs +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Core.Resource -{ - using System; - - /// - /// Depicts the contract for resource factories. - /// - public interface IResourceFactory - { - /// - /// Used to check whether the resource factory - /// is able to deal with the given resource - /// identifier. - /// - /// - /// Implementors should return true - /// only if the given identifier is supported - /// by the resource factory - /// - bool Accept(CustomUri uri); - - /// - /// Creates an instance - /// for the given resource identifier - /// - IResource Create(CustomUri uri); - - /// - /// Creates an instance - /// for the given resource identifier - /// - IResource Create(CustomUri uri, string basePath); - } -} \ No newline at end of file diff --git a/Castle.Core/Core/Resource/ResourceException.cs b/Castle.Core/Core/Resource/ResourceException.cs deleted file mode 100644 index f71e2ea..0000000 --- a/Castle.Core/Core/Resource/ResourceException.cs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Core.Resource -{ - using System; - using System.Runtime.Serialization; - - [Serializable] - public class ResourceException : Exception - { - public ResourceException() - { - } - - public ResourceException(string message) : base(message) - { - } - - public ResourceException(string message, Exception innerException) : base(message, innerException) - { - } - - protected ResourceException(SerializationInfo info, StreamingContext context) : base(info, context) - { - } - } -} \ No newline at end of file diff --git a/Castle.Core/Core/Resource/StaticContentResource.cs b/Castle.Core/Core/Resource/StaticContentResource.cs deleted file mode 100644 index 8182afc..0000000 --- a/Castle.Core/Core/Resource/StaticContentResource.cs +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Core.Resource -{ - using System; - using System.IO; - using System.Text; - - /// - /// Adapts a static string content as an - /// - public class StaticContentResource : AbstractResource - { - private readonly string contents; - - public StaticContentResource(string contents) - { - this.contents = contents; - } - - public override TextReader GetStreamReader() - { - return new StringReader(contents); - } - - public override TextReader GetStreamReader(Encoding encoding) - { - throw new NotImplementedException(); - } - - public override IResource CreateRelative(string relativePath) - { - throw new NotImplementedException(); - } - } -} \ No newline at end of file diff --git a/Castle.Core/Core/Resource/UncResource.cs b/Castle.Core/Core/Resource/UncResource.cs deleted file mode 100644 index 3fcc5f6..0000000 --- a/Castle.Core/Core/Resource/UncResource.cs +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Core.Resource -{ - using System; - using System.Globalization; - using System.IO; - - /// - /// Enable access to files on network shares - /// - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Unc")] - public class UncResource : AbstractStreamResource - { - private string basePath; - private string filePath; - - public UncResource(CustomUri resource) - { - CreateStream = delegate - { - return CreateStreamFromUri(resource, DefaultBasePath); - }; - } - - public UncResource(CustomUri resource, string basePath) - { - CreateStream = delegate - { - return CreateStreamFromUri(resource, basePath); - }; - } - - public UncResource(string resourceName) : this(new CustomUri(resourceName)) - { - } - - public UncResource(string resourceName, string basePath) : this(new CustomUri(resourceName), basePath) - { - } - - public override string FileBasePath - { - get { return basePath; } - } - - public override IResource CreateRelative(string relativePath) - { - return new UncResource(Path.Combine(basePath, relativePath)); - } - - public override string ToString() - { - return string.Format(CultureInfo.CurrentCulture, "UncResource: [{0}] [{1}]", filePath, basePath); - } - - private Stream CreateStreamFromUri(CustomUri resource, string rootPath) - { - if (resource == null) - throw new ArgumentNullException(nameof(resource)); - if (!resource.IsUnc) - throw new ArgumentException("Resource must be an Unc", nameof(resource)); - if (!resource.IsFile) - throw new ArgumentException("The specified resource is not a file", nameof(resource)); - - string resourcePath = resource.Path; - - if (!File.Exists(resourcePath) && rootPath != null) - { - resourcePath = Path.Combine(rootPath, resourcePath); - } - - filePath = Path.GetFileName(resourcePath); - basePath = Path.GetDirectoryName(resourcePath); - - CheckFileExists(resourcePath); - - return File.OpenRead(resourcePath); - } - - private static void CheckFileExists(string path) - { - if (!File.Exists(path)) - { - string message = string.Format(CultureInfo.InvariantCulture, "File {0} could not be found", path); - throw new ResourceException(message); - } - } - } -} \ No newline at end of file diff --git a/Castle.Core/Core/Resource/UncResourceFactory.cs b/Castle.Core/Core/Resource/UncResourceFactory.cs deleted file mode 100644 index 6a66730..0000000 --- a/Castle.Core/Core/Resource/UncResourceFactory.cs +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Core.Resource -{ - using System; - - public class UncResourceFactory : IResourceFactory - { - public UncResourceFactory() - { - } - - public bool Accept(CustomUri uri) - { - return uri.IsUnc; - } - - public IResource Create(CustomUri uri) - { - return new UncResource(uri); - } - - public IResource Create(CustomUri uri, string basePath) - { - return new UncResource(uri, basePath); - } - } -} \ No newline at end of file diff --git a/Castle.Core/Core/Smtp/DefaultSmtpSender.cs b/Castle.Core/Core/Smtp/DefaultSmtpSender.cs deleted file mode 100644 index 030b24d..0000000 --- a/Castle.Core/Core/Smtp/DefaultSmtpSender.cs +++ /dev/null @@ -1,250 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma warning disable 618 // Mono marked SmtpClient obsolete - -namespace Castle.Core.Smtp -{ - using System; - using System.Collections.Generic; - using System.ComponentModel; - using System.Net; - using System.Net.Mail; - - using Castle.Core.Internal; - - /// - /// Default implementation. - /// - public class DefaultSmtpSender : IEmailSender - { - private bool asyncSend; - private readonly string hostname; - private int port = 25; - private int? timeout; - private bool useSsl; - - /// - /// Initializes a new instance of the class based on the configuration provided in the application configuration file. - /// - /// - /// This constructor is based on the default configuration in the application configuration file. - /// - public DefaultSmtpSender() { } - - /// - /// This service implementation - /// requires a host name in order to work - /// - /// The smtp server name - public DefaultSmtpSender(string hostname) - { - this.hostname = hostname; - } - - /// - /// Gets or sets the port used to - /// access the SMTP server - /// - public int Port - { - get { return port; } - set { port = value; } - } - - /// - /// Gets the hostname. - /// - /// The hostname. - public string Hostname - { - get { return hostname; } - } - - /// - /// Gets or sets a value which is used to - /// configure if emails are going to be sent asynchronously or not. - /// - public bool AsyncSend - { - get { return asyncSend; } - set { asyncSend = value; } - } - - /// - /// Gets or sets a value that specifies - /// the amount of time after which a synchronous Send call times out. - /// - public int Timeout - { - get { return timeout.HasValue ? timeout.Value : 0; } - set { timeout = value; } - } - - /// - /// Gets or sets a value indicating whether the email should be sent using - /// a secure communication channel. - /// - /// true if should use SSL; otherwise, false. - public bool UseSsl - { - get { return useSsl; } - set { useSsl = value; } - } - - /// - /// Sends a message. - /// - /// If any of the parameters is null - /// From field - /// To field - /// e-mail's subject - /// message's body - public void Send(string from, string to, string subject, string messageText) - { - if (from == null) throw new ArgumentNullException(nameof(from)); - if (to == null) throw new ArgumentNullException(nameof(to)); - if (subject == null) throw new ArgumentNullException(nameof(subject)); - if (messageText == null) throw new ArgumentNullException(nameof(messageText)); - - Send(new MailMessage(from, to, subject, messageText)); - } - - /// - /// Sends a message. - /// - /// If the message is null - /// Message instance - public void Send(MailMessage message) - { - InternalSend(message); - } - - private void InternalSend(MailMessage message) - { - if (message == null) throw new ArgumentNullException(nameof(message)); - - if (asyncSend) - { - // The MailMessage must be disposed after sending the email. - // The code creates a delegate for deleting the mail and adds - // it to the smtpClient. - // After the mail is sent, the message is disposed and the - // eventHandler removed from the smtpClient. - - SmtpClient smtpClient = CreateSmtpClient(); - Guid msgGuid = new Guid(); - SendCompletedEventHandler sceh = null; - sceh = delegate(object sender, AsyncCompletedEventArgs e) - { - if (msgGuid == (Guid)e.UserState) - message.Dispose(); - // The handler itself, cannot be null, test omitted - smtpClient.SendCompleted -= sceh; - }; - smtpClient.SendCompleted += sceh; - smtpClient.SendAsync(message, msgGuid); - } - else - { - using (message) - { - SmtpClient smtpClient = CreateSmtpClient(); - - smtpClient.Send(message); - } - } - } - - public void Send(IEnumerable messages) - { - foreach (MailMessage message in messages) - { - Send(message); - } - } - - /// - /// Gets or sets the domain. - /// - /// The domain. - public string Domain { get; set; } - - /// - /// Gets or sets the name of the user. - /// - /// The name of the user. - public string UserName { get; set; } - - /// - /// Gets or sets the password. - /// - /// The password. - public string Password { get; set; } - - /// - /// Configures the sender - /// with port information and eventual credential - /// informed - /// - /// Message instance - protected virtual void Configure(SmtpClient smtpClient) - { - smtpClient.Credentials = null; - - if (HasCredentials) - { - var credentials = new NetworkCredential(UserName, Password, Domain); - smtpClient.Credentials = credentials; - } - - if (timeout.HasValue) - { - smtpClient.Timeout = timeout.Value; - } - - if (useSsl) - { - smtpClient.EnableSsl = useSsl; - } - } - - /// - /// Gets a value indicating whether credentials were informed. - /// - /// - /// if this instance has credentials; otherwise, . - /// - private bool HasCredentials - { - get { return !string.IsNullOrEmpty(UserName); } - } - - private SmtpClient CreateSmtpClient() - { - if (string.IsNullOrEmpty(hostname)) - { - // No hostname configured, use the settings provided in system.net.smtp (SmtpClient default behavior) - return new SmtpClient(); - } - - // A hostname is provided - init and configure using configured settings - var smtpClient = new SmtpClient(hostname, port); - Configure(smtpClient); - return smtpClient; - } - } -} - -#pragma warning restore 618 // Mono marked SmtpClient obsolete diff --git a/Castle.Core/Core/Smtp/IEmailSender.cs b/Castle.Core/Core/Smtp/IEmailSender.cs deleted file mode 100644 index 9f01f54..0000000 --- a/Castle.Core/Core/Smtp/IEmailSender.cs +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Core.Smtp -{ - using System.Collections.Generic; - using System.Net.Mail; - - /// - /// Email sender abstraction. - /// - public interface IEmailSender - { - /// - /// Sends a mail message. - /// - /// From field - /// To field - /// E-mail's subject - /// message's body - void Send(string from, string to, string subject, string messageText); - - /// - /// Sends a message. - /// - /// Message instance - void Send(MailMessage message); - - /// - /// Sends multiple messages. - /// - /// List of messages - void Send(IEnumerable messages); - } -} diff --git a/Castle.Core/Core/StringObjectDictionaryAdapter.cs b/Castle.Core/Core/StringObjectDictionaryAdapter.cs deleted file mode 100644 index 9cedaff..0000000 --- a/Castle.Core/Core/StringObjectDictionaryAdapter.cs +++ /dev/null @@ -1,227 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Core -{ - using System; - using System.Collections; - using System.Collections.Generic; - - public sealed class StringObjectDictionaryAdapter : IDictionary - { - private readonly IDictionary dictionary; - - public StringObjectDictionaryAdapter(IDictionary dictionary) - { - this.dictionary = dictionary; - } - - bool IDictionary.ContainsKey(string key) - { - return dictionary.Contains(key); - } - - void IDictionary.Add(string key, object value) - { - throw new NotImplementedException(); - } - - bool IDictionary.Remove(string key) - { - throw new NotImplementedException(); - } - - bool IDictionary.TryGetValue(string key, out object value) - { - value = null; - if (dictionary.Contains(key)) - { - value = dictionary[key]; - return true; - } - else - { - return false; - } - } - - object IDictionary.this[string key] - { - get { return dictionary[key]; } - set { throw new NotImplementedException(); } - } - - ICollection IDictionary.Keys - { - get - { - string[] keys = new string[Count]; - dictionary.Keys.CopyTo(keys, 0); - return keys; - } - } - - ICollection IDictionary.Values - { - get - { - object[] values = new object[Count]; - dictionary.Values.CopyTo(values, 0); - return values; - } - } - - void ICollection>.Add(KeyValuePair item) - { - throw new NotImplementedException(); - } - - bool ICollection>.Contains(KeyValuePair item) - { - throw new NotImplementedException(); - } - - void ICollection>.CopyTo(KeyValuePair[] array, int arrayIndex) - { - throw new NotImplementedException(); - } - - bool ICollection>.Remove(KeyValuePair item) - { - throw new NotImplementedException(); - } - - IEnumerator> IEnumerable>.GetEnumerator() - { - return new EnumeratorAdapter(this); - } - - public bool Contains(object key) - { - return dictionary.Contains(key); - } - - public void Add(object key, object value) - { - dictionary.Add(key, value); - } - - public void Clear() - { - dictionary.Clear(); - } - - public void Remove(object key) - { - dictionary.Remove(key); - } - - public object this[object key] - { - get { return dictionary[key]; } - set { dictionary[key] = value; } - } - - public ICollection Keys - { - get { return dictionary.Keys; } - } - - public ICollection Values - { - get { return dictionary.Values; } - } - - public bool IsReadOnly - { - get { return dictionary.IsReadOnly; } - } - - public bool IsFixedSize - { - get { return dictionary.IsFixedSize; } - } - - public void CopyTo(Array array, int index) - { - dictionary.CopyTo(array, index); - } - - public int Count - { - get { return dictionary.Count; } - } - - public object SyncRoot - { - get { return dictionary.SyncRoot; } - } - - public bool IsSynchronized - { - get { return dictionary.IsSynchronized; } - } - - public IEnumerator GetEnumerator() - { - return ((IEnumerable) dictionary).GetEnumerator(); - } - - internal class EnumeratorAdapter : IEnumerator> - { - private readonly StringObjectDictionaryAdapter adapter; - private IEnumerator keyEnumerator; - private string currentKey; - private object currentValue; - - public EnumeratorAdapter(StringObjectDictionaryAdapter adapter) - { - this.adapter = adapter; - keyEnumerator = ((IDictionary) adapter).Keys.GetEnumerator(); - } - - public bool MoveNext() - { - if (keyEnumerator.MoveNext()) - { - currentKey = keyEnumerator.Current; - currentValue = adapter[currentKey]; - return true; - } - - return false; - } - - public void Reset() - { - keyEnumerator.Reset(); - } - - public object Current - { - get { return new KeyValuePair(currentKey, currentValue); } - } - - KeyValuePair IEnumerator>.Current - { - get { return new KeyValuePair(currentKey, currentValue); } - } - - public void Dispose() - { - GC.SuppressFinalize(this); - } - } - } -} diff --git a/Castle.Core/DynamicProxy/AbstractInvocation.cs b/Castle.Core/DynamicProxy/AbstractInvocation.cs deleted file mode 100644 index 30197b8..0000000 --- a/Castle.Core/DynamicProxy/AbstractInvocation.cs +++ /dev/null @@ -1,211 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy -{ - using System; - using System.Diagnostics; - using System.Reflection; - - public abstract class AbstractInvocation : IInvocation - { - private readonly IInterceptor[] interceptors; - private readonly object[] arguments; - private int currentInterceptorIndex = -1; - private Type[] genericMethodArguments; - private readonly MethodInfo proxiedMethod; - protected readonly object proxyObject; - - protected AbstractInvocation( - object proxy, - IInterceptor[] interceptors, - MethodInfo proxiedMethod, - object[] arguments) - { - Debug.Assert(proxiedMethod != null); - proxyObject = proxy; - this.interceptors = interceptors; - this.proxiedMethod = proxiedMethod; - this.arguments = arguments; - } - - public void SetGenericMethodArguments(Type[] arguments) - { - genericMethodArguments = arguments; - } - - public abstract object InvocationTarget { get; } - - public abstract Type TargetType { get; } - - public abstract MethodInfo MethodInvocationTarget { get; } - - public Type[] GenericArguments - { - get { return genericMethodArguments; } - } - - public object Proxy - { - get { return proxyObject; } - } - - public MethodInfo Method - { - get { return proxiedMethod; } - } - - public MethodInfo GetConcreteMethod() - { - return EnsureClosedMethod(Method); - } - - public MethodInfo GetConcreteMethodInvocationTarget() - { - // it is ensured by the InvocationHelper that method will be closed - var method = MethodInvocationTarget; - Debug.Assert(method == null || method.IsGenericMethodDefinition == false, - "method == null || method.IsGenericMethodDefinition == false"); - return method; - } - - public object ReturnValue { get; set; } - - public object[] Arguments - { - get { return arguments; } - } - - public void SetArgumentValue(int index, object value) - { - arguments[index] = value; - } - - public object GetArgumentValue(int index) - { - return arguments[index]; - } - - public void Proceed() - { - if (interceptors == null) - // not yet fully initialized? probably, an intercepted method is called while we are being deserialized - { - InvokeMethodOnTarget(); - return; - } - - currentInterceptorIndex++; - try - { - if (currentInterceptorIndex == interceptors.Length) - { - InvokeMethodOnTarget(); - } - else if (currentInterceptorIndex > interceptors.Length) - { - throw new InvalidOperationException( - "Cannot proceed past the end of the interception pipeline. " + - "This likely signifies a bug in the calling code."); - } - else - { - interceptors[currentInterceptorIndex].Intercept(this); - } - } - finally - { - currentInterceptorIndex--; - } - } - - public IInvocationProceedInfo CaptureProceedInfo() - { - return new ProceedInfo(this); - } - - protected abstract void InvokeMethodOnTarget(); - - protected void ThrowOnNoTarget() - { - // let's try to build as friendly message as we can - string interceptorsMessage; - if (interceptors.Length == 0) - { - interceptorsMessage = "There are no interceptors specified"; - } - else - { - interceptorsMessage = "The interceptor attempted to 'Proceed'"; - } - - string methodKindIs; - string methodKindDescription; - if (Method.DeclaringType.IsClass && Method.IsAbstract) - { - methodKindIs = "is abstract"; - methodKindDescription = "an abstract method"; - } - else - { - methodKindIs = "has no target"; - methodKindDescription = "method without target"; - } - - var message = string.Format("This is a DynamicProxy2 error: {0} for method '{1}' which {2}. " + - "When calling {3} there is no implementation to 'proceed' to and " + - "it is the responsibility of the interceptor to mimic the implementation " + - "(set return value, out arguments etc)", - interceptorsMessage, Method, methodKindIs, methodKindDescription); - - throw new NotImplementedException(message); - } - - private MethodInfo EnsureClosedMethod(MethodInfo method) - { - if (method.ContainsGenericParameters) - { - Debug.Assert(genericMethodArguments != null); - return method.GetGenericMethodDefinition().MakeGenericMethod(genericMethodArguments); - } - return method; - } - - private sealed class ProceedInfo : IInvocationProceedInfo - { - private readonly AbstractInvocation invocation; - private readonly int interceptorIndex; - - public ProceedInfo(AbstractInvocation invocation) - { - this.invocation = invocation; - this.interceptorIndex = invocation.currentInterceptorIndex; - } - - public void Invoke() - { - var previousInterceptorIndex = invocation.currentInterceptorIndex; - try - { - invocation.currentInterceptorIndex = interceptorIndex; - invocation.Proceed(); - } - finally - { - invocation.currentInterceptorIndex = previousInterceptorIndex; - } - } - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/AllMethodsHook.cs b/Castle.Core/DynamicProxy/AllMethodsHook.cs deleted file mode 100644 index 9424c14..0000000 --- a/Castle.Core/DynamicProxy/AllMethodsHook.cs +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy -{ - using System; - using System.Collections.Generic; - using System.Reflection; - -#if FEATURE_SERIALIZATION - [Serializable] -#endif - public class AllMethodsHook : IProxyGenerationHook - { - protected static readonly ICollection SkippedTypes = new[] - { - typeof(object), - typeof(MarshalByRefObject), - typeof(ContextBoundObject) - }; - - public virtual bool ShouldInterceptMethod(Type type, MethodInfo methodInfo) - { - return SkippedTypes.Contains(methodInfo.DeclaringType) == false; - } - - public virtual void NonProxyableMemberNotification(Type type, MemberInfo memberInfo) - { - } - - public virtual void MethodsInspected() - { - } - - public override bool Equals(object obj) - { - return obj != null && obj.GetType() == GetType(); - } - - public override int GetHashCode() - { - return GetType().GetHashCode(); - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Contributors/ClassMembersCollector.cs b/Castle.Core/DynamicProxy/Contributors/ClassMembersCollector.cs deleted file mode 100644 index 1200cda..0000000 --- a/Castle.Core/DynamicProxy/Contributors/ClassMembersCollector.cs +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Contributors -{ - using System; - using System.Reflection; - - using Castle.DynamicProxy.Generators; - - internal class ClassMembersCollector : MembersCollector - { - public ClassMembersCollector(Type targetType) - : base(targetType) - { - } - - protected override MetaMethod GetMethodToGenerate(MethodInfo method, IProxyGenerationHook hook, bool isStandalone) - { - if (ProxyUtil.IsAccessibleMethod(method) == false) - { - return null; - } - - var accepted = AcceptMethod(method, true, hook); - if (!accepted && !method.IsAbstract) - { - //we don't need to do anything... - return null; - } - - return new MetaMethod(method, method, isStandalone, accepted, !method.IsAbstract); - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Contributors/ClassProxySerializableContributor.cs b/Castle.Core/DynamicProxy/Contributors/ClassProxySerializableContributor.cs deleted file mode 100644 index 44d04a4..0000000 --- a/Castle.Core/DynamicProxy/Contributors/ClassProxySerializableContributor.cs +++ /dev/null @@ -1,247 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#if FEATURE_SERIALIZATION - -namespace Castle.DynamicProxy.Contributors -{ - using System; - using System.Collections.Generic; - using System.Diagnostics; - using System.Linq; - using System.Reflection; - using System.Runtime.Serialization; - - using Castle.DynamicProxy.Generators; - using Castle.DynamicProxy.Generators.Emitters; - using Castle.DynamicProxy.Generators.Emitters.SimpleAST; - using Castle.DynamicProxy.Internal; - using Castle.DynamicProxy.Tokens; - - internal class ClassProxySerializableContributor : SerializableContributor - { - private bool delegateToBaseGetObjectData; - private ConstructorInfo serializationConstructor; - private readonly IList serializedFields = new List(); - - public ClassProxySerializableContributor(Type targetType, Type[] interfaces, string typeId) - : base(targetType, interfaces, typeId) - { - Debug.Assert(targetType.IsSerializable, "This contributor is intended for serializable types only."); - } - - public override void CollectElementsToProxy(IProxyGenerationHook hook, MetaType model) - { - delegateToBaseGetObjectData = VerifyIfBaseImplementsGetObjectData(targetType, model, out var getObjectData); - - // This contributor is going to add a `GetObjectData` method to the proxy type. - // If a method with the same name and signature exists in the proxied class type, - // and another contributor has decided to proxy it, we need to tell it not to. - // Otherwise, we'll end up with two implementations! - - if (getObjectData == null) - { - // `VerifyIfBaseImplementsGetObjectData` only searches for `GetObjectData` - // in the implementation map for `ISerializable`. In the best case, it was - // already found there. If not, we need to look again, since *any* method - // with the same signature is a problem. - - var getObjectDataMethod = targetType.GetMethod( - "GetObjectData", - BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, - null, - new[] { typeof(SerializationInfo), typeof(StreamingContext) }, - null); - - if (getObjectDataMethod != null) - { - getObjectData = model.FindMethod(getObjectDataMethod); - } - } - - if (getObjectData != null && getObjectData.Proxyable) - { - getObjectData.Ignore = true; - } - } - - public override void Generate(ClassEmitter @class) - { - ImplementGetObjectData(@class); - Constructor(@class); - } - - protected override void AddAddValueInvocation(ArgumentReference serializationInfo, MethodEmitter getObjectData, - FieldReference field) - { - serializedFields.Add(field); - base.AddAddValueInvocation(serializationInfo, getObjectData, field); - } - - protected override void CustomizeGetObjectData(CodeBuilder codebuilder, ArgumentReference serializationInfo, - ArgumentReference streamingContext, ClassEmitter emitter) - { - codebuilder.AddStatement( - new MethodInvocationExpression( - serializationInfo, - SerializationInfoMethods.AddValue_Bool, - new LiteralStringExpression("__delegateToBase"), - new LiteralBoolExpression(delegateToBaseGetObjectData))); - - if (delegateToBaseGetObjectData == false) - { - EmitCustomGetObjectData(codebuilder, serializationInfo); - return; - } - - EmitCallToBaseGetObjectData(codebuilder, serializationInfo, streamingContext); - } - - private void EmitCustomGetObjectData(CodeBuilder codebuilder, ArgumentReference serializationInfo) - { - var members = codebuilder.DeclareLocal(typeof(MemberInfo[])); - var data = codebuilder.DeclareLocal(typeof(object[])); - - var getSerializableMembers = new MethodInvocationExpression( - null, - FormatterServicesMethods.GetSerializableMembers, - new TypeTokenExpression(targetType)); - codebuilder.AddStatement(new AssignStatement(members, getSerializableMembers)); - - // Sort to keep order on both serialize and deserialize side the same, c.f DYNPROXY-ISSUE-127 - var callSort = new MethodInvocationExpression( - null, - TypeUtilMethods.Sort, - members); - codebuilder.AddStatement(new AssignStatement(members, callSort)); - - var getObjectData = new MethodInvocationExpression( - null, - FormatterServicesMethods.GetObjectData, - SelfReference.Self, - members); - codebuilder.AddStatement(new AssignStatement(data, getObjectData)); - - var addValue = new MethodInvocationExpression( - serializationInfo, - SerializationInfoMethods.AddValue_Object, - new LiteralStringExpression("__data"), - data); - codebuilder.AddStatement(addValue); - } - - private void EmitCallToBaseGetObjectData(CodeBuilder codebuilder, ArgumentReference serializationInfo, - ArgumentReference streamingContext) - { - var baseGetObjectData = targetType.GetMethod("GetObjectData", - new[] { typeof(SerializationInfo), typeof(StreamingContext) }); - - codebuilder.AddStatement( - new MethodInvocationExpression( - baseGetObjectData, - serializationInfo, - streamingContext)); - } - - private void Constructor(ClassEmitter emitter) - { - if (!delegateToBaseGetObjectData) - { - return; - } - GenerateSerializationConstructor(emitter); - } - - private void GenerateSerializationConstructor(ClassEmitter emitter) - { - var serializationInfo = new ArgumentReference(typeof(SerializationInfo)); - var streamingContext = new ArgumentReference(typeof(StreamingContext)); - - var ctor = emitter.CreateConstructor(serializationInfo, streamingContext); - - ctor.CodeBuilder.AddStatement( - new ConstructorInvocationStatement(serializationConstructor, - serializationInfo, - streamingContext)); - - foreach (var field in serializedFields) - { - var getValue = new MethodInvocationExpression(serializationInfo, - SerializationInfoMethods.GetValue, - new LiteralStringExpression(field.Reference.Name), - new TypeTokenExpression(field.Reference.FieldType)); - ctor.CodeBuilder.AddStatement(new AssignStatement( - field, - new ConvertExpression(field.Reference.FieldType, - typeof(object), - getValue))); - } - ctor.CodeBuilder.AddStatement(new ReturnStatement()); - } - - private bool VerifyIfBaseImplementsGetObjectData(Type baseType, MetaType model, out MetaMethod getObjectData) - { - getObjectData = null; - - if (!typeof(ISerializable).IsAssignableFrom(baseType)) - { - return false; - } - - if (baseType.IsDelegateType()) - { - //working around bug in CLR which returns true for "does this type implement ISerializable" for delegates - return false; - } - - // If base type implements ISerializable, we have to make sure - // the GetObjectData is marked as virtual - var getObjectDataMethod = baseType.GetInterfaceMap(typeof(ISerializable)).TargetMethods[0]; - if (getObjectDataMethod.IsPrivate) //explicit interface implementation - { - return false; - } - - if (!getObjectDataMethod.IsVirtual || getObjectDataMethod.IsFinal) - { - var message = string.Format("The type {0} implements ISerializable, but GetObjectData is not marked as virtual. " + - "Dynamic Proxy needs types implementing ISerializable to mark GetObjectData as virtual " + - "to ensure correct serialization process.", - baseType.FullName); - throw new ArgumentException(message); - } - - getObjectData = model.FindMethod(getObjectDataMethod); - - serializationConstructor = baseType.GetConstructor( - BindingFlags.Instance | BindingFlags.Public | - BindingFlags.NonPublic, - null, - new[] { typeof(SerializationInfo), typeof(StreamingContext) }, - null); - - if (serializationConstructor == null) - { - var message = string.Format("The type {0} implements ISerializable, " + - "but failed to provide a deserialization constructor", - baseType.FullName); - throw new ArgumentException(message); - } - - return true; - } - } -} - -#endif diff --git a/Castle.Core/DynamicProxy/Contributors/ClassProxyTargetContributor.cs b/Castle.Core/DynamicProxy/Contributors/ClassProxyTargetContributor.cs deleted file mode 100644 index 6b72d99..0000000 --- a/Castle.Core/DynamicProxy/Contributors/ClassProxyTargetContributor.cs +++ /dev/null @@ -1,180 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Contributors -{ - using System; - using System.Collections.Generic; - using System.Diagnostics; - using System.Linq; - using System.Reflection; - using System.Reflection.Emit; - - using Castle.DynamicProxy.Generators; - using Castle.DynamicProxy.Generators.Emitters; - using Castle.DynamicProxy.Generators.Emitters.SimpleAST; - using Castle.DynamicProxy.Internal; - using Castle.DynamicProxy.Tokens; - - internal class ClassProxyTargetContributor : CompositeTypeContributor - { - private readonly Type targetType; - - public ClassProxyTargetContributor(Type targetType, INamingScope namingScope) - : base(namingScope) - { - this.targetType = targetType; - } - - protected override IEnumerable GetCollectors() - { - var targetItem = new ClassMembersCollector(targetType) { Logger = Logger }; - yield return targetItem; - - foreach (var @interface in interfaces) - { - var item = new InterfaceMembersOnClassCollector(@interface, true, - targetType.GetInterfaceMap(@interface)) { Logger = Logger }; - yield return item; - } - } - - protected override MethodGenerator GetMethodGenerator(MetaMethod method, ClassEmitter @class, - OverrideMethodDelegate overrideMethod) - { - if (method.Ignore) - { - return null; - } - - if (!method.Proxyable) - { - return new MinimialisticMethodGenerator(method, - overrideMethod); - } - - if (ExplicitlyImplementedInterfaceMethod(method)) - { - return ExplicitlyImplementedInterfaceMethodGenerator(method, @class, overrideMethod); - } - - var invocation = GetInvocationType(method, @class); - - GetTargetExpressionDelegate getTargetTypeExpression = (c, m) => new TypeTokenExpression(targetType); - - return new MethodWithInvocationGenerator(method, - @class.GetField("__interceptors"), - invocation, - getTargetTypeExpression, - getTargetTypeExpression, - overrideMethod, - null); - } - - private Type BuildInvocationType(MetaMethod method, ClassEmitter @class) - { - var methodInfo = method.Method; - if (!method.HasTarget) - { - return new InheritanceInvocationTypeGenerator(targetType, - method, - null, null) - .Generate(@class, namingScope) - .BuildType(); - } - var callback = CreateCallbackMethod(@class, methodInfo, method.MethodOnTarget); - return new InheritanceInvocationTypeGenerator(callback.DeclaringType, - method, - callback, null) - .Generate(@class, namingScope) - .BuildType(); - } - - private MethodBuilder CreateCallbackMethod(ClassEmitter emitter, MethodInfo methodInfo, MethodInfo methodOnTarget) - { - var targetMethod = methodOnTarget ?? methodInfo; - var callBackMethod = emitter.CreateMethod(namingScope.GetUniqueName(methodInfo.Name + "_callback"), targetMethod); - - if (targetMethod.IsGenericMethod) - { - targetMethod = targetMethod.MakeGenericMethod(callBackMethod.GenericTypeParams.AsTypeArray()); - } - - // invocation on base class - - callBackMethod.CodeBuilder.AddStatement( - new ReturnStatement( - new MethodInvocationExpression(SelfReference.Self, - targetMethod, - callBackMethod.Arguments))); - - return callBackMethod.MethodBuilder; - } - - private bool ExplicitlyImplementedInterfaceMethod(MetaMethod method) - { - return method.MethodOnTarget.IsPrivate; - } - - private MethodGenerator ExplicitlyImplementedInterfaceMethodGenerator(MetaMethod method, ClassEmitter @class, - OverrideMethodDelegate overrideMethod) - { - var @delegate = GetDelegateType(method, @class); - var contributor = GetContributor(@delegate, method); - var invocation = new InheritanceInvocationTypeGenerator(targetType, method, null, contributor) - .Generate(@class, namingScope) - .BuildType(); - return new MethodWithInvocationGenerator(method, - @class.GetField("__interceptors"), - invocation, - (c, m) => new TypeTokenExpression(targetType), - overrideMethod, - contributor); - } - - private IInvocationCreationContributor GetContributor(Type @delegate, MetaMethod method) - { - if (@delegate.IsGenericType == false) - { - return new InvocationWithDelegateContributor(@delegate, targetType, method, namingScope); - } - return new InvocationWithGenericDelegateContributor(@delegate, - method, - new FieldReference(InvocationMethods.ProxyObject)); - } - - private Type GetDelegateType(MetaMethod method, ClassEmitter @class) - { - var scope = @class.ModuleScope; - var key = new CacheKey( - typeof(Delegate), - targetType, - new[] { method.MethodOnTarget.ReturnType } - .Concat(ArgumentsUtil.GetTypes(method.MethodOnTarget.GetParameters())). - ToArray(), - null); - - return scope.TypeCache.GetOrAddWithoutTakingLock(key, _ => - new DelegateTypeGenerator(method, targetType) - .Generate(@class, namingScope) - .BuildType()); - } - - private Type GetInvocationType(MetaMethod method, ClassEmitter @class) - { - // NOTE: No caching since invocation is tied to this specific proxy type via its invocation method - return BuildInvocationType(method, @class); - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Contributors/ClassProxyWithTargetTargetContributor.cs b/Castle.Core/DynamicProxy/Contributors/ClassProxyWithTargetTargetContributor.cs deleted file mode 100644 index 3b709b1..0000000 --- a/Castle.Core/DynamicProxy/Contributors/ClassProxyWithTargetTargetContributor.cs +++ /dev/null @@ -1,180 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Contributors -{ - using System; - using System.Collections.Generic; - using System.Diagnostics; - using System.Linq; - using System.Reflection; - - using Castle.DynamicProxy.Generators; - using Castle.DynamicProxy.Generators.Emitters; - using Castle.DynamicProxy.Generators.Emitters.SimpleAST; - using Castle.DynamicProxy.Tokens; - - internal class ClassProxyWithTargetTargetContributor : CompositeTypeContributor - { - private readonly Type targetType; - - public ClassProxyWithTargetTargetContributor(Type targetType, INamingScope namingScope) - : base(namingScope) - { - this.targetType = targetType; - } - - protected override IEnumerable GetCollectors() - { - var targetItem = new WrappedClassMembersCollector(targetType) { Logger = Logger }; - yield return targetItem; - - foreach (var @interface in interfaces) - { - var item = new InterfaceMembersOnClassCollector(@interface, true, - targetType.GetInterfaceMap(@interface)) { Logger = Logger }; - yield return item; - } - } - - protected override MethodGenerator GetMethodGenerator(MetaMethod method, ClassEmitter @class, - OverrideMethodDelegate overrideMethod) - { - if (method.Ignore) - { - return null; - } - - var methodIsDirectlyAccessible = IsDirectlyAccessible(method); - - if (!method.Proxyable) - { - if (methodIsDirectlyAccessible) - { - return new ForwardingMethodGenerator(method, overrideMethod, (c, m) => c.GetField("__target")); - } - else - { - return IndirectlyCalledMethodGenerator(method, @class, overrideMethod, skipInterceptors: true); - } - } - - if (!methodIsDirectlyAccessible) - { - return IndirectlyCalledMethodGenerator(method, @class, overrideMethod); - } - - var invocation = GetInvocationType(method, @class); - - return new MethodWithInvocationGenerator(method, - @class.GetField("__interceptors"), - invocation, - (c, m) => c.GetField("__target"), - overrideMethod, - null); - } - - private Type BuildInvocationType(MetaMethod method, ClassEmitter @class) - { - if (!method.HasTarget) - { - return new InheritanceInvocationTypeGenerator(targetType, - method, - null, null) - .Generate(@class, namingScope) - .BuildType(); - } - return new CompositionInvocationTypeGenerator(method.Method.DeclaringType, - method, - method.Method, - false, - null) - .Generate(@class, namingScope) - .BuildType(); - } - - private IInvocationCreationContributor GetContributor(Type @delegate, MetaMethod method) - { - if (@delegate.IsGenericType == false) - { - return new InvocationWithDelegateContributor(@delegate, targetType, method, namingScope); - } - return new InvocationWithGenericDelegateContributor(@delegate, - method, - new FieldReference(InvocationMethods.CompositionInvocationTarget)); - } - - private Type GetDelegateType(MetaMethod method, ClassEmitter @class) - { - var scope = @class.ModuleScope; - var key = new CacheKey( - typeof(Delegate), - targetType, - new[] { method.MethodOnTarget.ReturnType } - .Concat(ArgumentsUtil.GetTypes(method.MethodOnTarget.GetParameters())). - ToArray(), - null); - - return scope.TypeCache.GetOrAddWithoutTakingLock(key, _ => - new DelegateTypeGenerator(method, targetType) - .Generate(@class, namingScope) - .BuildType()); - } - - private Type GetInvocationType(MetaMethod method, ClassEmitter @class) - { - var scope = @class.ModuleScope; - var invocationInterfaces = new[] { typeof(IInvocation) }; - - var key = new CacheKey(method.Method, CompositionInvocationTypeGenerator.BaseType, invocationInterfaces, null); - - // no locking required as we're already within a lock - - return scope.TypeCache.GetOrAddWithoutTakingLock(key, _ => BuildInvocationType(method, @class)); - } - - private MethodGenerator IndirectlyCalledMethodGenerator(MetaMethod method, ClassEmitter proxy, - OverrideMethodDelegate overrideMethod, - bool skipInterceptors = false) - { - var @delegate = GetDelegateType(method, proxy); - var contributor = GetContributor(@delegate, method); - var invocation = new CompositionInvocationTypeGenerator(targetType, method, null, false, contributor) - .Generate(proxy, namingScope) - .BuildType(); - - IExpression expression; - if (skipInterceptors) - { - expression = NullExpression.Instance; - } - else - { - expression = proxy.GetField("__interceptors"); - } - - return new MethodWithInvocationGenerator(method, - expression, - invocation, - (c, m) => c.GetField("__target"), - overrideMethod, - contributor); - } - - private bool IsDirectlyAccessible(MetaMethod method) - { - return method.MethodOnTarget.IsPublic; - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Contributors/CompositeTypeContributor.cs b/Castle.Core/DynamicProxy/Contributors/CompositeTypeContributor.cs deleted file mode 100644 index fc34dff..0000000 --- a/Castle.Core/DynamicProxy/Contributors/CompositeTypeContributor.cs +++ /dev/null @@ -1,184 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Contributors -{ - using System; - using System.Collections.Generic; - using System.Diagnostics; - using System.Reflection; - - using Castle.Core.Logging; - using Castle.DynamicProxy.Generators; - using Castle.DynamicProxy.Generators.Emitters; - using Castle.DynamicProxy.Internal; - - internal abstract class CompositeTypeContributor : ITypeContributor - { - protected readonly INamingScope namingScope; - - protected readonly ICollection interfaces = new HashSet(); - - private ILogger logger = NullLogger.Instance; - private readonly List properties = new List(); - private readonly List events = new List(); - private readonly List methods = new List(); - - protected CompositeTypeContributor(INamingScope namingScope) - { - this.namingScope = namingScope; - } - - public ILogger Logger - { - get { return logger; } - set { logger = value; } - } - - public void CollectElementsToProxy(IProxyGenerationHook hook, MetaType model) - { - Debug.Assert(hook != null); - Debug.Assert(model != null); - - var sink = new MembersCollectorSink(model, this); - - foreach (var collector in GetCollectors()) - { - collector.CollectMembersToProxy(hook, sink); - } - } - - protected abstract IEnumerable GetCollectors(); - - public virtual void Generate(ClassEmitter @class) - { - foreach (var method in methods) - { - if (!method.Standalone) - { - continue; - } - - ImplementMethod(method, - @class, - @class.CreateMethod); - } - - foreach (var property in properties) - { - ImplementProperty(@class, property); - } - - foreach (var @event in events) - { - ImplementEvent(@class, @event); - } - } - - public void AddInterfaceToProxy(Type @interface) - { - Debug.Assert(@interface != null, "@interface == null", "Shouldn't be adding empty interfaces..."); - Debug.Assert(@interface.IsInterface || @interface.IsDelegateType(), "@interface.IsInterface || @interface.IsDelegateType()", "Should be adding interfaces or delegate types only..."); - Debug.Assert(!interfaces.Contains(@interface), "!interfaces.ContainsKey(@interface)", - "Shouldn't be adding same interface twice..."); - - interfaces.Add(@interface); - } - - private void ImplementEvent(ClassEmitter emitter, MetaEvent @event) - { - @event.BuildEventEmitter(emitter); - ImplementMethod(@event.Adder, emitter, @event.Emitter.CreateAddMethod); - ImplementMethod(@event.Remover, emitter, @event.Emitter.CreateRemoveMethod); - } - - private void ImplementProperty(ClassEmitter emitter, MetaProperty property) - { - property.BuildPropertyEmitter(emitter); - if (property.CanRead) - { - ImplementMethod(property.Getter, emitter, property.Emitter.CreateGetMethod); - } - - if (property.CanWrite) - { - ImplementMethod(property.Setter, emitter, property.Emitter.CreateSetMethod); - } - } - - protected abstract MethodGenerator GetMethodGenerator(MetaMethod method, ClassEmitter @class, - OverrideMethodDelegate overrideMethod); - - private void ImplementMethod(MetaMethod method, ClassEmitter @class, - OverrideMethodDelegate overrideMethod) - { - { - var generator = GetMethodGenerator(method, @class, overrideMethod); - if (generator == null) - { - return; - } - var proxyMethod = generator.Generate(@class, namingScope); - foreach (var attribute in method.Method.GetNonInheritableAttributes()) - { - proxyMethod.DefineCustomAttribute(attribute.Builder); - } - } - } - - private sealed class MembersCollectorSink : IMembersCollectorSink - { - private readonly MetaType model; - private readonly CompositeTypeContributor contributor; - - public MembersCollectorSink(MetaType model, CompositeTypeContributor contributor) - { - this.model = model; - this.contributor = contributor; - } - - // You may have noticed that most contributors do not query `MetaType` at all, - // but only their own collections. So perhaps you are wondering why collected - // type elements are added to `model` at all, and not just to `contributor`? - // - // TL;DR: This prevents member name collisions in the generated proxy type. - // - // `MetaType` uses `MetaTypeElementCollection`s internally, which switches members - // to explicit implementation whenever a name collision with a previously added - // member occurs. - // - // It would be pointless to do this at the level of the individual contributor, - // because name collisions could still occur across several contributors. This - // is why they all share the same `MetaType` instance. - - public void Add(MetaEvent @event) - { - model.AddEvent(@event); - contributor.events.Add(@event); - } - - public void Add(MetaMethod method) - { - model.AddMethod(method); - contributor.methods.Add(method); - } - - public void Add(MetaProperty property) - { - model.AddProperty(property); - contributor.properties.Add(property); - } - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Contributors/DelegateTypeMembersCollector.cs b/Castle.Core/DynamicProxy/Contributors/DelegateTypeMembersCollector.cs deleted file mode 100644 index d3f7970..0000000 --- a/Castle.Core/DynamicProxy/Contributors/DelegateTypeMembersCollector.cs +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Contributors -{ - using System; - using System.Reflection; - - using Castle.DynamicProxy.Generators; - using Castle.DynamicProxy.Internal; - - internal sealed class DelegateTypeMembersCollector : MembersCollector - { - public DelegateTypeMembersCollector(Type delegateType) - : base(delegateType) - { - } - - protected override MetaMethod GetMethodToGenerate(MethodInfo method, IProxyGenerationHook hook, bool isStandalone) - { - if (method.Name == "Invoke" && method.DeclaringType.IsDelegateType()) - { - return new MetaMethod(method, method, isStandalone, true, false); - } - else - { - return null; - } - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Contributors/Delegates.cs b/Castle.Core/DynamicProxy/Contributors/Delegates.cs deleted file mode 100644 index 60a64d6..0000000 --- a/Castle.Core/DynamicProxy/Contributors/Delegates.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Contributors -{ - using System.Reflection; - - using Castle.DynamicProxy.Generators.Emitters; - using Castle.DynamicProxy.Generators.Emitters.SimpleAST; - - internal delegate MethodEmitter OverrideMethodDelegate( - string name, MethodAttributes attributes, MethodInfo methodToOverride); - - internal delegate IExpression GetTargetExpressionDelegate(ClassEmitter @class, MethodInfo method); - - internal delegate Reference GetTargetReferenceDelegate(ClassEmitter @class, MethodInfo method); -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Contributors/FieldReferenceComparer.cs b/Castle.Core/DynamicProxy/Contributors/FieldReferenceComparer.cs deleted file mode 100644 index 1a658b4..0000000 --- a/Castle.Core/DynamicProxy/Contributors/FieldReferenceComparer.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Contributors -{ - using System; - using System.Collections.Generic; - - internal class FieldReferenceComparer : IComparer - { - public int Compare(Type x, Type y) - { - if (x == null) - { - throw new ArgumentNullException(nameof(x)); - } - - if (y == null) - { - throw new ArgumentNullException(nameof(y)); - } - - return string.CompareOrdinal(x.FullName, y.FullName); - } - } -} diff --git a/Castle.Core/DynamicProxy/Contributors/IInvocationCreationContributor.cs b/Castle.Core/DynamicProxy/Contributors/IInvocationCreationContributor.cs deleted file mode 100644 index 87b94f8..0000000 --- a/Castle.Core/DynamicProxy/Contributors/IInvocationCreationContributor.cs +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Contributors -{ - using System.Reflection; - - using Castle.DynamicProxy.Generators.Emitters; - using Castle.DynamicProxy.Generators.Emitters.SimpleAST; - - internal interface IInvocationCreationContributor - { - ConstructorEmitter CreateConstructor(ArgumentReference[] baseCtorArguments, AbstractTypeEmitter invocation); - - MethodInfo GetCallbackMethod(); - - MethodInvocationExpression GetCallbackMethodInvocation(AbstractTypeEmitter invocation, IExpression[] args, - Reference targetField, MethodEmitter invokeMethodOnTarget); - - IExpression[] GetConstructorInvocationArguments(IExpression[] arguments, ClassEmitter proxy); - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Contributors/IMembersCollectorSink.cs b/Castle.Core/DynamicProxy/Contributors/IMembersCollectorSink.cs deleted file mode 100644 index 0afd234..0000000 --- a/Castle.Core/DynamicProxy/Contributors/IMembersCollectorSink.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Contributors -{ - using Castle.DynamicProxy.Generators; - - internal interface IMembersCollectorSink - { - void Add(MetaEvent @event); - void Add(MetaMethod method); - void Add(MetaProperty property); - } -} diff --git a/Castle.Core/DynamicProxy/Contributors/ITypeContributor.cs b/Castle.Core/DynamicProxy/Contributors/ITypeContributor.cs deleted file mode 100644 index 64ab060..0000000 --- a/Castle.Core/DynamicProxy/Contributors/ITypeContributor.cs +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Contributors -{ - using Castle.DynamicProxy.Generators; - using Castle.DynamicProxy.Generators.Emitters; - - /// - /// Interface describing elements composing generated type - /// - internal interface ITypeContributor - { - void CollectElementsToProxy(IProxyGenerationHook hook, MetaType model); - - void Generate(ClassEmitter @class); - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Contributors/InterfaceMembersCollector.cs b/Castle.Core/DynamicProxy/Contributors/InterfaceMembersCollector.cs deleted file mode 100644 index bb0fdc8..0000000 --- a/Castle.Core/DynamicProxy/Contributors/InterfaceMembersCollector.cs +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Contributors -{ - using System; - using System.Reflection; - - using Castle.DynamicProxy.Generators; - - internal class InterfaceMembersCollector : MembersCollector - { - public InterfaceMembersCollector(Type @interface) - : base(@interface) - { - } - - protected override MetaMethod GetMethodToGenerate(MethodInfo method, IProxyGenerationHook hook, bool isStandalone) - { - if (ProxyUtil.IsAccessibleMethod(method) == false) - { - return null; - } - - var proxyable = AcceptMethod(method, false, hook); - return new MetaMethod(method, method, isStandalone, proxyable, false); - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Contributors/InterfaceMembersOnClassCollector.cs b/Castle.Core/DynamicProxy/Contributors/InterfaceMembersOnClassCollector.cs deleted file mode 100644 index 3e643cf..0000000 --- a/Castle.Core/DynamicProxy/Contributors/InterfaceMembersOnClassCollector.cs +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Contributors -{ - using System; - using System.Reflection; - - using Castle.DynamicProxy.Generators; - - internal class InterfaceMembersOnClassCollector : MembersCollector - { - private readonly InterfaceMapping map; - private readonly bool onlyProxyVirtual; - - public InterfaceMembersOnClassCollector(Type type, bool onlyProxyVirtual, InterfaceMapping map) : base(type) - { - this.onlyProxyVirtual = onlyProxyVirtual; - this.map = map; - } - - protected override MetaMethod GetMethodToGenerate(MethodInfo method, IProxyGenerationHook hook, bool isStandalone) - { - if (ProxyUtil.IsAccessibleMethod(method) == false) - { - return null; - } - - if (onlyProxyVirtual && IsVirtuallyImplementedInterfaceMethod(method)) - { - return null; - } - - var methodOnTarget = GetMethodOnTarget(method); - - var proxyable = AcceptMethod(method, onlyProxyVirtual, hook); - return new MetaMethod(method, methodOnTarget, isStandalone, proxyable, methodOnTarget.IsPrivate == false); - } - - private MethodInfo GetMethodOnTarget(MethodInfo method) - { - var index = Array.IndexOf(map.InterfaceMethods, method); - if (index == -1) - { - return null; - } - - return map.TargetMethods[index]; - } - - private bool IsVirtuallyImplementedInterfaceMethod(MethodInfo method) - { - var info = GetMethodOnTarget(method); - return info != null && info.IsFinal == false; - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Contributors/InterfaceProxySerializableContributor.cs b/Castle.Core/DynamicProxy/Contributors/InterfaceProxySerializableContributor.cs deleted file mode 100644 index 2d30dbc..0000000 --- a/Castle.Core/DynamicProxy/Contributors/InterfaceProxySerializableContributor.cs +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#if FEATURE_SERIALIZATION - -namespace Castle.DynamicProxy.Contributors -{ - using System; - - using Castle.DynamicProxy.Generators.Emitters; - using Castle.DynamicProxy.Generators.Emitters.SimpleAST; - using Castle.DynamicProxy.Tokens; - - internal class InterfaceProxySerializableContributor : SerializableContributor - { - public InterfaceProxySerializableContributor(Type targetType, string proxyGeneratorId, Type[] interfaces) - : base(targetType, interfaces, proxyGeneratorId) - { - } - - protected override void CustomizeGetObjectData(CodeBuilder codebuilder, ArgumentReference serializationInfo, - ArgumentReference streamingContext, ClassEmitter emitter) - { - var targetField = emitter.GetField("__target"); - - codebuilder.AddStatement( - new MethodInvocationExpression( - serializationInfo, - SerializationInfoMethods.AddValue_Object, - new LiteralStringExpression("__targetFieldType"), - new LiteralStringExpression(targetField.Reference.FieldType.AssemblyQualifiedName))); - - codebuilder.AddStatement( - new MethodInvocationExpression( - serializationInfo, - SerializationInfoMethods.AddValue_Object, - new LiteralStringExpression("__theInterface"), - new LiteralStringExpression(targetType.AssemblyQualifiedName))); - } - } -} - -#endif diff --git a/Castle.Core/DynamicProxy/Contributors/InterfaceProxyTargetContributor.cs b/Castle.Core/DynamicProxy/Contributors/InterfaceProxyTargetContributor.cs deleted file mode 100644 index deb0cde..0000000 --- a/Castle.Core/DynamicProxy/Contributors/InterfaceProxyTargetContributor.cs +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Contributors -{ - using System; - using System.Collections.Generic; - using System.Diagnostics; - using System.Reflection; - - using Castle.DynamicProxy.Generators; - using Castle.DynamicProxy.Generators.Emitters; - - internal class InterfaceProxyTargetContributor : CompositeTypeContributor - { - private readonly bool canChangeTarget; - private readonly Type proxyTargetType; - - public InterfaceProxyTargetContributor(Type proxyTargetType, bool canChangeTarget, INamingScope namingScope) - : base(namingScope) - { - this.proxyTargetType = proxyTargetType; - this.canChangeTarget = canChangeTarget; - } - - protected override IEnumerable GetCollectors() - { - foreach (var @interface in interfaces) - { - var item = GetCollectorForInterface(@interface); - item.Logger = Logger; - yield return item; - } - } - - protected virtual MembersCollector GetCollectorForInterface(Type @interface) - { - return new InterfaceMembersOnClassCollector(@interface, false, - proxyTargetType.GetInterfaceMap(@interface)); - } - - protected override MethodGenerator GetMethodGenerator(MetaMethod method, ClassEmitter @class, - OverrideMethodDelegate overrideMethod) - { - if (!method.Proxyable) - { - return new ForwardingMethodGenerator(method, - overrideMethod, - (c, m) => c.GetField("__target")); - } - - var invocation = GetInvocationType(method, @class); - - return new MethodWithInvocationGenerator(method, - @class.GetField("__interceptors"), - invocation, - (c, m) => c.GetField("__target"), - overrideMethod, - null); - } - - private Type GetInvocationType(MetaMethod method, ClassEmitter @class) - { - var scope = @class.ModuleScope; - - Type[] invocationInterfaces; - if (canChangeTarget) - { - invocationInterfaces = new[] { typeof(IInvocation), typeof(IChangeProxyTarget) }; - } - else - { - invocationInterfaces = new[] { typeof(IInvocation) }; - } - - var key = new CacheKey(method.Method, CompositionInvocationTypeGenerator.BaseType, invocationInterfaces, null); - - // no locking required as we're already within a lock - - return scope.TypeCache.GetOrAddWithoutTakingLock(key, _ => - new CompositionInvocationTypeGenerator(method.Method.DeclaringType, - method, - method.Method, - canChangeTarget, - null) - .Generate(@class, namingScope) - .BuildType()); - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Contributors/InterfaceProxyWithOptionalTargetContributor.cs b/Castle.Core/DynamicProxy/Contributors/InterfaceProxyWithOptionalTargetContributor.cs deleted file mode 100644 index 858a6fb..0000000 --- a/Castle.Core/DynamicProxy/Contributors/InterfaceProxyWithOptionalTargetContributor.cs +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Contributors -{ - using Castle.DynamicProxy.Generators; - using Castle.DynamicProxy.Generators.Emitters; - - internal class InterfaceProxyWithOptionalTargetContributor : InterfaceProxyWithoutTargetContributor - { - private readonly GetTargetReferenceDelegate getTargetReference; - - public InterfaceProxyWithOptionalTargetContributor(INamingScope namingScope, GetTargetExpressionDelegate getTarget, - GetTargetReferenceDelegate getTargetReference) - : base(namingScope, getTarget) - { - this.getTargetReference = getTargetReference; - canChangeTarget = true; - } - - protected override MethodGenerator GetMethodGenerator(MetaMethod method, ClassEmitter @class, - OverrideMethodDelegate overrideMethod) - { - if (!method.Proxyable) - { - return new OptionallyForwardingMethodGenerator(method, overrideMethod, getTargetReference); - } - - return base.GetMethodGenerator(method, @class, overrideMethod); - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Contributors/InterfaceProxyWithTargetInterfaceTargetContributor.cs b/Castle.Core/DynamicProxy/Contributors/InterfaceProxyWithTargetInterfaceTargetContributor.cs deleted file mode 100644 index b1f4525..0000000 --- a/Castle.Core/DynamicProxy/Contributors/InterfaceProxyWithTargetInterfaceTargetContributor.cs +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Contributors -{ - using System; - - using Castle.DynamicProxy.Generators; - - internal class InterfaceProxyWithTargetInterfaceTargetContributor : InterfaceProxyTargetContributor - { - public InterfaceProxyWithTargetInterfaceTargetContributor(Type proxyTargetType, bool allowChangeTarget, - INamingScope namingScope) - : base(proxyTargetType, allowChangeTarget, namingScope) - { - } - - protected override MembersCollector GetCollectorForInterface(Type @interface) - { - return new InterfaceMembersCollector(@interface); - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Contributors/InterfaceProxyWithoutTargetContributor.cs b/Castle.Core/DynamicProxy/Contributors/InterfaceProxyWithoutTargetContributor.cs deleted file mode 100644 index 3910e42..0000000 --- a/Castle.Core/DynamicProxy/Contributors/InterfaceProxyWithoutTargetContributor.cs +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Contributors -{ - using System; - using System.Collections.Generic; - using System.Diagnostics; - - using Castle.DynamicProxy.Generators; - using Castle.DynamicProxy.Generators.Emitters; - using Castle.DynamicProxy.Internal; - - internal class InterfaceProxyWithoutTargetContributor : CompositeTypeContributor - { - private readonly GetTargetExpressionDelegate getTargetExpression; - protected bool canChangeTarget = false; - - public InterfaceProxyWithoutTargetContributor(INamingScope namingScope, GetTargetExpressionDelegate getTarget) - : base(namingScope) - { - getTargetExpression = getTarget; - } - - protected override IEnumerable GetCollectors() - { - foreach (var @interface in interfaces) - { - var item = new InterfaceMembersCollector(@interface); - yield return item; - } - } - - protected override MethodGenerator GetMethodGenerator(MetaMethod method, ClassEmitter @class, - OverrideMethodDelegate overrideMethod) - { - if (!method.Proxyable) - { - return new MinimialisticMethodGenerator(method, overrideMethod); - } - - var invocation = GetInvocationType(method, @class); - return new MethodWithInvocationGenerator(method, - @class.GetField("__interceptors"), - invocation, - getTargetExpression, - overrideMethod, - null); - } - - private Type GetInvocationType(MetaMethod method, ClassEmitter emitter) - { - var methodInfo = method.Method; - - if (canChangeTarget == false && methodInfo.IsAbstract) - { - // We do not need to generate a custom invocation type because no custom implementation - // for `InvokeMethodOnTarget` will be needed (proceeding to target isn't possible here): - return typeof(InterfaceMethodWithoutTargetInvocation); - } - - var scope = emitter.ModuleScope; - Type[] invocationInterfaces; - if (canChangeTarget) - { - invocationInterfaces = new[] { typeof(IInvocation), typeof(IChangeProxyTarget) }; - } - else - { - invocationInterfaces = new[] { typeof(IInvocation) }; - } - var key = new CacheKey(methodInfo, CompositionInvocationTypeGenerator.BaseType, invocationInterfaces, null); - - // no locking required as we're already within a lock - - return scope.TypeCache.GetOrAddWithoutTakingLock(key, _ => - new CompositionInvocationTypeGenerator(methodInfo.DeclaringType, - method, - methodInfo, - canChangeTarget, - null) - .Generate(emitter, namingScope) - .BuildType()); - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Contributors/InvocationWithDelegateContributor.cs b/Castle.Core/DynamicProxy/Contributors/InvocationWithDelegateContributor.cs deleted file mode 100644 index 48f7d29..0000000 --- a/Castle.Core/DynamicProxy/Contributors/InvocationWithDelegateContributor.cs +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Contributors -{ - using System; - using System.Diagnostics; - using System.Reflection; - - using Castle.DynamicProxy.Generators; - using Castle.DynamicProxy.Generators.Emitters; - using Castle.DynamicProxy.Generators.Emitters.SimpleAST; - using Castle.DynamicProxy.Tokens; - - internal class InvocationWithDelegateContributor : IInvocationCreationContributor - { - private readonly Type delegateType; - private readonly MetaMethod method; - private readonly INamingScope namingScope; - private readonly Type targetType; - - public InvocationWithDelegateContributor(Type delegateType, Type targetType, MetaMethod method, - INamingScope namingScope) - { - Debug.Assert(delegateType.IsGenericType == false, "delegateType.IsGenericType == false"); - this.delegateType = delegateType; - this.targetType = targetType; - this.method = method; - this.namingScope = namingScope; - } - - public ConstructorEmitter CreateConstructor(ArgumentReference[] baseCtorArguments, AbstractTypeEmitter invocation) - { - var arguments = GetArguments(baseCtorArguments); - var constructor = invocation.CreateConstructor(arguments); - - var delegateField = invocation.CreateField("delegate", delegateType); - constructor.CodeBuilder.AddStatement(new AssignStatement(delegateField, arguments[0])); - return constructor; - } - - public MethodInfo GetCallbackMethod() - { - return delegateType.GetMethod("Invoke"); - } - - public MethodInvocationExpression GetCallbackMethodInvocation(AbstractTypeEmitter invocation, IExpression[] args, - Reference targetField, - MethodEmitter invokeMethodOnTarget) - { - var allArgs = GetAllArgs(args, targetField); - var @delegate = (Reference)invocation.GetField("delegate"); - - return new MethodInvocationExpression(@delegate, GetCallbackMethod(), allArgs); - } - - public IExpression[] GetConstructorInvocationArguments(IExpression[] arguments, ClassEmitter proxy) - { - var allArguments = new IExpression[arguments.Length + 1]; - allArguments[0] = BuildDelegateToken(proxy); - Array.Copy(arguments, 0, allArguments, 1, arguments.Length); - return allArguments; - } - - private FieldReference BuildDelegateToken(ClassEmitter proxy) - { - var callback = proxy.CreateStaticField(namingScope.GetUniqueName("callback_" + method.Method.Name), delegateType); - var createDelegate = new MethodInvocationExpression( - null, - DelegateMethods.CreateDelegate, - new TypeTokenExpression(delegateType), - NullExpression.Instance, - new MethodTokenExpression(method.MethodOnTarget)); - var bindDelegate = new AssignStatement(callback, new ConvertExpression(delegateType, createDelegate)); - - proxy.ClassConstructor.CodeBuilder.AddStatement(bindDelegate); - return callback; - } - - private IExpression[] GetAllArgs(IExpression[] args, Reference targetField) - { - var allArgs = new IExpression[args.Length + 1]; - args.CopyTo(allArgs, 1); - allArgs[0] = new ConvertExpression(targetType, targetField); - return allArgs; - } - - private ArgumentReference[] GetArguments(ArgumentReference[] baseCtorArguments) - { - var arguments = new ArgumentReference[baseCtorArguments.Length + 1]; - arguments[0] = new ArgumentReference(delegateType); - baseCtorArguments.CopyTo(arguments, 1); - return arguments; - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Contributors/InvocationWithGenericDelegateContributor.cs b/Castle.Core/DynamicProxy/Contributors/InvocationWithGenericDelegateContributor.cs deleted file mode 100644 index 3dbeaf5..0000000 --- a/Castle.Core/DynamicProxy/Contributors/InvocationWithGenericDelegateContributor.cs +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Contributors -{ - using System; - using System.Diagnostics; - using System.Linq; - using System.Reflection; - - using Castle.DynamicProxy.Generators; - using Castle.DynamicProxy.Generators.Emitters; - using Castle.DynamicProxy.Generators.Emitters.SimpleAST; - using Castle.DynamicProxy.Internal; - using Castle.DynamicProxy.Tokens; - - internal class InvocationWithGenericDelegateContributor : IInvocationCreationContributor - { - private readonly Type delegateType; - private readonly MetaMethod method; - private readonly Reference targetReference; - - public InvocationWithGenericDelegateContributor(Type delegateType, MetaMethod method, Reference targetReference) - { - Debug.Assert(delegateType.IsGenericType, "delegateType.IsGenericType"); - this.delegateType = delegateType; - this.method = method; - this.targetReference = targetReference; - } - - public ConstructorEmitter CreateConstructor(ArgumentReference[] baseCtorArguments, AbstractTypeEmitter invocation) - { - return invocation.CreateConstructor(baseCtorArguments); - } - - public MethodInfo GetCallbackMethod() - { - return delegateType.GetMethod("Invoke"); - } - - public MethodInvocationExpression GetCallbackMethodInvocation(AbstractTypeEmitter invocation, IExpression[] args, - Reference targetField, - MethodEmitter invokeMethodOnTarget) - { - var @delegate = GetDelegate(invocation, invokeMethodOnTarget); - return new MethodInvocationExpression(@delegate, GetCallbackMethod(), args); - } - - public IExpression[] GetConstructorInvocationArguments(IExpression[] arguments, ClassEmitter proxy) - { - return arguments; - } - - private Reference GetDelegate(AbstractTypeEmitter invocation, MethodEmitter invokeMethodOnTarget) - { - var genericTypeParameters = invocation.GenericTypeParams.AsTypeArray(); - var closedDelegateType = delegateType.MakeGenericType(genericTypeParameters); - var localReference = invokeMethodOnTarget.CodeBuilder.DeclareLocal(closedDelegateType); - var closedMethodOnTarget = method.MethodOnTarget.MakeGenericMethod(genericTypeParameters); - invokeMethodOnTarget.CodeBuilder.AddStatement( - SetDelegate(localReference, targetReference, closedDelegateType, closedMethodOnTarget)); - return localReference; - } - - private AssignStatement SetDelegate(LocalReference localDelegate, Reference localTarget, - Type closedDelegateType, MethodInfo closedMethodOnTarget) - { - var delegateCreateDelegate = new MethodInvocationExpression( - null, - DelegateMethods.CreateDelegate, - new TypeTokenExpression(closedDelegateType), - localTarget, - new MethodTokenExpression(closedMethodOnTarget)); - return new AssignStatement(localDelegate, new ConvertExpression(closedDelegateType, delegateCreateDelegate)); - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Contributors/MembersCollector.cs b/Castle.Core/DynamicProxy/Contributors/MembersCollector.cs deleted file mode 100644 index 6ca7a9a..0000000 --- a/Castle.Core/DynamicProxy/Contributors/MembersCollector.cs +++ /dev/null @@ -1,228 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Contributors -{ - using System; - using System.Collections.Generic; - using System.Linq; - using System.Reflection; - - using Castle.Core.Logging; - using Castle.DynamicProxy.Generators; - using Castle.DynamicProxy.Internal; - - internal abstract class MembersCollector - { - private const BindingFlags Flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance; - private ILogger logger = NullLogger.Instance; - - protected readonly Type type; - - protected MembersCollector(Type type) - { - this.type = type; - } - - public ILogger Logger - { - get { return logger; } - set { logger = value; } - } - - public virtual void CollectMembersToProxy(IProxyGenerationHook hook, IMembersCollectorSink sink) - { - var checkedMethods = new HashSet(); - - CollectProperties(); - CollectEvents(); - // Methods go last, because properties and events have methods too (getters/setters add/remove) - // and we don't want to get duplicates, so we collect property and event methods first - // then we collect methods, and add only these that aren't there yet - CollectMethods(); - - void CollectProperties() - { - var propertiesFound = type.GetProperties(Flags); - foreach (var property in propertiesFound) - { - AddProperty(property); - } - } - - void CollectEvents() - { - var eventsFound = type.GetEvents(Flags); - foreach (var @event in eventsFound) - { - AddEvent(@event); - } - } - - void CollectMethods() - { - var methodsFound = MethodFinder.GetAllInstanceMethods(type, Flags); - foreach (var method in methodsFound) - { - AddMethod(method, true); - } - } - - void AddProperty(PropertyInfo property) - { - MetaMethod getter = null; - MetaMethod setter = null; - - if (property.CanRead) - { - var getMethod = property.GetGetMethod(true); - getter = AddMethod(getMethod, false); - } - - if (property.CanWrite) - { - var setMethod = property.GetSetMethod(true); - setter = AddMethod(setMethod, false); - } - - if (setter == null && getter == null) - { - return; - } - - var nonInheritableAttributes = property.GetNonInheritableAttributes(); - var arguments = property.GetIndexParameters(); - - sink.Add(new MetaProperty(property, - getter, - setter, - nonInheritableAttributes.Select(a => a.Builder), - arguments.Select(a => a.ParameterType).ToArray())); - } - - void AddEvent(EventInfo @event) - { - var addMethod = @event.GetAddMethod(true); - var removeMethod = @event.GetRemoveMethod(true); - MetaMethod adder = null; - MetaMethod remover = null; - - if (addMethod != null) - { - adder = AddMethod(addMethod, false); - } - - if (removeMethod != null) - { - remover = AddMethod(removeMethod, false); - } - - if (adder == null && remover == null) - { - return; - } - - sink.Add(new MetaEvent(@event, adder, remover, EventAttributes.None)); - } - - MetaMethod AddMethod(MethodInfo method, bool isStandalone) - { - if (checkedMethods.Add(method) == false) - { - return null; - } - - var methodToGenerate = GetMethodToGenerate(method, hook, isStandalone); - if (methodToGenerate != null) - { - sink.Add(methodToGenerate); - } - - return methodToGenerate; - } - } - - protected abstract MetaMethod GetMethodToGenerate(MethodInfo method, IProxyGenerationHook hook, bool isStandalone); - - /// - /// Performs some basic screening and invokes the - /// to select methods. - /// - protected bool AcceptMethod(MethodInfo method, bool onlyVirtuals, IProxyGenerationHook hook) - { - return AcceptMethodPreScreen(method, onlyVirtuals, hook) && hook.ShouldInterceptMethod(type, method); - } - - /// - /// Performs some basic screening to filter out non-interceptable methods. - /// - /// - /// The will get invoked for non-interceptable method notification only; - /// it does not get asked whether or not to intercept the . - /// - protected bool AcceptMethodPreScreen(MethodInfo method, bool onlyVirtuals, IProxyGenerationHook hook) - { - if (IsInternalAndNotVisibleToDynamicProxy(method)) - { - return false; - } - - var isOverridable = method.IsVirtual && !method.IsFinal; - if (onlyVirtuals && !isOverridable) - { - if (method.DeclaringType != typeof(MarshalByRefObject) && - method.IsGetType() == false && - method.IsMemberwiseClone() == false) - { - Logger.DebugFormat("Excluded non-overridable method {0} on {1} because it cannot be intercepted.", method.Name, - method.DeclaringType.FullName); - hook.NonProxyableMemberNotification(type, method); - } - return false; - } - - // we can never intercept a sealed (final) method - if (method.IsFinal) - { - Logger.DebugFormat("Excluded sealed method {0} on {1} because it cannot be intercepted.", method.Name, - method.DeclaringType.FullName); - return false; - } - - //can only proxy methods that are public or protected (or internals that have already been checked above) - if ((method.IsPublic || method.IsFamily || method.IsAssembly || method.IsFamilyOrAssembly || method.IsFamilyAndAssembly) == false) - { - return false; - } - - if (method.DeclaringType == typeof(MarshalByRefObject)) - { - return false; - } - - if (method.IsFinalizer()) - { - return false; - } - - return true; - } - - private static bool IsInternalAndNotVisibleToDynamicProxy(MethodInfo method) - { - return ProxyUtil.IsInternal(method) && - ProxyUtil.AreInternalsVisibleToDynamicProxy(method.DeclaringType.Assembly) == false; - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Contributors/MixinContributor.cs b/Castle.Core/DynamicProxy/Contributors/MixinContributor.cs deleted file mode 100644 index e607099..0000000 --- a/Castle.Core/DynamicProxy/Contributors/MixinContributor.cs +++ /dev/null @@ -1,153 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Contributors -{ - using System; - using System.Collections.Generic; - using System.Diagnostics; - using System.Reflection; - - using Castle.DynamicProxy.Generators; - using Castle.DynamicProxy.Generators.Emitters; - using Castle.DynamicProxy.Generators.Emitters.SimpleAST; - using Castle.DynamicProxy.Internal; - - internal class MixinContributor : CompositeTypeContributor - { - private readonly bool canChangeTarget; - private readonly IList empty = new List(); - private readonly IDictionary fields = new SortedDictionary(new FieldReferenceComparer()); - private readonly GetTargetExpressionDelegate getTargetExpression; - - public MixinContributor(INamingScope namingScope, bool canChangeTarget) - : base(namingScope) - { - this.canChangeTarget = canChangeTarget; - getTargetExpression = BuildGetTargetExpression(); - } - - public IEnumerable Fields - { - get { return fields.Values; } - } - - public void AddEmptyInterface(Type @interface) - { - Debug.Assert(@interface != null, "@interface == null", "Shouldn't be adding empty interfaces..."); - Debug.Assert(@interface.IsInterface, "@interface.IsInterface", "Should be adding interfaces only..."); - Debug.Assert(!interfaces.Contains(@interface), "!interfaces.Contains(@interface)", - "Shouldn't be adding same interface twice..."); - Debug.Assert(!empty.Contains(@interface), "!empty.Contains(@interface)", - "Shouldn't be adding same interface twice..."); - empty.Add(@interface); - } - - public override void Generate(ClassEmitter @class) - { - foreach (var @interface in interfaces) - { - fields[@interface] = BuildTargetField(@class, @interface); - } - - foreach (var emptyInterface in empty) - { - fields[emptyInterface] = BuildTargetField(@class, emptyInterface); - } - - base.Generate(@class); - } - - protected override IEnumerable GetCollectors() - { - foreach (var @interface in interfaces) - { - MembersCollector item; - if (@interface.IsInterface) - { - item = new InterfaceMembersCollector(@interface); - } - else - { - Debug.Assert(@interface.IsDelegateType()); - item = new DelegateTypeMembersCollector(@interface); - } - yield return item; - } - } - - protected override MethodGenerator GetMethodGenerator(MetaMethod method, ClassEmitter @class, - OverrideMethodDelegate overrideMethod) - { - if (!method.Proxyable) - { - return new ForwardingMethodGenerator(method, - overrideMethod, - (c, i) => fields[i.DeclaringType]); - } - - var invocation = GetInvocationType(method, @class); - return new MethodWithInvocationGenerator(method, - @class.GetField("__interceptors"), - invocation, - getTargetExpression, - overrideMethod, - null); - } - - private GetTargetExpressionDelegate BuildGetTargetExpression() - { - if (!canChangeTarget) - { - return (c, m) => fields[m.DeclaringType]; - } - - return (c, m) => new NullCoalescingOperatorExpression( - new AsTypeReference(c.GetField("__target"), m.DeclaringType), - fields[m.DeclaringType]); - } - - private FieldReference BuildTargetField(ClassEmitter @class, Type type) - { - var name = "__mixin_" + type.FullName.Replace(".", "_"); - return @class.CreateField(namingScope.GetUniqueName(name), type); - } - - private Type GetInvocationType(MetaMethod method, ClassEmitter emitter) - { - var scope = emitter.ModuleScope; - Type[] invocationInterfaces; - if (canChangeTarget) - { - invocationInterfaces = new[] { typeof(IInvocation), typeof(IChangeProxyTarget) }; - } - else - { - invocationInterfaces = new[] { typeof(IInvocation) }; - } - var key = new CacheKey(method.Method, CompositionInvocationTypeGenerator.BaseType, invocationInterfaces, null); - - // no locking required as we're already within a lock - - return scope.TypeCache.GetOrAddWithoutTakingLock(key, _ => - new CompositionInvocationTypeGenerator(method.Method.DeclaringType, - method, - method.Method, - canChangeTarget, - null) - .Generate(emitter, namingScope) - .BuildType()); - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Contributors/NonInheritableAttributesContributor.cs b/Castle.Core/DynamicProxy/Contributors/NonInheritableAttributesContributor.cs deleted file mode 100644 index 0f30bec..0000000 --- a/Castle.Core/DynamicProxy/Contributors/NonInheritableAttributesContributor.cs +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Contributors -{ - using System; - - using Castle.DynamicProxy.Generators; - using Castle.DynamicProxy.Generators.Emitters; - using Castle.DynamicProxy.Internal; - - /// - /// Reproduces the proxied type's non-inheritable custom attributes on the proxy type. - /// - internal sealed class NonInheritableAttributesContributor : ITypeContributor - { - private readonly Type targetType; - - public NonInheritableAttributesContributor(Type targetType) - { - this.targetType = targetType; - } - - public void Generate(ClassEmitter emitter) - { - foreach (var attribute in targetType.GetNonInheritableAttributes()) - { - emitter.DefineCustomAttribute(attribute.Builder); - } - } - - public void CollectElementsToProxy(IProxyGenerationHook hook, MetaType model) - { - } - } -} diff --git a/Castle.Core/DynamicProxy/Contributors/ProxyTargetAccessorContributor.cs b/Castle.Core/DynamicProxy/Contributors/ProxyTargetAccessorContributor.cs deleted file mode 100644 index 32cdec1..0000000 --- a/Castle.Core/DynamicProxy/Contributors/ProxyTargetAccessorContributor.cs +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Contributors -{ - using System; - - using Castle.DynamicProxy.Generators; - using Castle.DynamicProxy.Generators.Emitters; - using Castle.DynamicProxy.Generators.Emitters.SimpleAST; - - /// - /// Adds an implementation for to the proxy type. - /// - internal sealed class ProxyTargetAccessorContributor : ITypeContributor - { - private readonly Func getTargetReference; - private readonly Type targetType; - - public ProxyTargetAccessorContributor(Func getTargetReference, Type targetType) - { - this.getTargetReference = getTargetReference; - this.targetType = targetType; - } - - public void CollectElementsToProxy(IProxyGenerationHook hook, MetaType model) - { - } - - public void Generate(ClassEmitter emitter) - { - var interceptorsField = emitter.GetField("__interceptors"); - var targetReference = getTargetReference(); - - var dynProxyGetTarget = emitter.CreateMethod(nameof(IProxyTargetAccessor.DynProxyGetTarget), typeof(object)); - - dynProxyGetTarget.CodeBuilder.AddStatement( - new ReturnStatement(new ConvertExpression(typeof(object), targetType, targetReference))); - - var dynProxySetTarget = emitter.CreateMethod(nameof(IProxyTargetAccessor.DynProxySetTarget), typeof(void), typeof(object)); - - // we can only change the target of the interface proxy - if (targetReference is FieldReference targetField) - { - dynProxySetTarget.CodeBuilder.AddStatement( - new AssignStatement(targetField, - new ConvertExpression(targetField.Fieldbuilder.FieldType, dynProxySetTarget.Arguments[0]))); - } - else - { - dynProxySetTarget.CodeBuilder.AddStatement( - new ThrowStatement(typeof(InvalidOperationException), "Cannot change the target of the class proxy.")); - } - - dynProxySetTarget.CodeBuilder.AddStatement(new ReturnStatement()); - - var getInterceptors = emitter.CreateMethod(nameof(IProxyTargetAccessor.GetInterceptors), typeof(IInterceptor[])); - - getInterceptors.CodeBuilder.AddStatement( - new ReturnStatement(interceptorsField)); - } - } -} diff --git a/Castle.Core/DynamicProxy/Contributors/SerializableContributor.cs b/Castle.Core/DynamicProxy/Contributors/SerializableContributor.cs deleted file mode 100644 index c4ff339..0000000 --- a/Castle.Core/DynamicProxy/Contributors/SerializableContributor.cs +++ /dev/null @@ -1,153 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#if FEATURE_SERIALIZATION - -namespace Castle.DynamicProxy.Contributors -{ - using System; - using System.Runtime.Serialization; - - using Castle.DynamicProxy.Generators; - using Castle.DynamicProxy.Generators.Emitters; - using Castle.DynamicProxy.Generators.Emitters.SimpleAST; - using Castle.DynamicProxy.Serialization; - using Castle.DynamicProxy.Tokens; - - internal abstract class SerializableContributor : ITypeContributor - { - protected readonly Type targetType; - private readonly string proxyTypeId; - private readonly Type[] interfaces; - - protected SerializableContributor(Type targetType, Type[] interfaces, string proxyTypeId) - { - this.targetType = targetType; - this.proxyTypeId = proxyTypeId; - this.interfaces = interfaces ?? Type.EmptyTypes; - } - - public virtual void Generate(ClassEmitter @class) - { - ImplementGetObjectData(@class); - } - - protected void ImplementGetObjectData(ClassEmitter emitter) - { - var getObjectData = emitter.CreateMethod("GetObjectData", typeof(void), - new[] { typeof(SerializationInfo), typeof(StreamingContext) }); - var info = getObjectData.Arguments[0]; - - var typeLocal = getObjectData.CodeBuilder.DeclareLocal(typeof(Type)); - - getObjectData.CodeBuilder.AddStatement( - new AssignStatement( - typeLocal, - new MethodInvocationExpression( - null, - TypeMethods.StaticGetType, - new LiteralStringExpression(typeof(ProxyObjectReference).AssemblyQualifiedName), - new LiteralBoolExpression(true), - new LiteralBoolExpression(false)))); - - getObjectData.CodeBuilder.AddStatement( - new MethodInvocationExpression( - info, - SerializationInfoMethods.SetType, - typeLocal)); - - foreach (var field in emitter.GetAllFields()) - { - if (field.Reference.IsStatic) - { - continue; - } - if (field.Reference.IsNotSerialized) - { - continue; - } - AddAddValueInvocation(info, getObjectData, field); - } - - var interfacesLocal = getObjectData.CodeBuilder.DeclareLocal(typeof(string[])); - - getObjectData.CodeBuilder.AddStatement( - new AssignStatement( - interfacesLocal, - new NewArrayExpression(interfaces.Length, typeof(string)))); - - for (var i = 0; i < interfaces.Length; i++) - { - getObjectData.CodeBuilder.AddStatement( - new AssignArrayStatement( - interfacesLocal, - i, - new LiteralStringExpression(interfaces[i].AssemblyQualifiedName))); - } - - getObjectData.CodeBuilder.AddStatement( - new MethodInvocationExpression( - info, - SerializationInfoMethods.AddValue_Object, - new LiteralStringExpression("__interfaces"), - interfacesLocal)); - - getObjectData.CodeBuilder.AddStatement( - new MethodInvocationExpression( - info, - SerializationInfoMethods.AddValue_Object, - new LiteralStringExpression("__baseType"), - new LiteralStringExpression(emitter.BaseType.AssemblyQualifiedName))); - - getObjectData.CodeBuilder.AddStatement( - new MethodInvocationExpression( - info, - SerializationInfoMethods.AddValue_Object, - new LiteralStringExpression("__proxyGenerationOptions"), - emitter.GetField("proxyGenerationOptions"))); - - getObjectData.CodeBuilder.AddStatement( - new MethodInvocationExpression( - info, - SerializationInfoMethods.AddValue_Object, - new LiteralStringExpression("__proxyTypeId"), - new LiteralStringExpression(proxyTypeId))); - - CustomizeGetObjectData(getObjectData.CodeBuilder, info, getObjectData.Arguments[1], emitter); - - getObjectData.CodeBuilder.AddStatement(new ReturnStatement()); - } - - protected virtual void AddAddValueInvocation(ArgumentReference serializationInfo, MethodEmitter getObjectData, - FieldReference field) - { - getObjectData.CodeBuilder.AddStatement( - new MethodInvocationExpression( - serializationInfo, - SerializationInfoMethods.AddValue_Object, - new LiteralStringExpression(field.Reference.Name), - field)); - return; - } - - protected abstract void CustomizeGetObjectData(CodeBuilder builder, ArgumentReference serializationInfo, - ArgumentReference streamingContext, ClassEmitter emitter); - - public virtual void CollectElementsToProxy(IProxyGenerationHook hook, MetaType model) - { - } - } -} - -#endif diff --git a/Castle.Core/DynamicProxy/Contributors/WrappedClassMembersCollector.cs b/Castle.Core/DynamicProxy/Contributors/WrappedClassMembersCollector.cs deleted file mode 100644 index eca2214..0000000 --- a/Castle.Core/DynamicProxy/Contributors/WrappedClassMembersCollector.cs +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Contributors -{ - using System; - using System.Reflection; - using System.Runtime.CompilerServices; - - using Castle.DynamicProxy.Generators; - using Castle.DynamicProxy.Generators.Emitters; - using Castle.DynamicProxy.Internal; - - internal class WrappedClassMembersCollector : ClassMembersCollector - { - public WrappedClassMembersCollector(Type type) : base(type) - { - } - - public override void CollectMembersToProxy(IProxyGenerationHook hook, IMembersCollectorSink sink) - { - base.CollectMembersToProxy(hook, sink); - CollectFields(hook); - // TODO: perhaps we should also look for nested classes... - } - - protected override MetaMethod GetMethodToGenerate(MethodInfo method, IProxyGenerationHook hook, bool isStandalone) - { - if (ProxyUtil.IsAccessibleMethod(method) == false) - { - return null; - } - - var interceptable = AcceptMethodPreScreen(method, true, hook); - if (!interceptable) - { - //we don't need to do anything... - return null; - } - - var accepted = hook.ShouldInterceptMethod(type, method); - - return new MetaMethod(method, method, isStandalone, accepted, hasTarget: true); - } - - protected bool IsGeneratedByTheCompiler(FieldInfo field) - { - // for example fields backing autoproperties - return field.IsDefined(typeof(CompilerGeneratedAttribute)); - } - - protected virtual bool IsOKToBeOnProxy(FieldInfo field) - { - return IsGeneratedByTheCompiler(field); - } - - private void CollectFields(IProxyGenerationHook hook) - { - var fields = type.GetAllFields(); - foreach (var field in fields) - { - if (IsOKToBeOnProxy(field)) - { - continue; - } - - hook.NonProxyableMemberNotification(type, field); - } - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/CustomAttributeInfo.cs b/Castle.Core/DynamicProxy/CustomAttributeInfo.cs deleted file mode 100644 index 1277b86..0000000 --- a/Castle.Core/DynamicProxy/CustomAttributeInfo.cs +++ /dev/null @@ -1,347 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy -{ - using System; - using System.Collections.Generic; - using System.Linq; - using System.Linq.Expressions; - using System.Reflection; - using System.Reflection.Emit; - using System.Runtime.CompilerServices; - - /// - /// Encapsulates the information needed to build an attribute. - /// - /// - /// Arrays passed to this class as constructor arguments or property or field values become owned by this class. - /// They should not be mutated after creation. - /// - public class CustomAttributeInfo : IEquatable - { - // Cached empty arrays to avoid unnecessary allocations - private static readonly PropertyInfo[] EmptyProperties = new PropertyInfo[0]; - private static readonly FieldInfo[] EmptyFields = new FieldInfo[0]; - private static readonly object[] EmptyValues = new object[0]; - - private static readonly IEqualityComparer ValueComparer = new AttributeArgumentValueEqualityComparer(); - - private readonly CustomAttributeBuilder builder; - private readonly ConstructorInfo constructor; - private readonly object[] constructorArgs; - private readonly IDictionary properties; - private readonly IDictionary fields; - - public CustomAttributeInfo( - ConstructorInfo constructor, - object[] constructorArgs, - PropertyInfo[] namedProperties, - object[] propertyValues, - FieldInfo[] namedFields, - object[] fieldValues) - { - // Will take care of validating the arguments - this.builder = new CustomAttributeBuilder(constructor, constructorArgs, namedProperties, propertyValues, namedFields, fieldValues); - - this.constructor = constructor; - this.constructorArgs = constructorArgs.Length == 0 ? EmptyValues : constructorArgs.ToArray(); - this.properties = MakeNameValueDictionary(namedProperties, propertyValues); - this.fields = MakeNameValueDictionary(namedFields, fieldValues); - } - - public CustomAttributeInfo( - ConstructorInfo constructor, - object[] constructorArgs, - PropertyInfo[] namedProperties, - object[] propertyValues) - : this(constructor, constructorArgs, namedProperties, propertyValues, EmptyFields, EmptyValues) - { - } - - public CustomAttributeInfo( - ConstructorInfo constructor, - object[] constructorArgs, - FieldInfo[] namedFields, - object[] fieldValues) - : this(constructor, constructorArgs, EmptyProperties, EmptyValues, namedFields, fieldValues) - { - } - - public CustomAttributeInfo( - ConstructorInfo constructor, - object[] constructorArgs) - : this(constructor, constructorArgs, EmptyProperties, EmptyValues, EmptyFields, EmptyValues) - { - } - - public static CustomAttributeInfo FromExpression(Expression> expression) - { - var namedProperties = new List(); - var propertyValues = new List(); - var namedFields = new List(); - var fieldValues = new List(); - - var body = UnwrapBody(expression.Body); - - var newExpression = body as NewExpression; - if (newExpression == null) - { - var memberInitExpression = body as MemberInitExpression; - if (memberInitExpression == null) - { - throw new ArgumentException("The expression must be either a simple constructor call or an object initializer expression"); - } - - newExpression = memberInitExpression.NewExpression; - - foreach (var binding in memberInitExpression.Bindings) - { - var assignment = binding as MemberAssignment; - if (assignment == null) - { - throw new ArgumentException("Only assignment bindings are supported"); - } - - object value = GetAttributeArgumentValue(assignment.Expression, allowArray: true); - - var property = assignment.Member as PropertyInfo; - if (property != null) - { - namedProperties.Add(property); - propertyValues.Add(value); - } - else - { - var field = assignment.Member as FieldInfo; - if (field != null) - { - namedFields.Add(field); - fieldValues.Add(value); - } - else - { - throw new ArgumentException("Only property and field assignments are supported"); - } - } - } - } - - var ctorArguments = new List(); - foreach (var arg in newExpression.Arguments) - { - object value = GetAttributeArgumentValue(arg, allowArray: true); - ctorArguments.Add(value); - } - - return new CustomAttributeInfo( - newExpression.Constructor, - ctorArguments.ToArray(), - namedProperties.ToArray(), - propertyValues.ToArray(), - namedFields.ToArray(), - fieldValues.ToArray()); - } - - private static Expression UnwrapBody(Expression body) - { - // In VB.NET, a lambda expression like `Function() New MyAttribute()` introduces - // a conversion to the return type. We need to remove this conversion expression - // to get the actual constructor call. - - var convertExpression = body as UnaryExpression; - if (convertExpression != null && convertExpression.NodeType == ExpressionType.Convert) - { - return convertExpression.Operand; - } - return body; - } - - private static object GetAttributeArgumentValue(Expression arg, bool allowArray) - { - switch (arg.NodeType) - { - case ExpressionType.Constant: - return ((ConstantExpression)arg).Value; - case ExpressionType.MemberAccess: - var memberExpr = (MemberExpression) arg; - if (memberExpr.Member is FieldInfo field) - { - if (memberExpr.Expression is ConstantExpression constant && - IsCompilerGenerated(constant.Type) && - constant.Value != null) - { - return field.GetValue(constant.Value); - } - } - break; - case ExpressionType.NewArrayInit: - if (allowArray) - { - var newArrayExpr = (NewArrayExpression) arg; - var array = Array.CreateInstance(newArrayExpr.Type.GetElementType(), newArrayExpr.Expressions.Count); - int index = 0; - foreach (var expr in newArrayExpr.Expressions) - { - object value = GetAttributeArgumentValue(expr, allowArray: false); - array.SetValue(value, index); - index++; - } - return array; - } - break; - } - - throw new ArgumentException("Only constant, local variables, method parameters and single-dimensional array expressions are supported"); - } - - private static bool IsCompilerGenerated(Type type) - { - return type.IsDefined(typeof(CompilerGeneratedAttribute)); - } - - internal CustomAttributeBuilder Builder - { - get { return builder; } - } - - public bool Equals(CustomAttributeInfo other) - { - if (ReferenceEquals(null, other)) return false; - if (ReferenceEquals(this, other)) return true; - return constructor.Equals(other.constructor) && - constructorArgs.SequenceEqual(other.constructorArgs, ValueComparer) && - AreMembersEquivalent(properties, other.properties) && - AreMembersEquivalent(fields, other.fields); - } - - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != this.GetType()) return false; - return Equals((CustomAttributeInfo)obj); - } - - public override int GetHashCode() - { - unchecked - { - int hashCode = constructor.GetHashCode(); - hashCode = (hashCode*397) ^ CombineHashCodes(constructorArgs); - hashCode = (hashCode*397) ^ CombineMemberHashCodes(properties); - hashCode = (hashCode*397) ^ CombineMemberHashCodes(fields); - return hashCode; - } - } - - private static bool AreMembersEquivalent(IDictionary x, IDictionary y) - { - if (x.Count != y.Count) - return false; - - foreach (var kvp in x) - { - object value; - if (!y.TryGetValue(kvp.Key, out value)) - return false; - if (!ValueComparer.Equals(kvp.Value, value)) - return false; - } - return true; - } - - private static int CombineHashCodes(IEnumerable values) - { - unchecked - { - int hashCode = 173; - foreach (object value in values) - { - hashCode = (hashCode*397) ^ ValueComparer.GetHashCode(value); - } - return hashCode; - } - } - - private static int CombineMemberHashCodes(IDictionary dict) - { - unchecked - { - // Just sum the hashcodes of all key-value pairs, because - // we don't want to take order into account. - - int hashCode = 0; - foreach (var kvp in dict) - { - int keyHashCode = kvp.Key.GetHashCode(); - int valueHashCode = ValueComparer.GetHashCode(kvp.Value); - hashCode += (keyHashCode*397) ^ valueHashCode; - } - return hashCode; - } - } - - private IDictionary MakeNameValueDictionary(T[] members, object[] values) - where T : MemberInfo - { - var dict = new Dictionary(); - for (int i = 0; i < members.Length; i++) - { - dict.Add(members[i].Name, values[i]); - } - return dict; - } - - private class AttributeArgumentValueEqualityComparer : IEqualityComparer - { - bool IEqualityComparer.Equals(object x, object y) - { - if (ReferenceEquals(x, y)) - return true; - if (x == null || y == null) - return false; - if (x.GetType() != y.GetType()) - return false; - - if (x.GetType().IsArray) - { - return AsObjectEnumerable(x).SequenceEqual(AsObjectEnumerable(y)); - } - - return x.Equals(y); - } - - int IEqualityComparer.GetHashCode(object obj) - { - if (obj == null) - return 0; - if (obj.GetType().IsArray) - { - return CombineHashCodes(AsObjectEnumerable(obj)); - } - return obj.GetHashCode(); - } - - private static IEnumerable AsObjectEnumerable(object array) - { - // Covariance doesn't work for value types - if (array.GetType().GetElementType().IsValueType) - return ((Array)array).Cast(); - - return (IEnumerable)array; - } - } - } -} diff --git a/Castle.Core/DynamicProxy/DefaultProxyBuilder.cs b/Castle.Core/DynamicProxy/DefaultProxyBuilder.cs deleted file mode 100644 index c8454aa..0000000 --- a/Castle.Core/DynamicProxy/DefaultProxyBuilder.cs +++ /dev/null @@ -1,164 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy -{ - using System; - using System.Collections.Generic; - using System.Linq; - using System.Reflection; - - using Castle.Core.Internal; - using Castle.Core.Logging; - using Castle.DynamicProxy.Generators; - - /// - /// Default implementation of interface producing in-memory proxy assemblies. - /// - public class DefaultProxyBuilder : IProxyBuilder - { - private readonly ModuleScope scope; - private ILogger logger = NullLogger.Instance; - - /// - /// Initializes a new instance of the class with new . - /// - public DefaultProxyBuilder() - : this(new ModuleScope()) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The module scope for generated proxy types. - public DefaultProxyBuilder(ModuleScope scope) - { - this.scope = scope; - } - - public ILogger Logger - { - get { return logger; } - set { logger = value; } - } - - public ModuleScope ModuleScope - { - get { return scope; } - } - - public Type CreateClassProxyType(Type classToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options) - { - AssertValidType(classToProxy, nameof(classToProxy)); - AssertValidTypes(additionalInterfacesToProxy, nameof(additionalInterfacesToProxy)); - AssertValidMixins(options, nameof(options)); - - var generator = new ClassProxyGenerator(scope, classToProxy, additionalInterfacesToProxy, options) { Logger = logger }; - return generator.GetProxyType(); - } - - public Type CreateClassProxyTypeWithTarget(Type classToProxy, Type[] additionalInterfacesToProxy, - ProxyGenerationOptions options) - { - AssertValidType(classToProxy, nameof(classToProxy)); - AssertValidTypes(additionalInterfacesToProxy, nameof(additionalInterfacesToProxy)); - AssertValidMixins(options, nameof(options)); - - var generator = new ClassProxyWithTargetGenerator(scope, classToProxy, additionalInterfacesToProxy, options) - { Logger = logger }; - return generator.GetProxyType(); - } - - public Type CreateInterfaceProxyTypeWithTarget(Type interfaceToProxy, Type[] additionalInterfacesToProxy, - Type targetType, - ProxyGenerationOptions options) - { - AssertValidType(interfaceToProxy, nameof(interfaceToProxy)); - AssertValidTypes(additionalInterfacesToProxy, nameof(additionalInterfacesToProxy)); - AssertValidMixins(options, nameof(options)); - - var generator = new InterfaceProxyWithTargetGenerator(scope, interfaceToProxy, additionalInterfacesToProxy, targetType, options) { Logger = logger }; - return generator.GetProxyType(); - } - - public Type CreateInterfaceProxyTypeWithTargetInterface(Type interfaceToProxy, Type[] additionalInterfacesToProxy, - ProxyGenerationOptions options) - { - AssertValidType(interfaceToProxy, nameof(interfaceToProxy)); - AssertValidTypes(additionalInterfacesToProxy, nameof(additionalInterfacesToProxy)); - AssertValidMixins(options, nameof(options)); - - var generator = new InterfaceProxyWithTargetInterfaceGenerator(scope, interfaceToProxy, additionalInterfacesToProxy, interfaceToProxy, options) { Logger = logger }; - return generator.GetProxyType(); - } - - public Type CreateInterfaceProxyTypeWithoutTarget(Type interfaceToProxy, Type[] additionalInterfacesToProxy, - ProxyGenerationOptions options) - { - AssertValidType(interfaceToProxy, nameof(interfaceToProxy)); - AssertValidTypes(additionalInterfacesToProxy, nameof(additionalInterfacesToProxy)); - AssertValidMixins(options, nameof(options)); - - var generator = new InterfaceProxyWithoutTargetGenerator(scope, interfaceToProxy, additionalInterfacesToProxy, typeof(object), options) { Logger = logger }; - return generator.GetProxyType(); - } - - private void AssertValidMixins(ProxyGenerationOptions options, string paramName) - { - try - { - options.Initialize(); - } - catch (InvalidOperationException ex) - { - throw new ArgumentException(ex.Message, paramName, ex.InnerException); // convert to more suitable exception type - } - } - - private void AssertValidType(Type target, string paramName) - { - AssertValidTypeForTarget(target, target, paramName); - } - - private void AssertValidTypeForTarget(Type type, Type target, string paramName) - { - if (type.IsGenericTypeDefinition) - { - throw new ArgumentException( - $"Can not create proxy for type {target.GetBestName()} because type {type.GetBestName()} is an open generic type.", - paramName); - } - if (ProxyUtil.IsAccessibleType(type) == false) - { - throw new ArgumentException(ExceptionMessageBuilder.CreateMessageForInaccessibleType(type, target), paramName); - } - foreach (var typeArgument in type.GetGenericArguments()) - { - AssertValidTypeForTarget(typeArgument, target, paramName); - } - } - - private void AssertValidTypes(IEnumerable targetTypes, string paramName) - { - if (targetTypes != null) - { - foreach (var t in targetTypes) - { - AssertValidType(t, paramName); - } - } - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/DynProxy.snk b/Castle.Core/DynamicProxy/DynProxy.snk deleted file mode 100644 index 7fb7fb9c29f935e4f8b665fce0e6b5a5d0dc7abe..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50098SN6N!`y_v|{B3|*${tK)e-1+wxBo$ELr?HV4TXtu=Ph`Bf z;t~^p{T-b~tu2z$(N+ZsIV8;L_e@A(@AfLcX}KvL(4#=%6TT7Vr_&KWl1NPV1YF1Y zXIl}-&;bA}S z`vR*!S=B0zjS~GWpEY5W8G1XDFWWa~fTN052p8x4d)I|wPWisqz;q)ieM#HB>$T`t zJcdo$Is0;~;HrG?CMPWPsuDx3W~#~A2i#oT02|?OL1w*?kA%H#>q9O0a`yr!R+&!L z+T&VK@cnn3+y`X6!r!mbwc$hcNVCL|gz|(^u4`U%#8yx}OXy)@Lfg9?eCP!r6&~w| zJrCB706)1jDcRzGbu-KpY!S{%2x)2;2O*epnF@Z^7MQFukDVNmfY~qwl=fcTMV#b& zJn0;i`Yh-rpk!e@JLr4zbO1vFZt4K?&)7Z0lve3JLn}JT%>SXy5MpaqWToSW-Sy2U zZ%l_1hL0$Lg4|E|1h{Ik3NOs^nuCd?4)&@!`XGxIzq!uXO+#QuV15H8S^5LLhR5nF zG8g*&$x^Q}fk3~#n?}_ - /// Provides instructions that a user could follow to make a type or method in - /// visible to DynamicProxy. - /// The assembly containing the type or method. - /// Instructions that a user could follow to make a type or method visible to DynamicProxy. - internal static string CreateInstructionsToMakeVisible(Assembly targetAssembly) - { - string strongNamedOrNotIndicator = " not"; // assume not strong-named - string assemblyToBeVisibleTo = "\"DynamicProxyGenAssembly2\""; // appropriate for non-strong-named - - if (targetAssembly.IsAssemblySigned()) - { - strongNamedOrNotIndicator = ""; - assemblyToBeVisibleTo = ReferencesCastleCore(targetAssembly) - ? "InternalsVisible.ToDynamicProxyGenAssembly2" - : '"' + InternalsVisible.ToDynamicProxyGenAssembly2 + '"'; - } - - var instructionsFormat = - "Make it public, or internal and mark your assembly with " + - "[assembly: InternalsVisibleTo({0})] attribute, because assembly {1} " + - "is{2} strong-named."; - - var instructions = string.Format(instructionsFormat, - assemblyToBeVisibleTo, - targetAssembly.GetName().Name, - strongNamedOrNotIndicator); - return instructions; - - bool ReferencesCastleCore(Assembly ia) - { - return ia.GetReferencedAssemblies() - .Any(r => r.FullName == Assembly.GetExecutingAssembly().FullName); - } - } - - /// - /// Creates a message to inform clients that a proxy couldn't be created due to reliance on an - /// inaccessible type (perhaps itself). - /// - /// the inaccessible type that prevents proxy creation - /// the type that couldn't be proxied - public static string CreateMessageForInaccessibleType(Type inaccessibleType, Type typeToProxy) - { - var targetAssembly = typeToProxy.Assembly; - - string inaccessibleTypeDescription = inaccessibleType == typeToProxy - ? "it" - : "type " + inaccessibleType.GetBestName(); - - var messageFormat = "Can not create proxy for type {0} because {1} is not accessible. "; - - var message = string.Format(messageFormat, - typeToProxy.GetBestName(), - inaccessibleTypeDescription); - - var instructions = CreateInstructionsToMakeVisible(targetAssembly); - - return message + instructions; - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/AttributesToAvoidReplicating.cs b/Castle.Core/DynamicProxy/Generators/AttributesToAvoidReplicating.cs deleted file mode 100644 index e045a50..0000000 --- a/Castle.Core/DynamicProxy/Generators/AttributesToAvoidReplicating.cs +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators -{ - using System; - using System.Collections.Generic; - using System.Linq; - using System.Reflection; - - public static class AttributesToAvoidReplicating - { - private static readonly object lockObject = new object(); - - private static IList attributes; - - static AttributesToAvoidReplicating() - { - attributes = new List() - { - typeof(System.Runtime.InteropServices.ComImportAttribute), - typeof(System.Runtime.InteropServices.MarshalAsAttribute), - typeof(System.Runtime.InteropServices.TypeIdentifierAttribute), - typeof(System.Security.Permissions.SecurityAttribute), - }; - } - - public static void Add(Type attribute) - { - // note: this class is made thread-safe by replacing the backing list rather than adding to it - lock (lockObject) - { - attributes = new List(attributes) { attribute }; - } - } - - public static void Add() - { - Add(typeof(T)); - } - - public static bool Contains(Type attribute) - { - return attributes.Contains(attribute); - } - - internal static bool ShouldAvoid(Type attribute) - { - return attributes.Any(attr => attr.IsAssignableFrom(attribute)); - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/BaseClassProxyGenerator.cs b/Castle.Core/DynamicProxy/Generators/BaseClassProxyGenerator.cs deleted file mode 100644 index 02f6012..0000000 --- a/Castle.Core/DynamicProxy/Generators/BaseClassProxyGenerator.cs +++ /dev/null @@ -1,219 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators -{ - using System; - using System.Collections.Generic; - using System.Linq; - using System.Reflection; - - using Castle.DynamicProxy.Contributors; - using Castle.DynamicProxy.Generators.Emitters.SimpleAST; - using Castle.DynamicProxy.Internal; - - internal abstract class BaseClassProxyGenerator : BaseProxyGenerator - { - protected BaseClassProxyGenerator(ModuleScope scope, Type targetType, Type[] interfaces, ProxyGenerationOptions options) - : base(scope, targetType, interfaces, options) - { - EnsureDoesNotImplementIProxyTargetAccessor(targetType, nameof(targetType)); - } - - protected abstract FieldReference TargetField { get; } - -#if FEATURE_SERIALIZATION - protected abstract SerializableContributor GetSerializableContributor(); -#endif - - protected abstract CompositeTypeContributor GetProxyTargetContributor(INamingScope namingScope); - - protected abstract ProxyTargetAccessorContributor GetProxyTargetAccessorContributor(); - - protected sealed override Type GenerateType(string name, INamingScope namingScope) - { - IEnumerable contributors; - var allInterfaces = GetTypeImplementerMapping(out contributors, namingScope); - - var model = new MetaType(); - // Collect methods - foreach (var contributor in contributors) - { - contributor.CollectElementsToProxy(ProxyGenerationOptions.Hook, model); - } - ProxyGenerationOptions.Hook.MethodsInspected(); - - var emitter = BuildClassEmitter(name, targetType, allInterfaces); - - CreateFields(emitter); - CreateTypeAttributes(emitter); - - // Constructor - var cctor = GenerateStaticConstructor(emitter); - - var constructorArguments = new List(); - - if (TargetField is { } targetField) - { - constructorArguments.Add(targetField); - } - - foreach (var contributor in contributors) - { - contributor.Generate(emitter); - - // TODO: redo it - if (contributor is MixinContributor mixinContributor) - { - constructorArguments.AddRange(mixinContributor.Fields); - } - } - - // constructor arguments - var interceptorsField = emitter.GetField("__interceptors"); - constructorArguments.Add(interceptorsField); - var selector = emitter.GetField("__selector"); - if (selector != null) - { - constructorArguments.Add(selector); - } - - GenerateConstructors(emitter, targetType, constructorArguments.ToArray()); - GenerateParameterlessConstructor(emitter, targetType, interceptorsField); - - // Complete type initializer code body - CompleteInitCacheMethod(cctor.CodeBuilder); - - // non-inheritable attributes from proxied type - var nonInheritableAttributesContributor = new NonInheritableAttributesContributor(targetType); - nonInheritableAttributesContributor.Generate(emitter); - - // Crosses fingers and build type - - var proxyType = emitter.BuildType(); - InitializeStaticFields(proxyType); - return proxyType; - } - - private IEnumerable GetTypeImplementerMapping(out IEnumerable contributors, INamingScope namingScope) - { - var contributorsList = new List(capacity: 5); - var targetInterfaces = targetType.GetAllInterfaces(); - var typeImplementerMapping = new Dictionary(); - - // Order of interface precedence: - - // 1. first target - // target is not an interface so we do nothing - var targetContributor = GetProxyTargetContributor(namingScope); - contributorsList.Add(targetContributor); - - // 2. then mixins - if (ProxyGenerationOptions.HasMixins) - { - var mixinContributor = new MixinContributor(namingScope, false) { Logger = Logger }; - contributorsList.Add(mixinContributor); - - foreach (var mixinInterface in ProxyGenerationOptions.MixinData.MixinInterfaces) - { - if (targetInterfaces.Contains(mixinInterface)) - { - // OK, so the target implements this interface. We now do one of two things: - if (interfaces.Contains(mixinInterface) && - typeImplementerMapping.ContainsKey(mixinInterface) == false) - { - AddMappingNoCheck(mixinInterface, targetContributor, typeImplementerMapping); - targetContributor.AddInterfaceToProxy(mixinInterface); - } - // we do not intercept the interface - mixinContributor.AddEmptyInterface(mixinInterface); - } - else - { - if (!typeImplementerMapping.ContainsKey(mixinInterface)) - { - mixinContributor.AddInterfaceToProxy(mixinInterface); - AddMappingNoCheck(mixinInterface, mixinContributor, typeImplementerMapping); - } - } - } - } - - // 3. then additional interfaces - if (interfaces.Length > 0) - { - var additionalInterfacesContributor = new InterfaceProxyWithoutTargetContributor(namingScope, (c, m) => NullExpression.Instance) { Logger = Logger }; - contributorsList.Add(additionalInterfacesContributor); - - foreach (var @interface in interfaces) - { - if (targetInterfaces.Contains(@interface)) - { - if (typeImplementerMapping.ContainsKey(@interface)) - { - continue; - } - - // we intercept the interface, and forward calls to the target type - AddMappingNoCheck(@interface, targetContributor, typeImplementerMapping); - targetContributor.AddInterfaceToProxy(@interface); - } - else if (ProxyGenerationOptions.MixinData.ContainsMixin(@interface) == false) - { - additionalInterfacesContributor.AddInterfaceToProxy(@interface); - AddMapping(@interface, additionalInterfacesContributor, typeImplementerMapping); - } - } - } - - // 4. plus special interfaces - -#if FEATURE_SERIALIZATION - if (targetType.IsSerializable) - { - var serializableContributor = GetSerializableContributor(); - contributorsList.Add(serializableContributor); - AddMappingForISerializable(typeImplementerMapping, serializableContributor); - } -#endif - - var proxyTargetAccessorContributor = GetProxyTargetAccessorContributor(); - contributorsList.Add(proxyTargetAccessorContributor); - try - { - AddMappingNoCheck(typeof(IProxyTargetAccessor), proxyTargetAccessorContributor, typeImplementerMapping); - } - catch (ArgumentException) - { - HandleExplicitlyPassedProxyTargetAccessor(targetInterfaces); - } - - contributors = contributorsList; - return typeImplementerMapping.Keys; - } - - private void EnsureDoesNotImplementIProxyTargetAccessor(Type type, string name) - { - if (!typeof(IProxyTargetAccessor).IsAssignableFrom(type)) - { - return; - } - var message = - string.Format( - "Target type for the proxy implements {0} which is a DynamicProxy infrastructure interface and you should never implement it yourself. Are you trying to proxy an existing proxy?", - typeof(IProxyTargetAccessor)); - throw new ArgumentException(message, name); - } - } -} diff --git a/Castle.Core/DynamicProxy/Generators/BaseInterfaceProxyGenerator.cs b/Castle.Core/DynamicProxy/Generators/BaseInterfaceProxyGenerator.cs deleted file mode 100644 index 84e6b11..0000000 --- a/Castle.Core/DynamicProxy/Generators/BaseInterfaceProxyGenerator.cs +++ /dev/null @@ -1,296 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators -{ - using System; - using System.Collections.Generic; - using System.Linq; - using System.Reflection; -#if FEATURE_SERIALIZATION - using System.Xml.Serialization; -#endif - - using Castle.DynamicProxy.Contributors; - using Castle.DynamicProxy.Generators.Emitters; - using Castle.DynamicProxy.Generators.Emitters.SimpleAST; - using Castle.DynamicProxy.Internal; - - internal abstract class BaseInterfaceProxyGenerator : BaseProxyGenerator - { - protected readonly Type proxyTargetType; - - protected FieldReference targetField; - - protected BaseInterfaceProxyGenerator(ModuleScope scope, Type targetType, Type[] interfaces, - Type proxyTargetType, ProxyGenerationOptions options) - : base(scope, targetType, interfaces, options) - { - CheckNotGenericTypeDefinition(proxyTargetType, nameof(proxyTargetType)); - EnsureValidBaseType(ProxyGenerationOptions.BaseTypeForInterfaceProxy); - - this.proxyTargetType = proxyTargetType; - } - - protected abstract bool AllowChangeTarget { get; } - - protected abstract string GeneratorType { get; } - - protected abstract CompositeTypeContributor GetProxyTargetContributor(Type proxyTargetType, INamingScope namingScope); - - protected abstract ProxyTargetAccessorContributor GetProxyTargetAccessorContributor(); - - protected abstract void AddMappingForAdditionalInterfaces(CompositeTypeContributor contributor, Type[] proxiedInterfaces, - IDictionary typeImplementerMapping, - ICollection targetInterfaces); - - protected virtual ITypeContributor AddMappingForTargetType(IDictionary typeImplementerMapping, - Type proxyTargetType, ICollection targetInterfaces, - INamingScope namingScope) - { - var contributor = GetProxyTargetContributor(proxyTargetType, namingScope); - var proxiedInterfaces = targetType.GetAllInterfaces(); - foreach (var @interface in proxiedInterfaces) - { - contributor.AddInterfaceToProxy(@interface); - AddMappingNoCheck(@interface, contributor, typeImplementerMapping); - } - - AddMappingForAdditionalInterfaces(contributor, proxiedInterfaces, typeImplementerMapping, targetInterfaces); - return contributor; - } - -#if FEATURE_SERIALIZATION - protected override void CreateTypeAttributes(ClassEmitter emitter) - { - base.CreateTypeAttributes(emitter); - emitter.DefineCustomAttribute(); - } -#endif - - protected override CacheKey GetCacheKey() - { - return new CacheKey(proxyTargetType, targetType, interfaces, ProxyGenerationOptions); - } - - protected override Type GenerateType(string typeName, INamingScope namingScope) - { - IEnumerable contributors; - var allInterfaces = GetTypeImplementerMapping(proxyTargetType, out contributors, namingScope); - - var model = new MetaType(); - // Collect methods - foreach (var contributor in contributors) - { - contributor.CollectElementsToProxy(ProxyGenerationOptions.Hook, model); - } - - ProxyGenerationOptions.Hook.MethodsInspected(); - - ClassEmitter emitter; - FieldReference interceptorsField; - var baseType = Init(typeName, out emitter, proxyTargetType, out interceptorsField, allInterfaces); - - // Constructor - - var cctor = GenerateStaticConstructor(emitter); - var ctorArguments = new List(); - - foreach (var contributor in contributors) - { - contributor.Generate(emitter); - - // TODO: redo it - if (contributor is MixinContributor) - { - ctorArguments.AddRange((contributor as MixinContributor).Fields); - } - } - - ctorArguments.Add(interceptorsField); - ctorArguments.Add(targetField); - var selector = emitter.GetField("__selector"); - if (selector != null) - { - ctorArguments.Add(selector); - } - - GenerateConstructors(emitter, baseType, ctorArguments.ToArray()); - - // Complete type initializer code body - CompleteInitCacheMethod(cctor.CodeBuilder); - - // non-inheritable attributes from proxied type - var nonInheritableAttributesContributor = new NonInheritableAttributesContributor(targetType); - nonInheritableAttributesContributor.Generate(emitter); - - // Crosses fingers and build type - var generatedType = emitter.BuildType(); - - InitializeStaticFields(generatedType); - return generatedType; - } - - protected virtual InterfaceProxyWithoutTargetContributor GetContributorForAdditionalInterfaces( - INamingScope namingScope) - { - return new InterfaceProxyWithoutTargetContributor(namingScope, (c, m) => NullExpression.Instance) { Logger = Logger }; - } - - protected virtual IEnumerable GetTypeImplementerMapping(Type proxyTargetType, - out IEnumerable contributors, - INamingScope namingScope) - { - var contributorsList = new List(capacity: 5); - var targetInterfaces = proxyTargetType.GetAllInterfaces(); - var typeImplementerMapping = new Dictionary(); - - // Order of interface precedence: - // 1. first target - var targetContributor = AddMappingForTargetType(typeImplementerMapping, proxyTargetType, targetInterfaces, namingScope); - contributorsList.Add(targetContributor); - - // 2. then mixins - if (ProxyGenerationOptions.HasMixins) - { - var mixinContributor = new MixinContributor(namingScope, AllowChangeTarget) { Logger = Logger }; - contributorsList.Add(mixinContributor); - - foreach (var mixinInterface in ProxyGenerationOptions.MixinData.MixinInterfaces) - { - if (targetInterfaces.Contains(mixinInterface)) - { - // OK, so the target implements this interface. We now do one of two things: - if (interfaces.Contains(mixinInterface)) - { - // we intercept the interface, and forward calls to the target type - AddMapping(mixinInterface, targetContributor, typeImplementerMapping); - } - // we do not intercept the interface - mixinContributor.AddEmptyInterface(mixinInterface); - } - else - { - if (!typeImplementerMapping.ContainsKey(mixinInterface)) - { - mixinContributor.AddInterfaceToProxy(mixinInterface); - typeImplementerMapping.Add(mixinInterface, mixinContributor); - } - } - } - } - - // 3. then additional interfaces - if (interfaces.Length > 0) - { - var additionalInterfacesContributor = GetContributorForAdditionalInterfaces(namingScope); - contributorsList.Add(additionalInterfacesContributor); - - foreach (var @interface in interfaces) - { - if (typeImplementerMapping.ContainsKey(@interface)) - { - continue; - } - if (ProxyGenerationOptions.MixinData.ContainsMixin(@interface)) - { - continue; - } - - additionalInterfacesContributor.AddInterfaceToProxy(@interface); - AddMappingNoCheck(@interface, additionalInterfacesContributor, typeImplementerMapping); - } - } - - // 4. plus special interfaces - -#if FEATURE_SERIALIZATION - var serializableContributor = new InterfaceProxySerializableContributor(targetType, GeneratorType, interfaces); - contributorsList.Add(serializableContributor); - AddMappingForISerializable(typeImplementerMapping, serializableContributor); -#endif - - var proxyTargetAccessorContributor = GetProxyTargetAccessorContributor(); - contributorsList.Add(proxyTargetAccessorContributor); - try - { - AddMappingNoCheck(typeof(IProxyTargetAccessor), proxyTargetAccessorContributor, typeImplementerMapping); - } - catch (ArgumentException) - { - HandleExplicitlyPassedProxyTargetAccessor(targetInterfaces); - } - - contributors = contributorsList; - return typeImplementerMapping.Keys; - } - - protected virtual Type Init(string typeName, out ClassEmitter emitter, Type proxyTargetType, - out FieldReference interceptorsField, IEnumerable allInterfaces) - { - var baseType = ProxyGenerationOptions.BaseTypeForInterfaceProxy; - - emitter = BuildClassEmitter(typeName, baseType, allInterfaces); - - CreateFields(emitter, proxyTargetType); - CreateTypeAttributes(emitter); - - interceptorsField = emitter.GetField("__interceptors"); - return baseType; - } - - private void CreateFields(ClassEmitter emitter, Type proxyTargetType) - { - base.CreateFields(emitter); - targetField = emitter.CreateField("__target", proxyTargetType); -#if FEATURE_SERIALIZATION - emitter.DefineCustomAttributeFor(targetField); -#endif - } - - private void EnsureValidBaseType(Type type) - { - if (type == null) - { - throw new ArgumentException( - "Base type for proxy is null reference. Please set it to System.Object or some other valid type."); - } - - if (!type.IsClass) - { - ThrowInvalidBaseType(type, "it is not a class type"); - } - - if (type.IsSealed) - { - ThrowInvalidBaseType(type, "it is sealed"); - } - - var constructor = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, - null, Type.EmptyTypes, null); - - if (constructor == null || constructor.IsPrivate) - { - ThrowInvalidBaseType(type, "it does not have accessible parameterless constructor"); - } - } - - private void ThrowInvalidBaseType(Type type, string doesNotHaveAccessibleParameterlessConstructor) - { - var format = - "Type {0} is not valid base type for interface proxy, because {1}. Only a non-sealed class with non-private default constructor can be used as base type for interface proxy. Please use some other valid type."; - throw new ArgumentException(string.Format(format, type, doesNotHaveAccessibleParameterlessConstructor)); - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/BaseProxyGenerator.cs b/Castle.Core/DynamicProxy/Generators/BaseProxyGenerator.cs deleted file mode 100644 index 2d79040..0000000 --- a/Castle.Core/DynamicProxy/Generators/BaseProxyGenerator.cs +++ /dev/null @@ -1,409 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators -{ - using System; - using System.Collections.Generic; - using System.Diagnostics; - using System.Linq; - using System.Reflection; -#if FEATURE_SERIALIZATION - using System.Runtime.Serialization; - using System.Xml.Serialization; -#endif - - using Castle.Core.Logging; - using Castle.DynamicProxy.Contributors; - using Castle.DynamicProxy.Generators.Emitters; - using Castle.DynamicProxy.Generators.Emitters.SimpleAST; - using Castle.DynamicProxy.Internal; - - /// - /// Base class that exposes the common functionalities - /// to proxy generation. - /// - internal abstract class BaseProxyGenerator - { - protected readonly Type targetType; - protected readonly Type[] interfaces; - private readonly ModuleScope scope; - private ILogger logger = NullLogger.Instance; - private ProxyGenerationOptions proxyGenerationOptions; - - protected BaseProxyGenerator(ModuleScope scope, Type targetType, Type[] interfaces, ProxyGenerationOptions proxyGenerationOptions) - { - CheckNotGenericTypeDefinition(targetType, nameof(targetType)); - CheckNotGenericTypeDefinitions(interfaces, nameof(interfaces)); - - this.scope = scope; - this.targetType = targetType; - this.interfaces = TypeUtil.GetAllInterfaces(interfaces); - this.proxyGenerationOptions = proxyGenerationOptions; - this.proxyGenerationOptions.Initialize(); - } - - public ILogger Logger - { - get { return logger; } - set { logger = value; } - } - - protected ProxyGenerationOptions ProxyGenerationOptions - { - get { return proxyGenerationOptions; } - } - - protected ModuleScope Scope - { - get { return scope; } - } - - public Type GetProxyType() - { - bool notFoundInTypeCache = false; - - var proxyType = Scope.TypeCache.GetOrAdd(GetCacheKey(), cacheKey => - { - notFoundInTypeCache = true; - Logger.DebugFormat("No cached proxy type was found for target type {0}.", targetType.FullName); - - EnsureOptionsOverrideEqualsAndGetHashCode(); - - var name = Scope.NamingScope.GetUniqueName("Castle.Proxies." + targetType.Name + "Proxy"); - return GenerateType(name, Scope.NamingScope.SafeSubScope()); - }); - - if (!notFoundInTypeCache) - { - Logger.DebugFormat("Found cached proxy type {0} for target type {1}.", proxyType.FullName, targetType.FullName); - } - - return proxyType; - } - - protected abstract CacheKey GetCacheKey(); - - protected abstract Type GenerateType(string name, INamingScope namingScope); - - protected void AddMapping(Type @interface, ITypeContributor implementer, IDictionary mapping) - { - Debug.Assert(implementer != null, "implementer != null"); - Debug.Assert(@interface != null, "@interface != null"); - Debug.Assert(@interface.IsInterface, "@interface.IsInterface"); - - if (!mapping.ContainsKey(@interface)) - { - AddMappingNoCheck(@interface, implementer, mapping); - } - } - -#if FEATURE_SERIALIZATION - protected void AddMappingForISerializable(IDictionary typeImplementerMapping, - ITypeContributor instance) - { - AddMapping(typeof(ISerializable), instance, typeImplementerMapping); - } -#endif - - /// - /// It is safe to add mapping (no mapping for the interface exists) - /// - protected void AddMappingNoCheck(Type @interface, ITypeContributor implementer, - IDictionary mapping) - { - mapping.Add(@interface, implementer); - } - - protected virtual ClassEmitter BuildClassEmitter(string typeName, Type parentType, IEnumerable interfaces) - { - CheckNotGenericTypeDefinition(parentType, nameof(parentType)); - CheckNotGenericTypeDefinitions(interfaces, nameof(interfaces)); - - return new ClassEmitter(Scope, typeName, parentType, interfaces); - } - - protected void CheckNotGenericTypeDefinition(Type type, string argumentName) - { - if (type != null && type.IsGenericTypeDefinition) - { - throw new ArgumentException("Type cannot be a generic type definition. Type: " + type.FullName, argumentName); - } - } - - protected void CheckNotGenericTypeDefinitions(IEnumerable types, string argumentName) - { - if (types == null) - { - return; - } - foreach (var t in types) - { - CheckNotGenericTypeDefinition(t, argumentName); - } - } - - protected void CompleteInitCacheMethod(CodeBuilder constCodeBuilder) - { - constCodeBuilder.AddStatement(new ReturnStatement()); - } - - protected virtual void CreateFields(ClassEmitter emitter) - { - CreateOptionsField(emitter); - CreateSelectorField(emitter); - CreateInterceptorsField(emitter); - } - - protected void CreateInterceptorsField(ClassEmitter emitter) - { - var interceptorsField = emitter.CreateField("__interceptors", typeof(IInterceptor[])); - -#if FEATURE_SERIALIZATION - emitter.DefineCustomAttributeFor(interceptorsField); -#endif - } - - protected FieldReference CreateOptionsField(ClassEmitter emitter) - { - return emitter.CreateStaticField("proxyGenerationOptions", typeof(ProxyGenerationOptions)); - } - - protected void CreateSelectorField(ClassEmitter emitter) - { - if (ProxyGenerationOptions.Selector == null) - { - return; - } - - emitter.CreateField("__selector", typeof(IInterceptorSelector)); - } - - protected virtual void CreateTypeAttributes(ClassEmitter emitter) - { - emitter.AddCustomAttributes(ProxyGenerationOptions.AdditionalAttributes); -#if FEATURE_SERIALIZATION - emitter.DefineCustomAttribute(new object[] { targetType }); -#endif - } - - protected void EnsureOptionsOverrideEqualsAndGetHashCode() - { - if (Logger.IsWarnEnabled) - { - // Check the proxy generation hook - if (!OverridesEqualsAndGetHashCode(ProxyGenerationOptions.Hook.GetType())) - { - Logger.WarnFormat("The IProxyGenerationHook type {0} does not override both Equals and GetHashCode. " + - "If these are not correctly overridden caching will fail to work causing performance problems.", - ProxyGenerationOptions.Hook.GetType().FullName); - } - - // Interceptor selectors no longer need to override Equals and GetHashCode - } - } - - protected void GenerateConstructor(ClassEmitter emitter, ConstructorInfo baseConstructor, - params FieldReference[] fields) - { - ArgumentReference[] args; - ParameterInfo[] baseConstructorParams = null; - - if (baseConstructor != null) - { - baseConstructorParams = baseConstructor.GetParameters(); - } - - if (baseConstructorParams != null && baseConstructorParams.Length != 0) - { - args = new ArgumentReference[fields.Length + baseConstructorParams.Length]; - - var offset = fields.Length; - for (var i = offset; i < offset + baseConstructorParams.Length; i++) - { - var paramInfo = baseConstructorParams[i - offset]; - args[i] = new ArgumentReference(paramInfo.ParameterType); - } - } - else - { - args = new ArgumentReference[fields.Length]; - } - - for (var i = 0; i < fields.Length; i++) - { - args[i] = new ArgumentReference(fields[i].Reference.FieldType); - } - - var constructor = emitter.CreateConstructor(args); - if (baseConstructorParams != null && baseConstructorParams.Length != 0) - { - var offset = 1 + fields.Length; - for (int i = 0, n = baseConstructorParams.Length; i < n; ++i) - { - var parameterBuilder = constructor.ConstructorBuilder.DefineParameter(offset + i, baseConstructorParams[i].Attributes, baseConstructorParams[i].Name); - foreach (var attribute in baseConstructorParams[i].GetNonInheritableAttributes()) - { - parameterBuilder.SetCustomAttribute(attribute.Builder); - } - } - } - - for (var i = 0; i < fields.Length; i++) - { - constructor.CodeBuilder.AddStatement(new AssignStatement(fields[i], args[i])); - } - - // Invoke base constructor - - if (baseConstructor != null) - { - Debug.Assert(baseConstructorParams != null); - - var slice = new ArgumentReference[baseConstructorParams.Length]; - Array.Copy(args, fields.Length, slice, 0, baseConstructorParams.Length); - - constructor.CodeBuilder.AddStatement(new ConstructorInvocationStatement(baseConstructor, slice)); - } - else - { - constructor.CodeBuilder.AddStatement(new ConstructorInvocationStatement(emitter.BaseType)); - } - - constructor.CodeBuilder.AddStatement(new ReturnStatement()); - } - - protected void GenerateConstructors(ClassEmitter emitter, Type baseType, params FieldReference[] fields) - { - var constructors = - baseType.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); - - foreach (var constructor in constructors) - { - if (!ProxyUtil.IsAccessibleMethod(constructor)) - { - continue; - } - - GenerateConstructor(emitter, constructor, fields); - } - } - - /// - /// Generates a parameters constructor that initializes the proxy - /// state with just to make it non-null. - /// - /// This constructor is important to allow proxies to be XML serializable - /// - /// - protected void GenerateParameterlessConstructor(ClassEmitter emitter, Type baseClass, FieldReference interceptorField) - { - // Check if the type actually has a default constructor - var defaultConstructor = baseClass.GetConstructor(BindingFlags.Public | BindingFlags.Instance, null, Type.EmptyTypes, - null); - - if (defaultConstructor == null) - { - defaultConstructor = baseClass.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, Type.EmptyTypes, - null); - - if (defaultConstructor == null || defaultConstructor.IsPrivate) - { - return; - } - } - - var constructor = emitter.CreateConstructor(); - - // initialize fields with an empty interceptor - - constructor.CodeBuilder.AddStatement(new AssignStatement(interceptorField, - new NewArrayExpression(1, typeof(IInterceptor)))); - constructor.CodeBuilder.AddStatement( - new AssignArrayStatement(interceptorField, 0, new NewInstanceExpression(typeof(StandardInterceptor)))); - - // Invoke base constructor - - constructor.CodeBuilder.AddStatement(new ConstructorInvocationStatement(defaultConstructor)); - - constructor.CodeBuilder.AddStatement(new ReturnStatement()); - } - - protected ConstructorEmitter GenerateStaticConstructor(ClassEmitter emitter) - { - return emitter.CreateTypeConstructor(); - } - - protected void HandleExplicitlyPassedProxyTargetAccessor(ICollection targetInterfaces) - { - var interfaceName = typeof(IProxyTargetAccessor).ToString(); - //ok, let's determine who tried to sneak the IProxyTargetAccessor in... - string message; - if (targetInterfaces.Contains(typeof(IProxyTargetAccessor))) - { - message = - string.Format( - "Target type for the proxy implements {0} which is a DynamicProxy infrastructure interface and you should never implement it yourself. Are you trying to proxy an existing proxy?", - interfaceName); - throw new InvalidOperationException("This is a DynamicProxy2 error: " + message); - } - else if (ProxyGenerationOptions.MixinData.ContainsMixin(typeof(IProxyTargetAccessor))) - { - var mixinType = ProxyGenerationOptions.MixinData.GetMixinInstance(typeof(IProxyTargetAccessor)).GetType(); - message = - string.Format( - "Mixin type {0} implements {1} which is a DynamicProxy infrastructure interface and you should never implement it yourself. Are you trying to mix in an existing proxy?", - mixinType.Name, interfaceName); - throw new InvalidOperationException("This is a DynamicProxy2 error: " + message); - } - else if (interfaces.Contains(typeof(IProxyTargetAccessor))) - { - message = - string.Format( - "You passed {0} as one of additional interfaces to proxy which is a DynamicProxy infrastructure interface and is implemented by every proxy anyway. Please remove it from the list of additional interfaces to proxy.", - interfaceName); - throw new InvalidOperationException("This is a DynamicProxy2 error: " + message); - } - else - { - // this can technically never happen - message = string.Format("It looks like we have a bug with regards to how we handle {0}. Please report it.", - interfaceName); - throw new DynamicProxyException(message); - } - } - - protected void InitializeStaticFields(Type builtType) - { - builtType.SetStaticField("proxyGenerationOptions", BindingFlags.NonPublic, ProxyGenerationOptions); - } - - private bool OverridesEqualsAndGetHashCode(Type type) - { - var equalsMethod = type.GetMethod("Equals", BindingFlags.Public | BindingFlags.Instance); - if (equalsMethod == null || equalsMethod.DeclaringType == typeof(object) || equalsMethod.IsAbstract) - { - return false; - } - - var getHashCodeMethod = type.GetMethod("GetHashCode", BindingFlags.Public | BindingFlags.Instance); - if (getHashCodeMethod == null || getHashCodeMethod.DeclaringType == typeof(object) || getHashCodeMethod.IsAbstract) - { - return false; - } - - return true; - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/CacheKey.cs b/Castle.Core/DynamicProxy/Generators/CacheKey.cs deleted file mode 100644 index d0a98b8..0000000 --- a/Castle.Core/DynamicProxy/Generators/CacheKey.cs +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators -{ - using System; - using System.Reflection; - -#if FEATURE_SERIALIZATION - [Serializable] -#endif - internal class CacheKey - { - private readonly MemberInfo target; - private readonly Type[] interfaces; - private readonly ProxyGenerationOptions options; - private readonly Type type; - - /// - /// Initializes a new instance of the class. - /// - /// Target element. This is either target type or target method for invocation types. - /// The type of the proxy. This is base type for invocation types. - /// The interfaces. - /// The options. - public CacheKey(MemberInfo target, Type type, Type[] interfaces, ProxyGenerationOptions options) - { - this.target = target; - this.type = type; - this.interfaces = interfaces ?? Type.EmptyTypes; - this.options = options; - } - - /// - /// Initializes a new instance of the class. - /// - /// Type of the target. - /// The interfaces. - /// The options. - public CacheKey(Type target, Type[] interfaces, ProxyGenerationOptions options) - : this(target, null, interfaces, options) - { - } - - public override int GetHashCode() - { - var result = target.GetHashCode(); - foreach (var inter in interfaces) - { - result = 29*result + inter.GetHashCode(); - } - if (options != null) - { - result = 29*result + options.GetHashCode(); - } - if (type != null) - { - result = 29*result + type.GetHashCode(); - } - return result; - } - - public override bool Equals(object obj) - { - if (this == obj) - { - return true; - } - - var cacheKey = obj as CacheKey; - if (cacheKey == null) - { - return false; - } - - if (!Equals(type, cacheKey.type)) - { - return false; - } - if (!Equals(target, cacheKey.target)) - { - return false; - } - if (interfaces.Length != cacheKey.interfaces.Length) - { - return false; - } - for (var i = 0; i < interfaces.Length; i++) - { - if (!Equals(interfaces[i], cacheKey.interfaces[i])) - { - return false; - } - } - if (!Equals(options, cacheKey.options)) - { - return false; - } - return true; - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/ClassProxyGenerator.cs b/Castle.Core/DynamicProxy/Generators/ClassProxyGenerator.cs deleted file mode 100644 index 7d713f1..0000000 --- a/Castle.Core/DynamicProxy/Generators/ClassProxyGenerator.cs +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators -{ - using System; - using System.Collections.Generic; - using System.Reflection; - - using Castle.DynamicProxy.Contributors; - using Castle.DynamicProxy.Generators.Emitters.SimpleAST; - using Castle.DynamicProxy.Serialization; - - internal sealed class ClassProxyGenerator : BaseClassProxyGenerator - { - public ClassProxyGenerator(ModuleScope scope, Type targetType, Type[] interfaces, ProxyGenerationOptions options) - : base(scope, targetType, interfaces, options) - { - } - - protected override FieldReference TargetField => null; - - protected override CacheKey GetCacheKey() - { - return new CacheKey(targetType, interfaces, ProxyGenerationOptions); - } - -#if FEATURE_SERIALIZATION - protected override SerializableContributor GetSerializableContributor() - { - return new ClassProxySerializableContributor(targetType, interfaces, ProxyTypeConstants.Class); - } -#endif - - protected override CompositeTypeContributor GetProxyTargetContributor(INamingScope namingScope) - { - return new ClassProxyTargetContributor(targetType, namingScope) { Logger = Logger }; - } - - protected override ProxyTargetAccessorContributor GetProxyTargetAccessorContributor() - { - return new ProxyTargetAccessorContributor( - getTargetReference: () => SelfReference.Self, - targetType); - } - } -} diff --git a/Castle.Core/DynamicProxy/Generators/ClassProxyWithTargetGenerator.cs b/Castle.Core/DynamicProxy/Generators/ClassProxyWithTargetGenerator.cs deleted file mode 100644 index c7f6fe6..0000000 --- a/Castle.Core/DynamicProxy/Generators/ClassProxyWithTargetGenerator.cs +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators -{ - using System; - using System.Collections.Generic; - using System.Reflection; - -#if FEATURE_SERIALIZATION - using System.Xml.Serialization; -#endif - - using Castle.DynamicProxy.Contributors; - using Castle.DynamicProxy.Generators.Emitters; - using Castle.DynamicProxy.Generators.Emitters.SimpleAST; - using Castle.DynamicProxy.Serialization; - - internal sealed class ClassProxyWithTargetGenerator : BaseClassProxyGenerator - { - private FieldReference targetField; - - public ClassProxyWithTargetGenerator(ModuleScope scope, Type targetType, Type[] interfaces, - ProxyGenerationOptions options) - : base(scope, targetType, interfaces, options) - { - } - - protected override FieldReference TargetField => targetField; - - protected override CacheKey GetCacheKey() - { - return new CacheKey(targetType, targetType, interfaces, ProxyGenerationOptions); - } - - protected override void CreateFields(ClassEmitter emitter) - { - base.CreateFields(emitter); - CreateTargetField(emitter); - } - -#if FEATURE_SERIALIZATION - protected override SerializableContributor GetSerializableContributor() - { - return new ClassProxySerializableContributor(targetType, interfaces, ProxyTypeConstants.ClassWithTarget); - } -#endif - - protected override CompositeTypeContributor GetProxyTargetContributor(INamingScope namingScope) - { - return new ClassProxyWithTargetTargetContributor(targetType, namingScope) { Logger = Logger }; - } - - protected override ProxyTargetAccessorContributor GetProxyTargetAccessorContributor() - { - return new ProxyTargetAccessorContributor( - getTargetReference: () => targetField, - targetType); - } - - private void CreateTargetField(ClassEmitter emitter) - { - targetField = emitter.CreateField("__target", targetType); -#if FEATURE_SERIALIZATION - emitter.DefineCustomAttributeFor(targetField); -#endif - } - } -} diff --git a/Castle.Core/DynamicProxy/Generators/CompositionInvocationTypeGenerator.cs b/Castle.Core/DynamicProxy/Generators/CompositionInvocationTypeGenerator.cs deleted file mode 100644 index 7222725..0000000 --- a/Castle.Core/DynamicProxy/Generators/CompositionInvocationTypeGenerator.cs +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators -{ - using System; - using System.Reflection; - - using Castle.DynamicProxy.Contributors; - using Castle.DynamicProxy.Generators.Emitters; - using Castle.DynamicProxy.Generators.Emitters.SimpleAST; - using Castle.DynamicProxy.Internal; - using Castle.DynamicProxy.Tokens; - - internal class CompositionInvocationTypeGenerator : InvocationTypeGenerator - { - public static readonly Type BaseType = typeof(CompositionInvocation); - - public CompositionInvocationTypeGenerator(Type target, MetaMethod method, MethodInfo callback, bool canChangeTarget, - IInvocationCreationContributor contributor) - : base(target, method, callback, canChangeTarget, contributor) - { - } - - protected override ArgumentReference[] GetBaseCtorArguments(Type targetFieldType, - out ConstructorInfo baseConstructor) - { - baseConstructor = InvocationMethods.CompositionInvocationConstructor; - return new[] - { - new ArgumentReference(targetFieldType), - new ArgumentReference(typeof(object)), - new ArgumentReference(typeof(IInterceptor[])), - new ArgumentReference(typeof(MethodInfo)), - new ArgumentReference(typeof(object[])), - }; - } - - protected override Type GetBaseType() - { - return BaseType; - } - - protected override FieldReference GetTargetReference() - { - return new FieldReference(InvocationMethods.CompositionInvocationTarget); - } - - protected override void ImplementInvokeMethodOnTarget(AbstractTypeEmitter invocation, ParameterInfo[] parameters, - MethodEmitter invokeMethodOnTarget, Reference targetField) - { - invokeMethodOnTarget.CodeBuilder.AddStatement( - new MethodInvocationExpression( - SelfReference.Self, - InvocationMethods.CompositionInvocationEnsureValidTarget)); - - base.ImplementInvokeMethodOnTarget(invocation, parameters, invokeMethodOnTarget, targetField); - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/DelegateTypeGenerator.cs b/Castle.Core/DynamicProxy/Generators/DelegateTypeGenerator.cs deleted file mode 100644 index 8efd6d4..0000000 --- a/Castle.Core/DynamicProxy/Generators/DelegateTypeGenerator.cs +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators -{ - using System; - using System.Reflection; - - using Castle.DynamicProxy.Generators.Emitters; - using Castle.DynamicProxy.Generators.Emitters.SimpleAST; - using Castle.DynamicProxy.Internal; - - internal class DelegateTypeGenerator : IGenerator - { - private const TypeAttributes DelegateFlags = TypeAttributes.Class | - TypeAttributes.Public | - TypeAttributes.Sealed | - TypeAttributes.AnsiClass | - TypeAttributes.AutoClass; - - private readonly MetaMethod method; - private readonly Type targetType; - - public DelegateTypeGenerator(MetaMethod method, Type targetType) - { - this.method = method; - this.targetType = targetType; - } - - public AbstractTypeEmitter Generate(ClassEmitter @class, INamingScope namingScope) - { - var emitter = GetEmitter(@class, namingScope); - BuildConstructor(emitter); - BuildInvokeMethod(emitter); - return emitter; - } - - private void BuildConstructor(AbstractTypeEmitter emitter) - { - var constructor = emitter.CreateConstructor(new ArgumentReference(typeof(object)), - new ArgumentReference(typeof(IntPtr))); - constructor.ConstructorBuilder.SetImplementationFlags(MethodImplAttributes.Runtime | MethodImplAttributes.Managed); - } - - private void BuildInvokeMethod(AbstractTypeEmitter @delegate) - { - var paramTypes = GetParamTypes(@delegate); - var invoke = @delegate.CreateMethod("Invoke", - MethodAttributes.Public | - MethodAttributes.HideBySig | - MethodAttributes.NewSlot | - MethodAttributes.Virtual, - @delegate.GetClosedParameterType(method.MethodOnTarget.ReturnType), - paramTypes); - invoke.MethodBuilder.SetImplementationFlags(MethodImplAttributes.Runtime | MethodImplAttributes.Managed); - } - - private AbstractTypeEmitter GetEmitter(ClassEmitter @class, INamingScope namingScope) - { - var methodInfo = method.MethodOnTarget; - var suggestedName = string.Format("Castle.Proxies.Delegates.{0}_{1}", - methodInfo.DeclaringType.Name, - method.Method.Name); - var uniqueName = namingScope.ParentScope.GetUniqueName(suggestedName); - - var @delegate = new ClassEmitter(@class.ModuleScope, - uniqueName, - typeof(MulticastDelegate), - Type.EmptyTypes, - DelegateFlags, - forceUnsigned: @class.InStrongNamedModule == false); - @delegate.CopyGenericParametersFromMethod(method.Method); - return @delegate; - } - - private Type[] GetParamTypes(AbstractTypeEmitter @delegate) - { - var parameters = method.MethodOnTarget.GetParameters(); - if (@delegate.TypeBuilder.IsGenericType) - { - var types = new Type[parameters.Length]; - - for (var i = 0; i < parameters.Length; i++) - { - types[i] = @delegate.GetClosedParameterType(parameters[i].ParameterType); - } - return types; - } - var paramTypes = new Type[parameters.Length + 1]; - paramTypes[0] = targetType; - for (var i = 0; i < parameters.Length; i++) - { - paramTypes[i + 1] = @delegate.GetClosedParameterType(parameters[i].ParameterType); - } - return paramTypes; - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/AbstractTypeEmitter.cs b/Castle.Core/DynamicProxy/Generators/Emitters/AbstractTypeEmitter.cs deleted file mode 100644 index 43b7958..0000000 --- a/Castle.Core/DynamicProxy/Generators/Emitters/AbstractTypeEmitter.cs +++ /dev/null @@ -1,374 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators.Emitters -{ - using System; - using System.Collections.Generic; - using System.Diagnostics; - using System.Reflection; - using System.Reflection.Emit; - - using Castle.DynamicProxy.Generators.Emitters.SimpleAST; - using Castle.DynamicProxy.Internal; - - internal abstract class AbstractTypeEmitter - { - private const MethodAttributes defaultAttributes = - MethodAttributes.HideBySig | MethodAttributes.Virtual | MethodAttributes.Public; - - private readonly List constructors; - private readonly List events; - - private readonly IDictionary fields = - new Dictionary(StringComparer.OrdinalIgnoreCase); - - private readonly List methods; - - private readonly List nested; - private readonly List properties; - private readonly TypeBuilder typebuilder; - - private GenericTypeParameterBuilder[] genericTypeParams; - - protected AbstractTypeEmitter(TypeBuilder typeBuilder) - { - typebuilder = typeBuilder; - nested = new List(); - methods = new List(); - constructors = new List(); - properties = new List(); - events = new List(); - } - - public Type BaseType - { - get - { - if (TypeBuilder.IsInterface) - { - throw new InvalidOperationException("This emitter represents an interface; interfaces have no base types."); - } - return TypeBuilder.BaseType; - } - } - - public TypeConstructorEmitter ClassConstructor { get; private set; } - - public GenericTypeParameterBuilder[] GenericTypeParams - { - get { return genericTypeParams; } - } - - public TypeBuilder TypeBuilder - { - get { return typebuilder; } - } - - public void AddCustomAttributes(IEnumerable additionalAttributes) - { - foreach (var attribute in additionalAttributes) - { - typebuilder.SetCustomAttribute(attribute.Builder); - } - } - - public void AddNestedClass(NestedClassEmitter nestedClass) - { - nested.Add(nestedClass); - } - - public virtual Type BuildType() - { - EnsureBuildersAreInAValidState(); - - var type = CreateType(typebuilder); - - foreach (var builder in nested) - { - builder.BuildType(); - } - - return type; - } - - public void CopyGenericParametersFromMethod(MethodInfo methodToCopyGenericsFrom) - { - // big sanity check - if (genericTypeParams != null) - { - throw new InvalidOperationException("Cannot invoke me twice"); - } - - SetGenericTypeParameters(GenericUtil.CopyGenericArguments(methodToCopyGenericsFrom, typebuilder)); - } - - public ConstructorEmitter CreateConstructor(params ArgumentReference[] arguments) - { - if (TypeBuilder.IsInterface) - { - throw new InvalidOperationException("Interfaces cannot have constructors."); - } - - var member = new ConstructorEmitter(this, arguments); - constructors.Add(member); - return member; - } - - public void CreateDefaultConstructor() - { - if (TypeBuilder.IsInterface) - { - throw new InvalidOperationException("Interfaces cannot have constructors."); - } - - constructors.Add(new ConstructorEmitter(this)); - } - - public EventEmitter CreateEvent(string name, EventAttributes atts, Type type) - { - var eventEmitter = new EventEmitter(this, name, atts, type); - events.Add(eventEmitter); - return eventEmitter; - } - - public FieldReference CreateField(string name, Type fieldType) - { - return CreateField(name, fieldType, true); - } - - public FieldReference CreateField(string name, Type fieldType, bool serializable) - { - var atts = FieldAttributes.Private; - - if (!serializable) - { - atts |= FieldAttributes.NotSerialized; - } - - return CreateField(name, fieldType, atts); - } - - public FieldReference CreateField(string name, Type fieldType, FieldAttributes atts) - { - var fieldBuilder = typebuilder.DefineField(name, fieldType, atts); - var reference = new FieldReference(fieldBuilder); - fields[name] = reference; - return reference; - } - - public MethodEmitter CreateMethod(string name, MethodAttributes attrs, Type returnType, params Type[] argumentTypes) - { - var member = new MethodEmitter(this, name, attrs, returnType, argumentTypes ?? Type.EmptyTypes); - methods.Add(member); - return member; - } - - public MethodEmitter CreateMethod(string name, Type returnType, params Type[] parameterTypes) - { - return CreateMethod(name, defaultAttributes, returnType, parameterTypes); - } - - public MethodEmitter CreateMethod(string name, MethodInfo methodToUseAsATemplate) - { - return CreateMethod(name, defaultAttributes, methodToUseAsATemplate); - } - - public MethodEmitter CreateMethod(string name, MethodAttributes attributes, MethodInfo methodToUseAsATemplate) - { - var method = new MethodEmitter(this, name, attributes, methodToUseAsATemplate); - methods.Add(method); - return method; - } - - public PropertyEmitter CreateProperty(string name, PropertyAttributes attributes, Type propertyType, Type[] arguments) - { - var propEmitter = new PropertyEmitter(this, name, attributes, propertyType, arguments); - properties.Add(propEmitter); - return propEmitter; - } - - public FieldReference CreateStaticField(string name, Type fieldType) - { - return CreateStaticField(name, fieldType, FieldAttributes.Private); - } - - public FieldReference CreateStaticField(string name, Type fieldType, FieldAttributes atts) - { - atts |= FieldAttributes.Static; - return CreateField(name, fieldType, atts); - } - - public ConstructorEmitter CreateTypeConstructor() - { - var member = new TypeConstructorEmitter(this); - constructors.Add(member); - ClassConstructor = member; - return member; - } - - public void DefineCustomAttribute(CustomAttributeBuilder attribute) - { - typebuilder.SetCustomAttribute(attribute); - } - - public void DefineCustomAttribute(object[] constructorArguments) where TAttribute : Attribute - { - var customAttributeInfo = AttributeUtil.CreateInfo(typeof(TAttribute), constructorArguments); - typebuilder.SetCustomAttribute(customAttributeInfo.Builder); - } - - public void DefineCustomAttribute() where TAttribute : Attribute, new() - { - var customAttributeInfo = AttributeUtil.CreateInfo(); - typebuilder.SetCustomAttribute(customAttributeInfo.Builder); - } - - public void DefineCustomAttributeFor(FieldReference field) where TAttribute : Attribute, new() - { - var customAttributeInfo = AttributeUtil.CreateInfo(); - var fieldbuilder = field.Fieldbuilder; - if (fieldbuilder == null) - { - throw new ArgumentException( - "Invalid field reference.This reference does not point to field on type being generated", nameof(field)); - } - fieldbuilder.SetCustomAttribute(customAttributeInfo.Builder); - } - - public IEnumerable GetAllFields() - { - return fields.Values; - } - - public FieldReference GetField(string name) - { - if (string.IsNullOrEmpty(name)) - { - return null; - } - - FieldReference value; - fields.TryGetValue(name, out value); - return value; - } - - public Type GetClosedParameterType(Type parameter) - { - if (parameter.IsGenericType) - { - // ECMA-335 section II.9.4: "The CLI does not support partial instantiation - // of generic types. And generic types shall not appear uninstantiated any- - // where in metadata signature blobs." (And parameters are defined there!) - Debug.Assert(parameter.IsGenericTypeDefinition == false); - - var arguments = parameter.GetGenericArguments(); - if (CloseGenericParametersIfAny(arguments)) - { - return parameter.GetGenericTypeDefinition().MakeGenericType(arguments); - } - } - - if (parameter.IsGenericParameter) - { - return GetGenericArgument(parameter.GenericParameterPosition); - } - - if (parameter.IsArray) - { - var elementType = GetClosedParameterType(parameter.GetElementType()); - int rank = parameter.GetArrayRank(); - return rank == 1 - ? elementType.MakeArrayType() - : elementType.MakeArrayType(rank); - } - - if (parameter.IsByRef) - { - var elementType = GetClosedParameterType(parameter.GetElementType()); - return elementType.MakeByRefType(); - } - - return parameter; - - bool CloseGenericParametersIfAny(Type[] arguments) - { - var hasAnyGenericParameters = false; - for (var i = 0; i < arguments.Length; i++) - { - var newType = GetClosedParameterType(arguments[i]); - if (newType != null && !ReferenceEquals(newType, arguments[i])) - { - arguments[i] = newType; - hasAnyGenericParameters = true; - } - } - return hasAnyGenericParameters; - } - } - - public Type GetGenericArgument(int position) - { - Debug.Assert(0 <= position && position < genericTypeParams.Length); - - return genericTypeParams[position]; - } - - public Type[] GetGenericArgumentsFor(MethodInfo genericMethod) - { - Debug.Assert(genericMethod.GetGenericArguments().Length == genericTypeParams.Length); - - return genericTypeParams; - } - - public void SetGenericTypeParameters(GenericTypeParameterBuilder[] genericTypeParameterBuilders) - { - genericTypeParams = genericTypeParameterBuilders; - } - - protected Type CreateType(TypeBuilder type) - { - return type.CreateTypeInfo(); - } - - protected virtual void EnsureBuildersAreInAValidState() - { - if (!typebuilder.IsInterface && constructors.Count == 0) - { - CreateDefaultConstructor(); - } - - foreach (IMemberEmitter builder in properties) - { - builder.EnsureValidCodeBlock(); - builder.Generate(); - } - foreach (IMemberEmitter builder in events) - { - builder.EnsureValidCodeBlock(); - builder.Generate(); - } - foreach (IMemberEmitter builder in constructors) - { - builder.EnsureValidCodeBlock(); - builder.Generate(); - } - foreach (IMemberEmitter builder in methods) - { - builder.EnsureValidCodeBlock(); - builder.Generate(); - } - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/ArgumentsUtil.cs b/Castle.Core/DynamicProxy/Generators/Emitters/ArgumentsUtil.cs deleted file mode 100644 index 2e0396d..0000000 --- a/Castle.Core/DynamicProxy/Generators/Emitters/ArgumentsUtil.cs +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators.Emitters -{ - using System; - using System.Reflection; - using System.Reflection.Emit; - - using Castle.DynamicProxy.Generators.Emitters.SimpleAST; - - internal abstract class ArgumentsUtil - { - public static ArgumentReference[] ConvertToArgumentReference(Type[] args) - { - var arguments = new ArgumentReference[args.Length]; - - for (var i = 0; i < args.Length; ++i) - { - arguments[i] = new ArgumentReference(args[i]); - } - - return arguments; - } - - public static ArgumentReference[] ConvertToArgumentReference(ParameterInfo[] args) - { - var arguments = new ArgumentReference[args.Length]; - - for (var i = 0; i < args.Length; ++i) - { - arguments[i] = new ArgumentReference(args[i].ParameterType); - } - - return arguments; - } - - public static IExpression[] ConvertToArgumentReferenceExpression(ParameterInfo[] args) - { - var arguments = new IExpression[args.Length]; - - for (var i = 0; i < args.Length; ++i) - { - arguments[i] = new ArgumentReference(args[i].ParameterType, i + 1); - } - - return arguments; - } - - public static void EmitLoadOwnerAndReference(Reference reference, ILGenerator il) - { - if (reference == null) - { - return; - } - - EmitLoadOwnerAndReference(reference.OwnerReference, il); - - reference.LoadReference(il); - } - - public static Type[] GetTypes(ParameterInfo[] parameters) - { - var types = new Type[parameters.Length]; - for (var i = 0; i < parameters.Length; i++) - { - types[i] = parameters[i].ParameterType; - } - return types; - } - - public static Type[] InitializeAndConvert(ArgumentReference[] args) - { - var types = new Type[args.Length]; - - for (var i = 0; i < args.Length; ++i) - { - args[i].Position = i + 1; - types[i] = args[i].Type; - } - - return types; - } - - public static void InitializeArgumentsByPosition(ArgumentReference[] args, bool isStatic) - { - var offset = isStatic ? 0 : 1; - for (var i = 0; i < args.Length; ++i) - { - args[i].Position = i + offset; - } - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/ClassEmitter.cs b/Castle.Core/DynamicProxy/Generators/Emitters/ClassEmitter.cs deleted file mode 100644 index cb2023b..0000000 --- a/Castle.Core/DynamicProxy/Generators/Emitters/ClassEmitter.cs +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators.Emitters -{ - using System; - using System.Collections.Generic; - using System.Diagnostics; - using System.Reflection; - using System.Reflection.Emit; - - using Castle.DynamicProxy.Internal; - - internal class ClassEmitter : AbstractTypeEmitter - { - internal const TypeAttributes DefaultAttributes = - TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.Serializable; - - private readonly ModuleScope moduleScope; - - public ClassEmitter(ModuleScope modulescope, string name, Type baseType, IEnumerable interfaces) - : this(modulescope, name, baseType, interfaces, DefaultAttributes, forceUnsigned: false) - { - } - - public ClassEmitter(ModuleScope modulescope, string name, Type baseType, IEnumerable interfaces, - TypeAttributes flags, - bool forceUnsigned) - : this(CreateTypeBuilder(modulescope, name, baseType, interfaces, flags, forceUnsigned)) - { - interfaces = InitializeGenericArgumentsFromBases(ref baseType, interfaces); - - if (interfaces != null) - { - foreach (var inter in interfaces) - { - if (inter.IsInterface) - { - TypeBuilder.AddInterfaceImplementation(inter); - } - else - { - Debug.Assert(inter.IsDelegateType()); - } - } - } - - TypeBuilder.SetParent(baseType); - moduleScope = modulescope; - } - - public ClassEmitter(TypeBuilder typeBuilder) - : base(typeBuilder) - { - } - - public ModuleScope ModuleScope - { - get { return moduleScope; } - } - - internal bool InStrongNamedModule - { - get { return StrongNameUtil.IsAssemblySigned(TypeBuilder.Assembly); } - } - - protected virtual IEnumerable InitializeGenericArgumentsFromBases(ref Type baseType, - IEnumerable interfaces) - { - if (baseType != null && baseType.IsGenericTypeDefinition) - { - throw new NotSupportedException("ClassEmitter does not support open generic base types. Type: " + baseType.FullName); - } - - if (interfaces == null) - { - return interfaces; - } - - foreach (var inter in interfaces) - { - if (inter.IsGenericTypeDefinition) - { - throw new NotSupportedException("ClassEmitter does not support open generic interfaces. Type: " + inter.FullName); - } - } - return interfaces; - } - - private static TypeBuilder CreateTypeBuilder(ModuleScope modulescope, string name, Type baseType, - IEnumerable interfaces, - TypeAttributes flags, bool forceUnsigned) - { - var isAssemblySigned = !forceUnsigned && !StrongNameUtil.IsAnyTypeFromUnsignedAssembly(baseType, interfaces); - return modulescope.DefineType(isAssemblySigned, name, flags); - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/CodeBuilder.cs b/Castle.Core/DynamicProxy/Generators/Emitters/CodeBuilder.cs deleted file mode 100644 index 606e975..0000000 --- a/Castle.Core/DynamicProxy/Generators/Emitters/CodeBuilder.cs +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators.Emitters -{ - using System; - using System.Collections.Generic; - using System.Reflection.Emit; - - using Castle.DynamicProxy.Generators.Emitters.SimpleAST; - - internal sealed class CodeBuilder - { - private readonly List locals; - private readonly List statements; - private bool isEmpty; - - public CodeBuilder() - { - statements = new List(); - locals = new List(); - isEmpty = true; - } - - internal bool IsEmpty - { - get { return isEmpty; } - } - - public CodeBuilder AddStatement(IStatement statement) - { - isEmpty = false; - statements.Add(statement); - return this; - } - - public LocalReference DeclareLocal(Type type) - { - var local = new LocalReference(type); - locals.Add(local); - return local; - } - - internal void Generate(ILGenerator il) - { - foreach (var local in locals) - { - local.Generate(il); - } - - foreach (var statement in statements) - { - statement.Emit(il); - } - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/ConstructorEmitter.cs b/Castle.Core/DynamicProxy/Generators/Emitters/ConstructorEmitter.cs deleted file mode 100644 index 37ab582..0000000 --- a/Castle.Core/DynamicProxy/Generators/Emitters/ConstructorEmitter.cs +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators.Emitters -{ - using System; - using System.Reflection; - using System.Reflection.Emit; - - using Castle.DynamicProxy.Generators.Emitters.SimpleAST; - - internal class ConstructorEmitter : IMemberEmitter - { - private readonly ConstructorBuilder builder; - private readonly CodeBuilder codeBuilder; - private readonly AbstractTypeEmitter maintype; - - protected internal ConstructorEmitter(AbstractTypeEmitter maintype, ConstructorBuilder builder) - { - this.maintype = maintype; - this.builder = builder; - codeBuilder = new CodeBuilder(); - } - - internal ConstructorEmitter(AbstractTypeEmitter maintype, params ArgumentReference[] arguments) - { - this.maintype = maintype; - - var args = ArgumentsUtil.InitializeAndConvert(arguments); - - builder = maintype.TypeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, args); - codeBuilder = new CodeBuilder(); - } - - public CodeBuilder CodeBuilder - { - get { return codeBuilder; } - } - - public ConstructorBuilder ConstructorBuilder - { - get { return builder; } - } - - public MemberInfo Member - { - get { return builder; } - } - - public Type ReturnType - { - get { return typeof(void); } - } - - private bool ImplementedByRuntime - { - get - { - var attributes = builder.MethodImplementationFlags; - return (attributes & MethodImplAttributes.Runtime) != 0; - } - } - - public virtual void EnsureValidCodeBlock() - { - if (ImplementedByRuntime == false && CodeBuilder.IsEmpty) - { - CodeBuilder.AddStatement(new ConstructorInvocationStatement(maintype.BaseType)); - CodeBuilder.AddStatement(new ReturnStatement()); - } - } - - public virtual void Generate() - { - if (ImplementedByRuntime) - { - return; - } - - CodeBuilder.Generate(builder.GetILGenerator()); - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/EventEmitter.cs b/Castle.Core/DynamicProxy/Generators/Emitters/EventEmitter.cs deleted file mode 100644 index 08ad72e..0000000 --- a/Castle.Core/DynamicProxy/Generators/Emitters/EventEmitter.cs +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators.Emitters -{ - using System; - using System.Reflection; - using System.Reflection.Emit; - - internal class EventEmitter : IMemberEmitter - { - private readonly EventBuilder eventBuilder; - private readonly Type type; - private readonly AbstractTypeEmitter typeEmitter; - private MethodEmitter addMethod; - private MethodEmitter removeMethod; - - public EventEmitter(AbstractTypeEmitter typeEmitter, string name, EventAttributes attributes, Type type) - { - if (name == null) - { - throw new ArgumentNullException(nameof(name)); - } - if (type == null) - { - throw new ArgumentNullException(nameof(type)); - } - this.typeEmitter = typeEmitter; - this.type = type; - eventBuilder = typeEmitter.TypeBuilder.DefineEvent(name, attributes, type); - } - - public MemberInfo Member - { - get { return null; } - } - - public Type ReturnType - { - get { return type; } - } - - public MethodEmitter CreateAddMethod(string addMethodName, MethodAttributes attributes, MethodInfo methodToOverride) - { - if (addMethod != null) - { - throw new InvalidOperationException("An add method exists"); - } - - addMethod = new MethodEmitter(typeEmitter, addMethodName, attributes, methodToOverride); - return addMethod; - } - - public MethodEmitter CreateRemoveMethod(string removeMethodName, MethodAttributes attributes, - MethodInfo methodToOverride) - { - if (removeMethod != null) - { - throw new InvalidOperationException("A remove method exists"); - } - removeMethod = new MethodEmitter(typeEmitter, removeMethodName, attributes, methodToOverride); - return removeMethod; - } - - public void EnsureValidCodeBlock() - { - addMethod.EnsureValidCodeBlock(); - removeMethod.EnsureValidCodeBlock(); - } - - public void Generate() - { - if (addMethod == null) - { - throw new InvalidOperationException("Event add method was not created"); - } - if (removeMethod == null) - { - throw new InvalidOperationException("Event remove method was not created"); - } - addMethod.Generate(); - eventBuilder.SetAddOnMethod(addMethod.MethodBuilder); - - removeMethod.Generate(); - eventBuilder.SetRemoveOnMethod(removeMethod.MethodBuilder); - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/GenericUtil.cs b/Castle.Core/DynamicProxy/Generators/Emitters/GenericUtil.cs deleted file mode 100644 index 458ce77..0000000 --- a/Castle.Core/DynamicProxy/Generators/Emitters/GenericUtil.cs +++ /dev/null @@ -1,160 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators.Emitters -{ - using System; - using System.Diagnostics; - using System.Reflection; - using System.Reflection.Emit; - - using Castle.Core.Internal; - using Castle.DynamicProxy.Internal; - - internal delegate GenericTypeParameterBuilder[] ApplyGenArgs(string[] argumentNames); - - internal class GenericUtil - { - public static GenericTypeParameterBuilder[] CopyGenericArguments( - MethodInfo methodToCopyGenericsFrom, - TypeBuilder builder) - { - return CopyGenericArguments(methodToCopyGenericsFrom, builder.DefineGenericParameters); - } - - public static GenericTypeParameterBuilder[] CopyGenericArguments( - MethodInfo methodToCopyGenericsFrom, - MethodBuilder builder) - { - return CopyGenericArguments(methodToCopyGenericsFrom, builder.DefineGenericParameters); - } - - private static Type AdjustConstraintToNewGenericParameters( - Type constraint, MethodInfo methodToCopyGenericsFrom, Type[] originalGenericParameters, - GenericTypeParameterBuilder[] newGenericParameters) - { - if (constraint.IsGenericType) - { - var genericArgumentsOfConstraint = constraint.GetGenericArguments(); - - for (var i = 0; i < genericArgumentsOfConstraint.Length; ++i) - { - genericArgumentsOfConstraint[i] = - AdjustConstraintToNewGenericParameters(genericArgumentsOfConstraint[i], methodToCopyGenericsFrom, - originalGenericParameters, newGenericParameters); - } - return constraint.GetGenericTypeDefinition().MakeGenericType(genericArgumentsOfConstraint); - } - else if (constraint.IsGenericParameter) - { - // Determine the source of the parameter - if (constraint.DeclaringMethod != null) - { - // constraint comes from the method - var index = Array.IndexOf(originalGenericParameters, constraint); - Trace.Assert(index != -1, - "When a generic method parameter has a constraint on another method parameter, both parameters must be declared on the same method."); - return newGenericParameters[index]; - } - else // parameter from surrounding type - { - Trace.Assert(constraint.DeclaringType.IsGenericTypeDefinition); - Trace.Assert(methodToCopyGenericsFrom.DeclaringType.IsGenericType - && constraint.DeclaringType == methodToCopyGenericsFrom.DeclaringType.GetGenericTypeDefinition(), - "When a generic method parameter has a constraint on a generic type parameter, the generic type must be the declaring typer of the method."); - - var index = Array.IndexOf(constraint.DeclaringType.GetGenericArguments(), constraint); - Trace.Assert(index != -1, "The generic parameter comes from the given type."); - return methodToCopyGenericsFrom.DeclaringType.GetGenericArguments()[index]; // these are the actual, concrete types - } - } - else - { - return constraint; - } - } - - private static Type[] AdjustGenericConstraints(MethodInfo methodToCopyGenericsFrom, - GenericTypeParameterBuilder[] newGenericParameters, - Type[] originalGenericArguments, - Type[] constraints) - { - // HACK: the mono runtime has a strange bug where assigning to the constraints - // parameter and returning it throws, so we'll create a new array. - // System.ArrayTypeMismatchException : Source array type cannot be assigned to destination array type. - Type[] adjustedConstraints = new Type[constraints.Length]; - for (var i = 0; i < constraints.Length; i++) - { - adjustedConstraints[i] = AdjustConstraintToNewGenericParameters(constraints[i], - methodToCopyGenericsFrom, originalGenericArguments, newGenericParameters); - } - return adjustedConstraints; - } - - private static GenericTypeParameterBuilder[] CopyGenericArguments( - MethodInfo methodToCopyGenericsFrom, - ApplyGenArgs genericParameterGenerator) - { - var originalGenericArguments = methodToCopyGenericsFrom.GetGenericArguments(); - if (originalGenericArguments.Length == 0) - { - return null; - } - - var argumentNames = GetArgumentNames(originalGenericArguments); - var newGenericParameters = genericParameterGenerator(argumentNames); - - for (var i = 0; i < newGenericParameters.Length; i++) - { - try - { - var attributes = originalGenericArguments[i].GenericParameterAttributes; - newGenericParameters[i].SetGenericParameterAttributes(attributes); - var constraints = AdjustGenericConstraints(methodToCopyGenericsFrom, newGenericParameters, originalGenericArguments, originalGenericArguments[i].GetGenericParameterConstraints()); - - newGenericParameters[i].SetInterfaceConstraints(constraints); - CopyNonInheritableAttributes(newGenericParameters[i], originalGenericArguments[i]); - } - catch (NotSupportedException) - { - // Doesn't matter - - newGenericParameters[i].SetGenericParameterAttributes(GenericParameterAttributes.None); - } - } - - return newGenericParameters; - } - - private static void CopyNonInheritableAttributes(GenericTypeParameterBuilder newGenericParameter, - Type originalGenericArgument) - { - foreach (var attribute in originalGenericArgument.GetNonInheritableAttributes()) - { - newGenericParameter.SetCustomAttribute(attribute.Builder); - } - } - - private static string[] GetArgumentNames(Type[] originalGenericArguments) - { - var argumentNames = new string[originalGenericArguments.Length]; - - for (var i = 0; i < argumentNames.Length; i++) - { - argumentNames[i] = originalGenericArguments[i].Name; - } - return argumentNames; - } - } -} diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/IMemberEmitter.cs b/Castle.Core/DynamicProxy/Generators/Emitters/IMemberEmitter.cs deleted file mode 100644 index 9f6676a..0000000 --- a/Castle.Core/DynamicProxy/Generators/Emitters/IMemberEmitter.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators.Emitters -{ - using System; - using System.Reflection; - - internal interface IMemberEmitter - { - MemberInfo Member { get; } - - Type ReturnType { get; } - - void EnsureValidCodeBlock(); - - void Generate(); - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/LdcOpCodesDictionary.cs b/Castle.Core/DynamicProxy/Generators/Emitters/LdcOpCodesDictionary.cs deleted file mode 100644 index c461e73..0000000 --- a/Castle.Core/DynamicProxy/Generators/Emitters/LdcOpCodesDictionary.cs +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators.Emitters -{ - using System; - using System.Collections.Generic; - using System.Reflection.Emit; - - /// - /// Provides appropriate Ldc.X opcode for the type of primitive value to be loaded. - /// - internal sealed class LdcOpCodesDictionary : Dictionary - { - private static readonly LdcOpCodesDictionary dict = new LdcOpCodesDictionary(); - - // has to be assigned explicitly to suppress compiler warning - private static readonly OpCode emptyOpCode = new OpCode(); - - private LdcOpCodesDictionary() - { - Add(typeof(bool), OpCodes.Ldc_I4); - Add(typeof(char), OpCodes.Ldc_I4); - Add(typeof(SByte), OpCodes.Ldc_I4); - Add(typeof(Int16), OpCodes.Ldc_I4); - Add(typeof(Int32), OpCodes.Ldc_I4); - Add(typeof(Int64), OpCodes.Ldc_I8); - Add(typeof(float), OpCodes.Ldc_R4); - Add(typeof(double), OpCodes.Ldc_R8); - Add(typeof(byte), OpCodes.Ldc_I4_0); - Add(typeof(UInt16), OpCodes.Ldc_I4_0); - Add(typeof(UInt32), OpCodes.Ldc_I4_0); - Add(typeof(UInt64), OpCodes.Ldc_I4_0); - } - - public new OpCode this[Type type] - { - get - { - if (TryGetValue(type, out var opCode)) - { - return opCode; - } - return EmptyOpCode; - } - } - - public static OpCode EmptyOpCode - { - get { return emptyOpCode; } - } - - public static LdcOpCodesDictionary Instance - { - get { return dict; } - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/LdindOpCodesDictionary.cs b/Castle.Core/DynamicProxy/Generators/Emitters/LdindOpCodesDictionary.cs deleted file mode 100644 index a605fd7..0000000 --- a/Castle.Core/DynamicProxy/Generators/Emitters/LdindOpCodesDictionary.cs +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators.Emitters -{ - using System; - using System.Collections.Generic; - using System.Reflection.Emit; - - /// - /// Provides appropriate Ldind.X opcode for - /// the type of primitive value to be loaded indirectly. - /// - internal sealed class LdindOpCodesDictionary : Dictionary - { - private static readonly LdindOpCodesDictionary dict = new LdindOpCodesDictionary(); - - // has to be assigned explicitly to suppress compiler warning - private static readonly OpCode emptyOpCode = new OpCode(); - - private LdindOpCodesDictionary() - { - Add(typeof(bool), OpCodes.Ldind_I1); - Add(typeof(char), OpCodes.Ldind_I2); - Add(typeof(SByte), OpCodes.Ldind_I1); - Add(typeof(Int16), OpCodes.Ldind_I2); - Add(typeof(Int32), OpCodes.Ldind_I4); - Add(typeof(Int64), OpCodes.Ldind_I8); - Add(typeof(float), OpCodes.Ldind_R4); - Add(typeof(double), OpCodes.Ldind_R8); - Add(typeof(byte), OpCodes.Ldind_U1); - Add(typeof(UInt16), OpCodes.Ldind_U2); - Add(typeof(UInt32), OpCodes.Ldind_U4); - Add(typeof(UInt64), OpCodes.Ldind_I8); - } - - public new OpCode this[Type type] - { - get - { - if (TryGetValue(type, out var opCode)) - { - return opCode; - } - return EmptyOpCode; - } - } - - public static OpCode EmptyOpCode - { - get { return emptyOpCode; } - } - - public static LdindOpCodesDictionary Instance - { - get { return dict; } - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/MethodEmitter.cs b/Castle.Core/DynamicProxy/Generators/Emitters/MethodEmitter.cs deleted file mode 100644 index 7d2579f..0000000 --- a/Castle.Core/DynamicProxy/Generators/Emitters/MethodEmitter.cs +++ /dev/null @@ -1,350 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators.Emitters -{ - using System; - using System.Collections.Generic; - using System.Diagnostics; - using System.Globalization; - using System.Linq; - using System.Reflection; - using System.Reflection.Emit; - - using Castle.DynamicProxy.Generators.Emitters.SimpleAST; - using Castle.DynamicProxy.Internal; - - [DebuggerDisplay("{builder.Name}")] - internal class MethodEmitter : IMemberEmitter - { - private readonly MethodBuilder builder; - private readonly CodeBuilder codeBuilder; - private readonly GenericTypeParameterBuilder[] genericTypeParams; - - private ArgumentReference[] arguments; - - protected internal MethodEmitter(MethodBuilder builder) - { - this.builder = builder; - codeBuilder = new CodeBuilder(); - } - - internal MethodEmitter(AbstractTypeEmitter owner, string name, MethodAttributes attributes) - : this(owner.TypeBuilder.DefineMethod(name, attributes)) - { - } - - internal MethodEmitter(AbstractTypeEmitter owner, string name, - MethodAttributes attributes, Type returnType, - params Type[] argumentTypes) - : this(owner, name, attributes) - { - SetParameters(argumentTypes); - SetReturnType(returnType); - } - - internal MethodEmitter(AbstractTypeEmitter owner, string name, - MethodAttributes attributes, MethodInfo methodToUseAsATemplate) - : this(owner, name, attributes) - { - // All code paths leading up to this constructor can be traced back to - // proxy type generation code. At present, proxy types are never generic. - Debug.Assert(owner.GenericTypeParams == null || owner.GenericTypeParams.Length == 0); - - var returnType = methodToUseAsATemplate.ReturnType; - var baseMethodParameters = methodToUseAsATemplate.GetParameters(); - var parameters = ArgumentsUtil.GetTypes(baseMethodParameters); - - genericTypeParams = GenericUtil.CopyGenericArguments(methodToUseAsATemplate, builder); - SetParameters(parameters); - SetReturnType(returnType); - SetSignature(returnType, methodToUseAsATemplate.ReturnParameter, parameters, baseMethodParameters); - DefineParameters(baseMethodParameters); - } - - public ArgumentReference[] Arguments - { - get { return arguments; } - } - - public CodeBuilder CodeBuilder - { - get { return codeBuilder; } - } - - public GenericTypeParameterBuilder[] GenericTypeParams - { - get { return genericTypeParams; } - } - - public MethodBuilder MethodBuilder - { - get { return builder; } - } - - public MemberInfo Member - { - get { return builder; } - } - - public Type ReturnType - { - get { return builder.ReturnType; } - } - - private bool ImplementedByRuntime - { - get - { - var attributes = builder.MethodImplementationFlags; - return (attributes & MethodImplAttributes.Runtime) != 0; - } - } - - public void DefineCustomAttribute(CustomAttributeBuilder attribute) - { - builder.SetCustomAttribute(attribute); - } - - public void SetParameters(Type[] paramTypes) - { - builder.SetParameters(paramTypes); - arguments = ArgumentsUtil.ConvertToArgumentReference(paramTypes); - ArgumentsUtil.InitializeArgumentsByPosition(arguments, MethodBuilder.IsStatic); - } - - public virtual void EnsureValidCodeBlock() - { - if (ImplementedByRuntime == false && CodeBuilder.IsEmpty) - { - if (ReturnType == typeof(void)) - { - CodeBuilder.AddStatement(new ReturnStatement()); - } - else - { - CodeBuilder.AddStatement(new ReturnStatement(new DefaultValueExpression(ReturnType))); - } - } - } - - public virtual void Generate() - { - if (ImplementedByRuntime) - { - return; - } - - codeBuilder.Generate(builder.GetILGenerator()); - } - - private void DefineParameters(ParameterInfo[] parameters) - { - foreach (var parameter in parameters) - { - var parameterBuilder = builder.DefineParameter(parameter.Position + 1, parameter.Attributes, parameter.Name); - foreach (var attribute in parameter.GetNonInheritableAttributes()) - { - parameterBuilder.SetCustomAttribute(attribute.Builder); - } - - // If a parameter has a default value, that default value needs to be replicated. - // Default values as reported by `ParameterInfo.[Raw]DefaultValue` have two possible origins: - // - // 1. A `[DecimalConstant]` or `[DateTimeConstant]` custom attribute attached to the parameter. - // Attribute-based default values have already been copied above. - // (Note that another attribute type, `[DefaultParameterValue]`, only appears in source - // code. The compiler replaces it with another metadata construct:) - // - // 2. A `Constant` metadata table entry whose parent is the parameter. - // Constant-based default values need more work. We can detect this case by checking - // whether the `ParameterAttributes.HasDefault` flag is set. (NB: This is not the same - // as querying `ParameterInfo.HasDefault`, which would also return true for case (1)!) - if ((parameter.Attributes & ParameterAttributes.HasDefault) != 0) - { - try - { - CopyDefaultValueConstant(from: parameter, to: parameterBuilder); - } - catch - { - // Default value replication is a nice-to-have feature but not essential, - // so if it goes wrong for one parameter, just continue. - } - } - } - } - - private void CopyDefaultValueConstant(ParameterInfo from, ParameterBuilder to) - { - Debug.Assert(from != null); - Debug.Assert(to != null); - Debug.Assert((from.Attributes & ParameterAttributes.HasDefault) != 0); - - object defaultValue; - try - { - defaultValue = from.DefaultValue; - } - catch (FormatException) when (from.ParameterType == typeof(DateTime)) - { - // This catch clause guards against a CLR bug that makes it impossible to query - // the default value of an optional DateTime parameter. For the CoreCLR, see - // https://github.com/dotnet/corefx/issues/26164. - - // If this bug is present, it is caused by a `null` default value: - defaultValue = null; - } - catch (FormatException) when (from.ParameterType.IsEnum) - { - // This catch clause guards against a CLR bug that makes it impossible to query - // the default value of a (closed generic) enum parameter. For the CoreCLR, see - // https://github.com/dotnet/corefx/issues/29570. - - // If this bug is present, it is caused by a `null` default value: - defaultValue = null; - } - - if (defaultValue is Missing) - { - // It is likely that we are reflecting over invalid metadata if we end up here. - // At this point, `to.Attributes` will have the `HasDefault` flag set. If we do - // not call `to.SetConstant`, that flag will be reset when creating the dynamic - // type, so `to` will at least end up having valid metadata. It is quite likely - // that the `Missing.Value` will still be reproduced because the `Parameter- - // Builder`'s `ParameterAttributes.Optional` is likely set. (If it isn't set, - // we'll be causing a default value of `DBNull.Value`, but there's nothing that - // can be done about that, short of recreating a new `ParameterBuilder`.) - return; - } - - try - { - to.SetConstant(defaultValue); - } - catch (ArgumentException) - { - var parameterType = from.ParameterType; - var parameterNonNullableType = parameterType; - - if (defaultValue == null) - { - if (parameterType.IsNullableType()) - { - // This guards against a Mono bug that prohibits setting default value `null` - // for a `Nullable` parameter. See https://github.com/mono/mono/issues/8504. - // - // If this bug is present, luckily we still get `null` as the default value if - // we do nothing more (which is probably itself yet another bug, as the CLR - // would "produce" a default value of `Missing.Value` in this situation). - return; - } - else if (parameterType.IsValueType) - { - // This guards against a CLR bug that prohibits replicating `null` default - // values for non-nullable value types (which, despite the apparent type - // mismatch, is perfectly legal and something that the Roslyn compilers do). - // For the CoreCLR, see https://github.com/dotnet/corefx/issues/26184. - - // If this bug is present, the best we can do is to not set the default value. - // This will cause a default value of `Missing.Value` (if `ParameterAttributes- - // .Optional` is set) or `DBNull.Value` (otherwise, unlikely). - return; - } - } - else if (parameterType.IsNullableType()) - { - parameterNonNullableType = from.ParameterType.GetGenericArguments()[0]; - if (parameterNonNullableType.IsEnum || parameterNonNullableType.IsAssignableFrom(defaultValue.GetType())) - { - // This guards against two bugs: - // - // * On the CLR and CoreCLR, a bug that makes it impossible to use `ParameterBuilder- - // .SetConstant` on parameters of a nullable enum type. For CoreCLR, see - // https://github.com/dotnet/coreclr/issues/17893. - // - // If this bug is present, there is no way to faithfully reproduce the default - // value. This will most likely cause a default value of `Missing.Value` or - // `DBNull.Value`. (To better understand which of these, see comment above). - // - // * On Mono, a bug that performs a too-strict type check for nullable types. The - // value passed to `ParameterBuilder.SetConstant` must have a type matching that - // of the parameter precisely. See https://github.com/mono/mono/issues/8597. - // - // If this bug is present, there's no way to reproduce the default value because - // we cannot actually create a value of type `Nullable<>`. - return; - } - } - - // Finally, we might have got here because the metadata constant simply doesn't match - // the parameter type exactly. Some code generators other than the .NET compilers - // might produce such metadata. Make a final attempt to coerce it to the required type: - try - { - var coercedDefaultValue = Convert.ChangeType(defaultValue, parameterNonNullableType, CultureInfo.InvariantCulture); - to.SetConstant(coercedDefaultValue); - - return; - } - catch - { - // We don't care about the error thrown by an unsuccessful type coercion. - } - - throw; - } - } - - private void SetReturnType(Type returnType) - { - builder.SetReturnType(returnType); - } - - private void SetSignature(Type returnType, ParameterInfo returnParameter, Type[] parameters, - ParameterInfo[] baseMethodParameters) - { - Type[] returnRequiredCustomModifiers; - Type[] returnOptionalCustomModifiers; - Type[][] parametersRequiredCustomModifiers; - Type[][] parametersOptionalCustomModifiers; - - returnRequiredCustomModifiers = returnParameter.GetRequiredCustomModifiers(); - Array.Reverse(returnRequiredCustomModifiers); - - returnOptionalCustomModifiers = returnParameter.GetOptionalCustomModifiers(); - Array.Reverse(returnOptionalCustomModifiers); - - int parameterCount = baseMethodParameters.Length; - parametersRequiredCustomModifiers = new Type[parameterCount][]; - parametersOptionalCustomModifiers = new Type[parameterCount][]; - for (int i = 0; i < parameterCount; ++i) - { - parametersRequiredCustomModifiers[i] = baseMethodParameters[i].GetRequiredCustomModifiers(); - Array.Reverse(parametersRequiredCustomModifiers[i]); - - parametersOptionalCustomModifiers[i] = baseMethodParameters[i].GetOptionalCustomModifiers(); - Array.Reverse(parametersOptionalCustomModifiers[i]); - } - - builder.SetSignature( - returnType, - returnRequiredCustomModifiers, - returnOptionalCustomModifiers, - parameters, - parametersRequiredCustomModifiers, - parametersOptionalCustomModifiers); - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/NestedClassEmitter.cs b/Castle.Core/DynamicProxy/Generators/Emitters/NestedClassEmitter.cs deleted file mode 100644 index 53809e4..0000000 --- a/Castle.Core/DynamicProxy/Generators/Emitters/NestedClassEmitter.cs +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators.Emitters -{ - using System; - using System.Reflection; - using System.Reflection.Emit; - - internal class NestedClassEmitter : AbstractTypeEmitter - { - public NestedClassEmitter(AbstractTypeEmitter maintype, string name, Type baseType, Type[] interfaces) - : this( - maintype, - CreateTypeBuilder(maintype, name, TypeAttributes.Sealed | TypeAttributes.NestedPublic | TypeAttributes.Class, - baseType, interfaces)) - { - } - - public NestedClassEmitter(AbstractTypeEmitter maintype, string name, TypeAttributes attributes, Type baseType, - Type[] interfaces) - : this(maintype, CreateTypeBuilder(maintype, name, attributes, baseType, interfaces)) - { - } - - public NestedClassEmitter(AbstractTypeEmitter maintype, TypeBuilder typeBuilder) - : base(typeBuilder) - { - maintype.AddNestedClass(this); - } - - private static TypeBuilder CreateTypeBuilder(AbstractTypeEmitter maintype, string name, TypeAttributes attributes, - Type baseType, Type[] interfaces) - { - return maintype.TypeBuilder.DefineNestedType( - name, - attributes, - baseType, interfaces); - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/OpCodeUtil.cs b/Castle.Core/DynamicProxy/Generators/Emitters/OpCodeUtil.cs deleted file mode 100644 index 4b1ac75..0000000 --- a/Castle.Core/DynamicProxy/Generators/Emitters/OpCodeUtil.cs +++ /dev/null @@ -1,178 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators.Emitters -{ - using System; - using System.Reflection; - using System.Reflection.Emit; - - internal abstract class OpCodeUtil - { - /// - /// Emits a load indirect opcode of the appropriate type for a value or object reference. - /// Pops a pointer off the evaluation stack, dereferences it and loads - /// a value of the specified type. - /// - public static void EmitLoadIndirectOpCodeForType(ILGenerator gen, Type type) - { - if (type.IsEnum) - { - EmitLoadIndirectOpCodeForType(gen, GetUnderlyingTypeOfEnum(type)); - return; - } - - if (type.IsByRef) - { - throw new NotSupportedException("Cannot load ByRef values"); - } - else if (type.IsPrimitive && type != typeof(IntPtr) && type != typeof(UIntPtr)) - { - var opCode = LdindOpCodesDictionary.Instance[type]; - - if (opCode == LdindOpCodesDictionary.EmptyOpCode) - { - throw new ArgumentException("Type " + type + " could not be converted to a OpCode"); - } - - gen.Emit(opCode); - } - else if (type.IsValueType) - { - gen.Emit(OpCodes.Ldobj, type); - } - else if (type.IsGenericParameter) - { - gen.Emit(OpCodes.Ldobj, type); - } - else - { - gen.Emit(OpCodes.Ldind_Ref); - } - } - - /// - /// Emits a load opcode of the appropriate kind for the constant default value of a - /// type, such as 0 for value types and null for reference types. - /// - public static void EmitLoadOpCodeForDefaultValueOfType(ILGenerator gen, Type type) - { - if (type.IsPrimitive) - { - var opCode = LdcOpCodesDictionary.Instance[type]; - switch (opCode.StackBehaviourPush) - { - case StackBehaviour.Pushi: - gen.Emit(opCode, 0); - if (Is64BitTypeLoadedAsInt32(type)) - { - // we load Int32, and have to convert it to 64bit type - gen.Emit(OpCodes.Conv_I8); - } - break; - case StackBehaviour.Pushr8: - gen.Emit(opCode, 0D); - break; - case StackBehaviour.Pushi8: - gen.Emit(opCode, 0L); - break; - case StackBehaviour.Pushr4: - gen.Emit(opCode, 0F); - break; - default: - throw new NotSupportedException(); - } - } - else - { - gen.Emit(OpCodes.Ldnull); - } - } - - /// - /// Emits a store indirectopcode of the appropriate type for a value or object reference. - /// Pops a value of the specified type and a pointer off the evaluation stack, and - /// stores the value. - /// - public static void EmitStoreIndirectOpCodeForType(ILGenerator gen, Type type) - { - if (type.IsEnum) - { - EmitStoreIndirectOpCodeForType(gen, GetUnderlyingTypeOfEnum(type)); - return; - } - - if (type.IsByRef) - { - throw new NotSupportedException("Cannot store ByRef values"); - } - else if (type.IsPrimitive && type != typeof(IntPtr) && type != typeof(UIntPtr)) - { - var opCode = StindOpCodesDictionary.Instance[type]; - - if (Equals(opCode, StindOpCodesDictionary.EmptyOpCode)) - { - throw new ArgumentException("Type " + type + " could not be converted to a OpCode"); - } - - gen.Emit(opCode); - } - else if (type.IsValueType) - { - gen.Emit(OpCodes.Stobj, type); - } - else if (type.IsGenericParameter) - { - gen.Emit(OpCodes.Stobj, type); - } - else - { - gen.Emit(OpCodes.Stind_Ref); - } - } - - private static Type GetUnderlyingTypeOfEnum(Type enumType) - { - var baseType = (IConvertible)Activator.CreateInstance(enumType); - var code = baseType.GetTypeCode(); - - switch (code) - { - case TypeCode.SByte: - return typeof(SByte); - case TypeCode.Byte: - return typeof(Byte); - case TypeCode.Int16: - return typeof(Int16); - case TypeCode.Int32: - return typeof(Int32); - case TypeCode.Int64: - return typeof(Int64); - case TypeCode.UInt16: - return typeof(UInt16); - case TypeCode.UInt32: - return typeof(UInt32); - case TypeCode.UInt64: - return typeof(UInt64); - default: - throw new NotSupportedException(); - } - } - - private static bool Is64BitTypeLoadedAsInt32(Type type) - { - return type == typeof(long) || type == typeof(ulong); - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/PropertyEmitter.cs b/Castle.Core/DynamicProxy/Generators/Emitters/PropertyEmitter.cs deleted file mode 100644 index c2674b3..0000000 --- a/Castle.Core/DynamicProxy/Generators/Emitters/PropertyEmitter.cs +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators.Emitters -{ - using System; - using System.Reflection; - using System.Reflection.Emit; - - internal class PropertyEmitter : IMemberEmitter - { - private readonly PropertyBuilder builder; - private readonly AbstractTypeEmitter parentTypeEmitter; - private MethodEmitter getMethod; - private MethodEmitter setMethod; - - public PropertyEmitter(AbstractTypeEmitter parentTypeEmitter, string name, PropertyAttributes attributes, - Type propertyType, Type[] arguments) - { - this.parentTypeEmitter = parentTypeEmitter; - - builder = parentTypeEmitter.TypeBuilder.DefineProperty( - name, attributes, CallingConventions.HasThis, propertyType, - null, null, arguments, null, null); - } - - public MemberInfo Member - { - get { return null; } - } - - public Type ReturnType - { - get { return builder.PropertyType; } - } - - public MethodEmitter CreateGetMethod(string name, MethodAttributes attrs, MethodInfo methodToOverride, - params Type[] parameters) - { - if (getMethod != null) - { - throw new InvalidOperationException("A get method exists"); - } - - getMethod = new MethodEmitter(parentTypeEmitter, name, attrs, methodToOverride); - return getMethod; - } - - public MethodEmitter CreateGetMethod(string name, MethodAttributes attributes, MethodInfo methodToOverride) - { - return CreateGetMethod(name, attributes, methodToOverride, Type.EmptyTypes); - } - - public MethodEmitter CreateSetMethod(string name, MethodAttributes attrs, MethodInfo methodToOverride, - params Type[] parameters) - { - if (setMethod != null) - { - throw new InvalidOperationException("A set method exists"); - } - - setMethod = new MethodEmitter(parentTypeEmitter, name, attrs, methodToOverride); - return setMethod; - } - - public MethodEmitter CreateSetMethod(string name, MethodAttributes attributes, MethodInfo methodToOverride) - { - var method = CreateSetMethod(name, attributes, methodToOverride, Type.EmptyTypes); - return method; - } - - public void DefineCustomAttribute(CustomAttributeBuilder attribute) - { - builder.SetCustomAttribute(attribute); - } - - public void EnsureValidCodeBlock() - { - if (setMethod != null) - { - setMethod.EnsureValidCodeBlock(); - } - - if (getMethod != null) - { - getMethod.EnsureValidCodeBlock(); - } - } - - public void Generate() - { - if (setMethod != null) - { - setMethod.Generate(); - builder.SetSetMethod(setMethod.MethodBuilder); - } - - if (getMethod != null) - { - getMethod.Generate(); - builder.SetGetMethod(getMethod.MethodBuilder); - } - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ArgumentReference.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ArgumentReference.cs deleted file mode 100644 index 19be72d..0000000 --- a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ArgumentReference.cs +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST -{ - using System; - using System.Diagnostics; - using System.Reflection.Emit; - - [DebuggerDisplay("argument {Type}")] - internal class ArgumentReference : TypeReference - { - public ArgumentReference(Type argumentType) - : base(argumentType) - { - Position = -1; - } - - public ArgumentReference(Type argumentType, int position) - : base(argumentType) - { - Position = position; - } - - internal int Position { get; set; } - - public override void LoadAddressOfReference(ILGenerator gen) - { - throw new NotSupportedException(); - } - - public override void LoadReference(ILGenerator gen) - { - if (Position == -1) - { - throw new InvalidOperationException("ArgumentReference uninitialized"); - } - switch (Position) - { - case 0: - gen.Emit(OpCodes.Ldarg_0); - break; - case 1: - gen.Emit(OpCodes.Ldarg_1); - break; - case 2: - gen.Emit(OpCodes.Ldarg_2); - break; - case 3: - gen.Emit(OpCodes.Ldarg_3); - break; - default: - gen.Emit(OpCodes.Ldarg_S, Position); - break; - } - } - - public override void StoreReference(ILGenerator gen) - { - if (Position == -1) - { - throw new InvalidOperationException("ArgumentReference uninitialized"); - } - gen.Emit(OpCodes.Starg, Position); - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/AsTypeReference.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/AsTypeReference.cs deleted file mode 100644 index 6f0ce6c..0000000 --- a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/AsTypeReference.cs +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST -{ - using System; - using System.Diagnostics; - using System.Reflection.Emit; - - [DebuggerDisplay("{reference} as {type}")] - internal class AsTypeReference : Reference - { - private readonly Reference reference; - private readonly Type type; - - public AsTypeReference(Reference reference, Type type) - { - if (reference == null) - { - throw new ArgumentNullException(nameof(reference)); - } - if (type == null) - { - throw new ArgumentNullException(nameof(type)); - } - this.reference = reference; - this.type = type; - if (reference == OwnerReference) - { - OwnerReference = null; - } - } - - public override void LoadAddressOfReference(ILGenerator gen) - { - // NOTE: Or maybe throw new NotSupportedException() ? - reference.LoadAddressOfReference(gen); - } - - public override void LoadReference(ILGenerator gen) - { - reference.LoadReference(gen); - gen.Emit(OpCodes.Isinst, type); - } - - public override void StoreReference(ILGenerator gen) - { - // NOTE: Or maybe throw new NotSupportedException() ? - reference.StoreReference(gen); - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/AssignArgumentStatement.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/AssignArgumentStatement.cs deleted file mode 100644 index 5c4b2a7..0000000 --- a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/AssignArgumentStatement.cs +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST -{ - using System.Reflection.Emit; - - internal class AssignArgumentStatement : IStatement - { - private readonly ArgumentReference argument; - private readonly IExpression expression; - - public AssignArgumentStatement(ArgumentReference argument, IExpression expression) - { - this.argument = argument; - this.expression = expression; - } - - public void Emit(ILGenerator gen) - { - ArgumentsUtil.EmitLoadOwnerAndReference(argument, gen); - expression.Emit(gen); - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/AssignArrayStatement.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/AssignArrayStatement.cs deleted file mode 100644 index b8ea4d5..0000000 --- a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/AssignArrayStatement.cs +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST -{ - using System.Reflection.Emit; - - internal class AssignArrayStatement : IStatement - { - private readonly Reference targetArray; - private readonly int targetPosition; - private readonly IExpression value; - - public AssignArrayStatement(Reference targetArray, int targetPosition, IExpression value) - { - this.targetArray = targetArray; - this.targetPosition = targetPosition; - this.value = value; - } - - public void Emit(ILGenerator il) - { - ArgumentsUtil.EmitLoadOwnerAndReference(targetArray, il); - - il.Emit(OpCodes.Ldc_I4, targetPosition); - - value.Emit(il); - - il.Emit(OpCodes.Stelem_Ref); - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/AssignStatement.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/AssignStatement.cs deleted file mode 100644 index 4d33b78..0000000 --- a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/AssignStatement.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST -{ - using System.Reflection.Emit; - - internal class AssignStatement : IStatement - { - private readonly IExpression expression; - private readonly Reference target; - - public AssignStatement(Reference target, IExpression expression) - { - this.target = target; - this.expression = expression; - } - - public void Emit(ILGenerator gen) - { - ArgumentsUtil.EmitLoadOwnerAndReference(target.OwnerReference, gen); - expression.Emit(gen); - target.StoreReference(gen); - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/BlockStatement.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/BlockStatement.cs deleted file mode 100644 index c3526ed..0000000 --- a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/BlockStatement.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST -{ - using System.Collections.Generic; - using System.Reflection.Emit; - - internal class BlockStatement : IStatement - { - private readonly List statements = new List(); - - public void AddStatement(IStatement statement) - { - statements.Add(statement); - } - - public void Emit(ILGenerator gen) - { - foreach (var s in statements) - { - s.Emit(gen); - } - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ByRefReference.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ByRefReference.cs deleted file mode 100644 index f6fc69a..0000000 --- a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ByRefReference.cs +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST -{ - using System; - using System.Diagnostics; - using System.Reflection.Emit; - - - [DebuggerDisplay("&{localReference}")] - internal class ByRefReference : TypeReference - { - private readonly LocalReference localReference; - - public ByRefReference(LocalReference localReference) - : base(localReference.Type) - { - this.localReference = localReference; - } - - public override void LoadAddressOfReference(ILGenerator gen) - { - localReference.LoadAddressOfReference(gen); - } - - public override void LoadReference(ILGenerator gen) - { - localReference.LoadAddressOfReference(gen); - } - - public override void StoreReference(ILGenerator gen) - { - throw new NotImplementedException(); - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ConstructorInvocationStatement.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ConstructorInvocationStatement.cs deleted file mode 100644 index be9cfe6..0000000 --- a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ConstructorInvocationStatement.cs +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST -{ - using System; - using System.Reflection; - using System.Reflection.Emit; - - internal class ConstructorInvocationStatement : IStatement - { - private readonly IExpression[] args; - private readonly ConstructorInfo cmethod; - - public ConstructorInvocationStatement(Type baseType) - : this(GetDefaultConstructor(baseType)) - { - } - - public ConstructorInvocationStatement(ConstructorInfo method, params IExpression[] args) - { - if (method == null) - { - throw new ArgumentNullException(nameof(method)); - } - if (args == null) - { - throw new ArgumentNullException(nameof(args)); - } - - cmethod = method; - this.args = args; - } - - public void Emit(ILGenerator gen) - { - gen.Emit(OpCodes.Ldarg_0); - - foreach (var exp in args) - { - exp.Emit(gen); - } - - gen.Emit(OpCodes.Call, cmethod); - } - - private static ConstructorInfo GetDefaultConstructor(Type baseType) - { - var type = baseType; - if (type.ContainsGenericParameters) - { - type = type.GetGenericTypeDefinition(); - // need to get generic type definition, otherwise the GetConstructor method might throw NotSupportedException - } - - var flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; - return type.GetConstructor(flags, null, Type.EmptyTypes, null); - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ConvertExpression.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ConvertExpression.cs deleted file mode 100644 index 5e90d39..0000000 --- a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ConvertExpression.cs +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST -{ - using System; - using System.Reflection; - using System.Reflection.Emit; - - internal class ConvertExpression : IExpression - { - private readonly IExpression right; - private Type fromType; - private Type target; - - public ConvertExpression(Type targetType, IExpression right) - : this(targetType, typeof(object), right) - { - } - - public ConvertExpression(Type targetType, Type fromType, IExpression right) - { - target = targetType; - this.fromType = fromType; - this.right = right; - } - - public void Emit(ILGenerator gen) - { - right.Emit(gen); - - if (fromType == target) - { - return; - } - - if (fromType.IsByRef) - { - fromType = fromType.GetElementType(); - } - - if (target.IsByRef) - { - target = target.GetElementType(); - } - - if (target.IsValueType) - { - if (fromType.IsValueType) - { - throw new NotImplementedException("Cannot convert between distinct value types"); - } - else - { - // Unbox conversion - // Assumes fromType is a boxed value - // if we can, we emit a box and ldind, otherwise, we will use unbox.any - if (LdindOpCodesDictionary.Instance[target] != LdindOpCodesDictionary.EmptyOpCode) - { - gen.Emit(OpCodes.Unbox, target); - OpCodeUtil.EmitLoadIndirectOpCodeForType(gen, target); - } - else - { - gen.Emit(OpCodes.Unbox_Any, target); - } - } - } - else - { - if (fromType.IsValueType) - { - // Box conversion - gen.Emit(OpCodes.Box, fromType); - EmitCastIfNeeded(typeof(object), target, gen); - } - else - { - // Possible down-cast - EmitCastIfNeeded(fromType, target, gen); - } - } - } - - private static void EmitCastIfNeeded(Type from, Type target, ILGenerator gen) - { - if (target.IsGenericParameter) - { - gen.Emit(OpCodes.Unbox_Any, target); - } - else if (from.IsGenericParameter) - { - gen.Emit(OpCodes.Box, from); - } - else if (target.IsGenericType && target != from) - { - gen.Emit(OpCodes.Castclass, target); - } - else if (target.IsSubclassOf(from)) - { - gen.Emit(OpCodes.Castclass, target); - } - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/DefaultValueExpression.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/DefaultValueExpression.cs deleted file mode 100644 index c4668cf..0000000 --- a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/DefaultValueExpression.cs +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST -{ - using System; - using System.Reflection; - using System.Reflection.Emit; - - internal class DefaultValueExpression : IExpression - { - private readonly Type type; - - public DefaultValueExpression(Type type) - { - this.type = type; - } - - public void Emit(ILGenerator gen) - { - // TODO: check if this can be simplified by using more of OpCodeUtil and other existing types - if (IsPrimitiveOrClass(type)) - { - OpCodeUtil.EmitLoadOpCodeForDefaultValueOfType(gen, type); - } - else if (type.IsValueType || type.IsGenericParameter) - { - // TODO: handle decimal explicitly - var local = gen.DeclareLocal(type); - gen.Emit(OpCodes.Ldloca_S, local); - gen.Emit(OpCodes.Initobj, type); - gen.Emit(OpCodes.Ldloc, local); - } - else if (type.IsByRef) - { - EmitByRef(gen); - } - else - { - throw new NotImplementedException("Can't emit default value for type " + type); - } - } - - private void EmitByRef(ILGenerator gen) - { - var elementType = type.GetElementType(); - if (IsPrimitiveOrClass(elementType)) - { - OpCodeUtil.EmitLoadOpCodeForDefaultValueOfType(gen, elementType); - OpCodeUtil.EmitStoreIndirectOpCodeForType(gen, elementType); - } - else if (elementType.IsGenericParameter || elementType.IsValueType) - { - gen.Emit(OpCodes.Initobj, elementType); - } - else - { - throw new NotImplementedException("Can't emit default value for reference of type " + elementType); - } - } - - private bool IsPrimitiveOrClass(Type type) - { - if (type.IsPrimitive && type != typeof(IntPtr) && type != typeof(UIntPtr)) - { - return true; - } - return ((type.IsClass || type.IsInterface) && - type.IsGenericParameter == false && - type.IsByRef == false); - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/EndExceptionBlockStatement.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/EndExceptionBlockStatement.cs deleted file mode 100644 index f8b9339..0000000 --- a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/EndExceptionBlockStatement.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST -{ - using System.Reflection.Emit; - - internal class EndExceptionBlockStatement : IStatement - { - public void Emit(ILGenerator gen) - { - gen.EndExceptionBlock(); - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/FieldReference.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/FieldReference.cs deleted file mode 100644 index bdc39e6..0000000 --- a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/FieldReference.cs +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST -{ - using System.Diagnostics; - using System.Reflection; - using System.Reflection.Emit; - - [DebuggerDisplay("{fieldbuilder.Name} ({fieldbuilder.FieldType})")] - internal class FieldReference : Reference - { - private readonly FieldInfo field; - private readonly FieldBuilder fieldbuilder; - private readonly bool isStatic; - - public FieldReference(FieldInfo field) - { - this.field = field; - if ((field.Attributes & FieldAttributes.Static) != 0) - { - isStatic = true; - owner = null; - } - } - - public FieldReference(FieldBuilder fieldbuilder) - { - this.fieldbuilder = fieldbuilder; - field = fieldbuilder; - if ((fieldbuilder.Attributes & FieldAttributes.Static) != 0) - { - isStatic = true; - owner = null; - } - } - - public FieldBuilder Fieldbuilder - { - get { return fieldbuilder; } - } - - public FieldInfo Reference - { - get { return field; } - } - - public override void LoadAddressOfReference(ILGenerator gen) - { - if (isStatic) - { - gen.Emit(OpCodes.Ldsflda, Reference); - } - else - { - gen.Emit(OpCodes.Ldflda, Reference); - } - } - - public override void LoadReference(ILGenerator gen) - { - if (isStatic) - { - gen.Emit(OpCodes.Ldsfld, Reference); - } - else - { - gen.Emit(OpCodes.Ldfld, Reference); - } - } - - public override void StoreReference(ILGenerator gen) - { - if (isStatic) - { - gen.Emit(OpCodes.Stsfld, Reference); - } - else - { - gen.Emit(OpCodes.Stfld, Reference); - } - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/FinallyStatement.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/FinallyStatement.cs deleted file mode 100644 index ff2ba63..0000000 --- a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/FinallyStatement.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST -{ - using System.Reflection.Emit; - - internal class FinallyStatement : IStatement - { - public void Emit(ILGenerator gen) - { - gen.BeginFinallyBlock(); - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/IExpression.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/IExpression.cs deleted file mode 100644 index 8c06a69..0000000 --- a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/IExpression.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST -{ - internal interface IExpression : IExpressionOrStatement - { - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/IExpressionOrStatement.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/IExpressionOrStatement.cs deleted file mode 100644 index fb58101..0000000 --- a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/IExpressionOrStatement.cs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST -{ - using System.Reflection.Emit; - - internal interface IExpressionOrStatement - { - void Emit(ILGenerator gen); - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/IStatement.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/IStatement.cs deleted file mode 100644 index 78d3bbd..0000000 --- a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/IStatement.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST -{ - internal interface IStatement : IExpressionOrStatement - { - } -} diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/IfNullExpression.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/IfNullExpression.cs deleted file mode 100644 index 333a732..0000000 --- a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/IfNullExpression.cs +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST -{ - using System; - using System.Reflection.Emit; - - internal class IfNullExpression : IExpression, IStatement - { - private readonly IExpressionOrStatement ifNotNull; - private readonly IExpressionOrStatement ifNull; - private readonly Reference reference; - private readonly IExpression expression; - - public IfNullExpression(Reference reference, IExpressionOrStatement ifNull, IExpressionOrStatement ifNotNull = null) - { - this.reference = reference ?? throw new ArgumentNullException(nameof(reference)); - this.ifNull = ifNull; - this.ifNotNull = ifNotNull; - } - - public IfNullExpression(IExpression expression, IExpressionOrStatement ifNull, IExpressionOrStatement ifNotNull = null) - { - this.expression = expression ?? throw new ArgumentNullException(nameof(expression)); - this.ifNull = ifNull; - this.ifNotNull = ifNotNull; - } - - public void Emit(ILGenerator gen) - { - if (reference != null) - { - ArgumentsUtil.EmitLoadOwnerAndReference(reference, gen); - } - else if (expression != null) - { - expression.Emit(gen); - } - - var notNull = gen.DefineLabel(); - gen.Emit(OpCodes.Brtrue_S, notNull); - ifNull.Emit(gen); - gen.MarkLabel(notNull); - if (ifNotNull != null) // yeah, I know that reads funny :) - { - ifNotNull.Emit(gen); - } - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/IndirectReference.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/IndirectReference.cs deleted file mode 100644 index 321d439..0000000 --- a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/IndirectReference.cs +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST -{ - using System; - using System.Diagnostics; - using System.Reflection; - using System.Reflection.Emit; - - /// - /// Wraps a reference that is passed - /// ByRef and provides indirect load/store support. - /// - [DebuggerDisplay("&{OwnerReference}")] - internal class IndirectReference : TypeReference - { - public IndirectReference(TypeReference byRefReference) : - base(byRefReference, byRefReference.Type.GetElementType()) - { - if (!byRefReference.Type.IsByRef) - { - throw new ArgumentException("Expected an IsByRef reference", nameof(byRefReference)); - } - } - - public override void LoadAddressOfReference(ILGenerator gen) - { - // Load of owner reference takes care of this. - } - - // TODO: Better name - - public override void LoadReference(ILGenerator gen) - { - OpCodeUtil.EmitLoadIndirectOpCodeForType(gen, Type); - } - - public override void StoreReference(ILGenerator gen) - { - OpCodeUtil.EmitStoreIndirectOpCodeForType(gen, Type); - } - - public static TypeReference WrapIfByRef(TypeReference reference) - { - return reference.Type.IsByRef ? new IndirectReference(reference) : reference; - } - - // TODO: Better name - public static TypeReference[] WrapIfByRef(TypeReference[] references) - { - var result = new TypeReference[references.Length]; - - for (var i = 0; i < references.Length; i++) - { - result[i] = WrapIfByRef(references[i]); - } - - return result; - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/LiteralBoolExpression.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/LiteralBoolExpression.cs deleted file mode 100644 index 2fb5050..0000000 --- a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/LiteralBoolExpression.cs +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST -{ - using System.Reflection.Emit; - - internal class LiteralBoolExpression : IExpression - { - private readonly bool value; - - public LiteralBoolExpression(bool value) - { - this.value = value; - } - - public void Emit(ILGenerator gen) - { - gen.Emit(value ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0); - } - } -} diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/LiteralIntExpression.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/LiteralIntExpression.cs deleted file mode 100644 index 3e07dd4..0000000 --- a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/LiteralIntExpression.cs +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST -{ - using System.Reflection.Emit; - - internal class LiteralIntExpression : IExpression - { - private readonly int value; - - public LiteralIntExpression(int value) - { - this.value = value; - } - - public void Emit(ILGenerator gen) - { - switch (value) - { - case -1: - gen.Emit(OpCodes.Ldc_I4_M1); - break; - case 0: - gen.Emit(OpCodes.Ldc_I4_0); - break; - case 1: - gen.Emit(OpCodes.Ldc_I4_1); - break; - case 2: - gen.Emit(OpCodes.Ldc_I4_2); - break; - case 3: - gen.Emit(OpCodes.Ldc_I4_3); - break; - case 4: - gen.Emit(OpCodes.Ldc_I4_4); - break; - case 5: - gen.Emit(OpCodes.Ldc_I4_5); - break; - case 6: - gen.Emit(OpCodes.Ldc_I4_6); - break; - case 7: - gen.Emit(OpCodes.Ldc_I4_7); - break; - case 8: - gen.Emit(OpCodes.Ldc_I4_8); - break; - default: - gen.Emit(OpCodes.Ldc_I4, value); - break; - } - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/LiteralStringExpression.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/LiteralStringExpression.cs deleted file mode 100644 index f8a842d..0000000 --- a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/LiteralStringExpression.cs +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST -{ - using System.Reflection.Emit; - - internal class LiteralStringExpression : IExpression - { - private readonly string value; - - public LiteralStringExpression(string value) - { - this.value = value; - } - - public void Emit(ILGenerator gen) - { - gen.Emit(OpCodes.Ldstr, value); - } - } -} diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/LoadRefArrayElementExpression.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/LoadRefArrayElementExpression.cs deleted file mode 100644 index 311a46c..0000000 --- a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/LoadRefArrayElementExpression.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST -{ - using System.Reflection.Emit; - - internal class LoadRefArrayElementExpression : IExpression - { - private readonly Reference arrayReference; - private readonly LiteralIntExpression index; - - public LoadRefArrayElementExpression(int index, Reference arrayReference) - { - this.index = new LiteralIntExpression(index); - this.arrayReference = arrayReference; - } - - public void Emit(ILGenerator gen) - { - ArgumentsUtil.EmitLoadOwnerAndReference(arrayReference, gen); - index.Emit(gen); - gen.Emit(OpCodes.Ldelem_Ref); - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/LocalReference.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/LocalReference.cs deleted file mode 100644 index cc051a5..0000000 --- a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/LocalReference.cs +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST -{ - using System; - using System.Diagnostics; - using System.Reflection.Emit; - - [DebuggerDisplay("local {Type}")] - internal class LocalReference : TypeReference - { - private LocalBuilder localbuilder; - - public LocalReference(Type type) : base(type) - { - } - - public override void Generate(ILGenerator gen) - { - localbuilder = gen.DeclareLocal(base.Type); - } - - public override void LoadAddressOfReference(ILGenerator gen) - { - gen.Emit(OpCodes.Ldloca, localbuilder); - } - - public override void LoadReference(ILGenerator gen) - { - gen.Emit(OpCodes.Ldloc, localbuilder); - } - - public override void StoreReference(ILGenerator gen) - { - gen.Emit(OpCodes.Stloc, localbuilder); - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/MethodInvocationExpression.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/MethodInvocationExpression.cs deleted file mode 100644 index 4261758..0000000 --- a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/MethodInvocationExpression.cs +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST -{ - using System.Reflection; - using System.Reflection.Emit; - - internal class MethodInvocationExpression : IExpression, IStatement - { - protected readonly IExpression[] args; - protected readonly MethodInfo method; - protected readonly Reference owner; - - public MethodInvocationExpression(MethodInfo method, params IExpression[] args) : - this(SelfReference.Self, method, args) - { - } - - public MethodInvocationExpression(MethodEmitter method, params IExpression[] args) : - this(SelfReference.Self, method.MethodBuilder, args) - { - } - - public MethodInvocationExpression(Reference owner, MethodEmitter method, params IExpression[] args) : - this(owner, method.MethodBuilder, args) - { - } - - public MethodInvocationExpression(Reference owner, MethodInfo method, params IExpression[] args) - { - this.owner = owner; - this.method = method; - this.args = args; - } - - public bool VirtualCall { get; set; } - - public void Emit(ILGenerator gen) - { - ArgumentsUtil.EmitLoadOwnerAndReference(owner, gen); - - foreach (var exp in args) - { - exp.Emit(gen); - } - - if (VirtualCall) - { - gen.Emit(OpCodes.Callvirt, method); - } - else - { - gen.Emit(OpCodes.Call, method); - } - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/MethodTokenExpression.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/MethodTokenExpression.cs deleted file mode 100644 index cc70b09..0000000 --- a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/MethodTokenExpression.cs +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST -{ - using System.Diagnostics; - using System.Reflection; - using System.Reflection.Emit; - - using Castle.DynamicProxy.Tokens; - - internal class MethodTokenExpression : IExpression - { - private readonly MethodInfo method; - - public MethodTokenExpression(MethodInfo method) - { - this.method = method; - Debug.Assert(method.DeclaringType != null); // DynamicProxy isn't using global methods nor `DynamicMethod` - } - - public void Emit(ILGenerator gen) - { - gen.Emit(OpCodes.Ldtoken, method); - gen.Emit(OpCodes.Ldtoken, method.DeclaringType); - - var minfo = MethodBaseMethods.GetMethodFromHandle; - gen.Emit(OpCodes.Call, minfo); - gen.Emit(OpCodes.Castclass, typeof(MethodInfo)); - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/NewArrayExpression.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/NewArrayExpression.cs deleted file mode 100644 index e6a2524..0000000 --- a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/NewArrayExpression.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST -{ - using System; - using System.Reflection.Emit; - - internal class NewArrayExpression : IExpression - { - private readonly Type arrayType; - private readonly int size; - - public NewArrayExpression(int size, Type arrayType) - { - this.size = size; - this.arrayType = arrayType; - } - - public void Emit(ILGenerator gen) - { - gen.Emit(OpCodes.Ldc_I4, size); - gen.Emit(OpCodes.Newarr, arrayType); - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/NewInstanceExpression.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/NewInstanceExpression.cs deleted file mode 100644 index d5abeff..0000000 --- a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/NewInstanceExpression.cs +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST -{ - using System; - using System.Reflection; - using System.Reflection.Emit; - - internal class NewInstanceExpression : IExpression - { - private readonly IExpression[] arguments; - private ConstructorInfo constructor; - - public NewInstanceExpression(ConstructorInfo constructor, params IExpression[] args) - { - this.constructor = constructor ?? throw new ArgumentNullException(nameof(constructor)); - arguments = args; - } - - public NewInstanceExpression(Type target) - { - constructor = target.GetConstructor(Type.EmptyTypes) ?? throw new MissingMethodException("Could not find default constructor."); - arguments = null; - } - - public void Emit(ILGenerator gen) - { - if (arguments != null) - { - foreach (var exp in arguments) - { - exp.Emit(gen); - } - } - - gen.Emit(OpCodes.Newobj, constructor); - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/NullCoalescingOperatorExpression.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/NullCoalescingOperatorExpression.cs deleted file mode 100644 index 7c492a6..0000000 --- a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/NullCoalescingOperatorExpression.cs +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST -{ - using System; - using System.Reflection.Emit; - - internal class NullCoalescingOperatorExpression : IExpression - { - private readonly IExpression @default; - private readonly IExpression expression; - - public NullCoalescingOperatorExpression(IExpression expression, IExpression @default) - { - if (expression == null) - { - throw new ArgumentNullException(nameof(expression)); - } - - if (@default == null) - { - throw new ArgumentNullException(nameof(@default)); - } - - this.expression = expression; - this.@default = @default; - } - - public void Emit(ILGenerator gen) - { - expression.Emit(gen); - gen.Emit(OpCodes.Dup); - var label = gen.DefineLabel(); - gen.Emit(OpCodes.Brtrue_S, label); - gen.Emit(OpCodes.Pop); - @default.Emit(gen); - gen.MarkLabel(label); - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/NullExpression.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/NullExpression.cs deleted file mode 100644 index cdf0495..0000000 --- a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/NullExpression.cs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST -{ - using System.Reflection.Emit; - - internal class NullExpression : IExpression - { - public static readonly NullExpression Instance = new NullExpression(); - - protected NullExpression() - { - } - - public void Emit(ILGenerator gen) - { - gen.Emit(OpCodes.Ldnull); - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/Reference.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/Reference.cs deleted file mode 100644 index 6064317..0000000 --- a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/Reference.cs +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST -{ - using System.Reflection.Emit; - - internal abstract class Reference : IExpression - { - protected Reference owner = SelfReference.Self; - - protected Reference() - { - } - - protected Reference(Reference owner) - { - this.owner = owner; - } - - public Reference OwnerReference - { - get { return owner; } - set { owner = value; } - } - - public abstract void LoadAddressOfReference(ILGenerator gen); - - public abstract void LoadReference(ILGenerator gen); - - public abstract void StoreReference(ILGenerator gen); - - public virtual void Generate(ILGenerator gen) - { - } - - public void Emit(ILGenerator gen) - { - ArgumentsUtil.EmitLoadOwnerAndReference(this, gen); - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ReferencesToObjectArrayExpression.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ReferencesToObjectArrayExpression.cs deleted file mode 100644 index dea87ef..0000000 --- a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ReferencesToObjectArrayExpression.cs +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST -{ - using System; - using System.Reflection; - using System.Reflection.Emit; - - internal class ReferencesToObjectArrayExpression : IExpression - { - private readonly TypeReference[] args; - - public ReferencesToObjectArrayExpression(params TypeReference[] args) - { - this.args = args; - } - - public void Emit(ILGenerator gen) - { - var local = gen.DeclareLocal(typeof(object[])); - - gen.Emit(OpCodes.Ldc_I4, args.Length); - gen.Emit(OpCodes.Newarr, typeof(object)); - gen.Emit(OpCodes.Stloc, local); - - for (var i = 0; i < args.Length; i++) - { - gen.Emit(OpCodes.Ldloc, local); - gen.Emit(OpCodes.Ldc_I4, i); - - var reference = args[i]; - - ArgumentsUtil.EmitLoadOwnerAndReference(reference, gen); - - if (reference.Type.IsByRef) - { - throw new NotSupportedException(); - } - - if (reference.Type.IsValueType) - { - gen.Emit(OpCodes.Box, reference.Type); - } - else if (reference.Type.IsGenericParameter) - { - gen.Emit(OpCodes.Box, reference.Type); - } - - gen.Emit(OpCodes.Stelem_Ref); - } - - gen.Emit(OpCodes.Ldloc, local); - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ReturnStatement.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ReturnStatement.cs deleted file mode 100644 index 35bd01d..0000000 --- a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ReturnStatement.cs +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST -{ - using System.Reflection.Emit; - - internal class ReturnStatement : IStatement - { - private readonly IExpression expression; - private readonly Reference reference; - - public ReturnStatement() - { - } - - public ReturnStatement(Reference reference) - { - this.reference = reference; - } - - public ReturnStatement(IExpression expression) - { - this.expression = expression; - } - - public void Emit(ILGenerator gen) - { - if (reference != null) - { - ArgumentsUtil.EmitLoadOwnerAndReference(reference, gen); - } - else if (expression != null) - { - expression.Emit(gen); - } - - gen.Emit(OpCodes.Ret); - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/SelfReference.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/SelfReference.cs deleted file mode 100644 index 085d964..0000000 --- a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/SelfReference.cs +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST -{ - using System; - using System.Diagnostics; - using System.Reflection.Emit; - - [DebuggerDisplay("this")] - internal class SelfReference : Reference - { - public static readonly SelfReference Self = new SelfReference(); - - protected SelfReference() : base(null) - { - } - - public override void LoadAddressOfReference(ILGenerator gen) - { - throw new NotSupportedException(); - } - - public override void LoadReference(ILGenerator gen) - { - gen.Emit(OpCodes.Ldarg_0); - } - - public override void StoreReference(ILGenerator gen) - { - gen.Emit(OpCodes.Ldarg_0); - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ThrowStatement.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ThrowStatement.cs deleted file mode 100644 index f34a3c5..0000000 --- a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/ThrowStatement.cs +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST -{ - using System; - using System.Reflection; - using System.Reflection.Emit; - - internal class ThrowStatement : IStatement - { - private readonly string errorMessage; - private readonly Type exceptionType; - - public ThrowStatement(Type exceptionType, string errorMessage) - { - this.exceptionType = exceptionType; - this.errorMessage = errorMessage; - } - - public void Emit(ILGenerator gen) - { - var ci = exceptionType.GetConstructor(new[] { typeof(string) }); - var message = new LiteralStringExpression(errorMessage); - - var creationStmt = new NewInstanceExpression(ci, message); - - creationStmt.Emit(gen); - - gen.Emit(OpCodes.Throw); - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/TryStatement.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/TryStatement.cs deleted file mode 100644 index 69eb9bd..0000000 --- a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/TryStatement.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST -{ - using System.Reflection.Emit; - - internal class TryStatement : IStatement - { - public void Emit(ILGenerator gen) - { - gen.BeginExceptionBlock(); - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/TypeReference.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/TypeReference.cs deleted file mode 100644 index fa551e6..0000000 --- a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/TypeReference.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST -{ - using System; - - internal abstract class TypeReference : Reference - { - private readonly Type type; - - protected TypeReference(Type argumentType) : this(null, argumentType) - { - } - - protected TypeReference(Reference owner, Type type) : base(owner) - { - this.type = type; - } - - public Type Type - { - get { return type; } - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/TypeTokenExpression.cs b/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/TypeTokenExpression.cs deleted file mode 100644 index 2a390c2..0000000 --- a/Castle.Core/DynamicProxy/Generators/Emitters/SimpleAST/TypeTokenExpression.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators.Emitters.SimpleAST -{ - using System; - using System.Reflection.Emit; - - using Castle.DynamicProxy.Tokens; - - internal class TypeTokenExpression : IExpression - { - private readonly Type type; - - public TypeTokenExpression(Type type) - { - this.type = type; - } - - public void Emit(ILGenerator gen) - { - gen.Emit(OpCodes.Ldtoken, type); - gen.Emit(OpCodes.Call, TypeMethods.GetTypeFromHandle); - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/StindOpCodesDictionary.cs b/Castle.Core/DynamicProxy/Generators/Emitters/StindOpCodesDictionary.cs deleted file mode 100644 index 87b1240..0000000 --- a/Castle.Core/DynamicProxy/Generators/Emitters/StindOpCodesDictionary.cs +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators.Emitters -{ - using System; - using System.Collections.Generic; - using System.Reflection.Emit; - - /// - /// Provides appropriate Stind.X opcode - /// for the type of primitive value to be stored indirectly. - /// - internal sealed class StindOpCodesDictionary : Dictionary - { - private static readonly StindOpCodesDictionary dict = new StindOpCodesDictionary(); - - // has to be assigned explicitly to suppress compiler warning - private static readonly OpCode emptyOpCode = new OpCode(); - - private StindOpCodesDictionary() - { - Add(typeof(bool), OpCodes.Stind_I1); - Add(typeof(char), OpCodes.Stind_I2); - Add(typeof(SByte), OpCodes.Stind_I1); - Add(typeof(Int16), OpCodes.Stind_I2); - Add(typeof(Int32), OpCodes.Stind_I4); - Add(typeof(Int64), OpCodes.Stind_I8); - Add(typeof(float), OpCodes.Stind_R4); - Add(typeof(double), OpCodes.Stind_R8); - Add(typeof(byte), OpCodes.Stind_I1); - Add(typeof(UInt16), OpCodes.Stind_I2); - Add(typeof(UInt32), OpCodes.Stind_I4); - Add(typeof(UInt64), OpCodes.Stind_I8); - } - - public new OpCode this[Type type] - { - get - { - if (TryGetValue(type, out var opCode)) - { - return opCode; - } - return EmptyOpCode; - } - } - - public static OpCode EmptyOpCode - { - get { return emptyOpCode; } - } - - public static StindOpCodesDictionary Instance - { - get { return dict; } - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/StrongNameUtil.cs b/Castle.Core/DynamicProxy/Generators/Emitters/StrongNameUtil.cs deleted file mode 100644 index 43cec00..0000000 --- a/Castle.Core/DynamicProxy/Generators/Emitters/StrongNameUtil.cs +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators.Emitters -{ - using System; - using System.Collections.Generic; - using System.Linq; - using System.Reflection; - - internal static class StrongNameUtil - { - private static readonly IDictionary signedAssemblyCache = new Dictionary(); - private static readonly object lockObject = new object(); - - public static bool IsAssemblySigned(this Assembly assembly) - { - lock (lockObject) - { - if (signedAssemblyCache.TryGetValue(assembly, out var isSigned) == false) - { - isSigned = assembly.ContainsPublicKey(); - signedAssemblyCache.Add(assembly, isSigned); - } - return isSigned; - } - } - - private static bool ContainsPublicKey(this Assembly assembly) - { - // Pulled from a comment on http://www.flawlesscode.com/post/2008/08/Mocking-and-IOC-in-Silverlight-2-Castle-Project-and-Moq-ports.aspx - return assembly.FullName != null && !assembly.FullName.Contains("PublicKeyToken=null"); - } - - public static bool IsAnyTypeFromUnsignedAssembly(IEnumerable types) - { - return types.Any(t => t.Assembly.IsAssemblySigned() == false); - } - - public static bool IsAnyTypeFromUnsignedAssembly(Type baseType, IEnumerable interfaces) - { - if (baseType != null && baseType.Assembly.IsAssemblySigned() == false) - { - return true; - } - - return IsAnyTypeFromUnsignedAssembly(interfaces); - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/Emitters/TypeConstructorEmitter.cs b/Castle.Core/DynamicProxy/Generators/Emitters/TypeConstructorEmitter.cs deleted file mode 100644 index ce0b9a0..0000000 --- a/Castle.Core/DynamicProxy/Generators/Emitters/TypeConstructorEmitter.cs +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators.Emitters -{ - using Castle.DynamicProxy.Generators.Emitters.SimpleAST; - - internal class TypeConstructorEmitter : ConstructorEmitter - { - internal TypeConstructorEmitter(AbstractTypeEmitter maintype) - : base(maintype, maintype.TypeBuilder.DefineTypeInitializer()) - { - } - - public override void EnsureValidCodeBlock() - { - if (CodeBuilder.IsEmpty) - { - CodeBuilder.AddStatement(new ReturnStatement()); - } - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/ForwardingMethodGenerator.cs b/Castle.Core/DynamicProxy/Generators/ForwardingMethodGenerator.cs deleted file mode 100644 index 6b7364f..0000000 --- a/Castle.Core/DynamicProxy/Generators/ForwardingMethodGenerator.cs +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators -{ - using Castle.DynamicProxy.Contributors; - using Castle.DynamicProxy.Generators.Emitters; - using Castle.DynamicProxy.Generators.Emitters.SimpleAST; - - internal class ForwardingMethodGenerator : MethodGenerator - { - private readonly GetTargetReferenceDelegate getTargetReference; - - public ForwardingMethodGenerator(MetaMethod method, OverrideMethodDelegate overrideMethod, - GetTargetReferenceDelegate getTargetReference) - : base(method, overrideMethod) - { - this.getTargetReference = getTargetReference; - } - - protected override MethodEmitter BuildProxiedMethodBody(MethodEmitter emitter, ClassEmitter @class, - INamingScope namingScope) - { - var targetReference = getTargetReference(@class, MethodToOverride); - var arguments = ArgumentsUtil.ConvertToArgumentReferenceExpression(MethodToOverride.GetParameters()); - - emitter.CodeBuilder.AddStatement(new ReturnStatement( - new MethodInvocationExpression( - targetReference, - MethodToOverride, - arguments) { VirtualCall = true })); - return emitter; - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/GeneratorUtil.cs b/Castle.Core/DynamicProxy/Generators/GeneratorUtil.cs deleted file mode 100644 index eb9ff84..0000000 --- a/Castle.Core/DynamicProxy/Generators/GeneratorUtil.cs +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators -{ - using System.Linq; - using System.Reflection; - using System.Runtime.InteropServices; - - using Castle.DynamicProxy.Generators.Emitters; - using Castle.DynamicProxy.Generators.Emitters.SimpleAST; - using Castle.DynamicProxy.Tokens; - - internal static class GeneratorUtil - { - public static void CopyOutAndRefParameters(TypeReference[] dereferencedArguments, LocalReference invocation, - MethodInfo method, MethodEmitter emitter) - { - var parameters = method.GetParameters(); - - // Create it only if there are byref writable arguments. - LocalReference arguments = null; - - for (var i = 0; i < parameters.Length; i++) - { - if (IsByRef(parameters[i]) && !IsReadOnly(parameters[i])) - { - if (arguments == null) - { - arguments = StoreInvocationArgumentsInLocal(emitter, invocation); - } - - emitter.CodeBuilder.AddStatement(AssignArgument(dereferencedArguments, i, arguments)); - } - } - - bool IsByRef(ParameterInfo parameter) - { - return parameter.ParameterType.IsByRef; - } - - bool IsReadOnly(ParameterInfo parameter) - { - // C# `in` parameters are also by-ref, but meant to be read-only. - // The section "Metadata representation of in parameters" on the following page - // defines how such parameters are marked: - // - // https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.2/readonly-ref.md - // - // This poses three problems for detecting them: - // - // * The C# Roslyn compiler marks `in` parameters with an `[in]` IL modifier, - // but this isn't specified, nor is it used uniquely for `in` params. - // - // * `System.Runtime.CompilerServices.IsReadOnlyAttribute` is not defined on all - // .NET platforms, so the compiler sometimes recreates that type in the same - // assembly that contains the method having an `in` parameter. In other words, - // it's an attribute one must check for by name (which is slow, as it implies - // use of a `GetCustomAttributes` enumeration instead of a faster `IsDefined`). - // - // * A required custom modifier `System.Runtime.InteropServices.InAttribute` - // is always present in those cases relevant for DynamicProxy (proxyable methods), - // but not all targeted platforms support reading custom modifiers. Also, - // support for cmods is generally flaky (at this time of writing, mid-2018). - // - // The above points inform the following detection logic: First, we rely on an IL - // `[in]` modifier being present. This is a "fast guard" against non-`in` parameters: - if ((parameter.Attributes & (ParameterAttributes.In | ParameterAttributes.Out)) != ParameterAttributes.In) - { - return false; - } - - // This check allows to make the detection logic more robust on the platforms which support custom modifiers. - // The robustness is achieved by the fact, that usually the `IsReadOnlyAttribute` emitted by the compiler is internal to the assembly. - // Therefore, if clients use Reflection.Emit to create "a copy" of the methods with read-only members, they cannot re-use the existing attribute. - // Instead, they are forced to emit their own `IsReadOnlyAttribute` to mark some argument as immutable. - // The `InAttribute` type OTOH was always available in BCL. Therefore, it's much easier to copy the modreq and be recognized by Castle. - // - // If check fails, resort to the IsReadOnlyAttribute check. - // Check for the required modifiers first, as it's faster. - if (parameter.GetRequiredCustomModifiers().Any(x => x == typeof(InAttribute))) - { - return true; - } - - // The comparison by name is intentional; any assembly could define that attribute. - // See explanation in comment above. - if (parameter.GetCustomAttributes(false).Any(x => x.GetType().FullName == "System.Runtime.CompilerServices.IsReadOnlyAttribute")) - { - return true; - } - - return false; - } - } - - private static ConvertExpression Argument(int i, LocalReference invocationArgs, TypeReference[] arguments) - { - return new ConvertExpression(arguments[i].Type, new LoadRefArrayElementExpression(i, invocationArgs)); - } - - private static AssignStatement AssignArgument(TypeReference[] dereferencedArguments, int i, - LocalReference invocationArgs) - { - return new AssignStatement(dereferencedArguments[i], Argument(i, invocationArgs, dereferencedArguments)); - } - - private static AssignStatement GetArguments(LocalReference invocationArgs, LocalReference invocation) - { - return new AssignStatement(invocationArgs, new MethodInvocationExpression(invocation, InvocationMethods.GetArguments)); - } - - private static LocalReference StoreInvocationArgumentsInLocal(MethodEmitter emitter, LocalReference invocation) - { - var invocationArgs = emitter.CodeBuilder.DeclareLocal(typeof(object[])); - emitter.CodeBuilder.AddStatement(GetArguments(invocationArgs, invocation)); - return invocationArgs; - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/IGenerator.cs b/Castle.Core/DynamicProxy/Generators/IGenerator.cs deleted file mode 100644 index 619f8af..0000000 --- a/Castle.Core/DynamicProxy/Generators/IGenerator.cs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators -{ - using Castle.DynamicProxy.Generators.Emitters; - - internal interface IGenerator - { - T Generate(ClassEmitter @class, INamingScope namingScope); - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/INamingScope.cs b/Castle.Core/DynamicProxy/Generators/INamingScope.cs deleted file mode 100644 index 57cd4c0..0000000 --- a/Castle.Core/DynamicProxy/Generators/INamingScope.cs +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators -{ - /// - /// Represents the scope of uniqueness of names for types and their members - /// - internal interface INamingScope - { - INamingScope ParentScope { get; } - - /// - /// Gets a unique name based on - /// - /// Name suggested by the caller - /// Unique name based on . - /// - /// Implementers should provide name as closely resembling as possible. - /// Generally if no collision occurs it is suggested to return suggested name, otherwise append sequential suffix. - /// Implementers must return deterministic names, that is when is called twice - /// with the same suggested name, the same returned name should be provided each time. Non-deterministic return - /// values, like appending random suffices will break serialization of proxies. - /// - string GetUniqueName(string suggestedName); - - /// - /// Returns new, disposable naming scope. It is responsibility of the caller to make sure that no naming collision - /// with enclosing scope, or other subscopes is possible. - /// - /// New naming scope. - INamingScope SafeSubScope(); - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/InheritanceInvocationTypeGenerator.cs b/Castle.Core/DynamicProxy/Generators/InheritanceInvocationTypeGenerator.cs deleted file mode 100644 index b02d587..0000000 --- a/Castle.Core/DynamicProxy/Generators/InheritanceInvocationTypeGenerator.cs +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators -{ - using System; - using System.Reflection; - - using Castle.DynamicProxy.Contributors; - using Castle.DynamicProxy.Generators.Emitters.SimpleAST; - using Castle.DynamicProxy.Internal; - using Castle.DynamicProxy.Tokens; - - internal class InheritanceInvocationTypeGenerator : InvocationTypeGenerator - { - public static readonly Type BaseType = typeof(InheritanceInvocation); - - public InheritanceInvocationTypeGenerator(Type targetType, MetaMethod method, MethodInfo callback, - IInvocationCreationContributor contributor) - : base(targetType, method, callback, false, contributor) - { - } - - protected override ArgumentReference[] GetBaseCtorArguments(Type targetFieldType, - out ConstructorInfo baseConstructor) - { - baseConstructor = InvocationMethods.InheritanceInvocationConstructor; - return new[] - { - new ArgumentReference(typeof(Type)), - new ArgumentReference(typeof(object)), - new ArgumentReference(typeof(IInterceptor[])), - new ArgumentReference(typeof(MethodInfo)), - new ArgumentReference(typeof(object[])) - }; - } - - protected override Type GetBaseType() - { - return BaseType; - } - - protected override FieldReference GetTargetReference() - { - return new FieldReference(InvocationMethods.ProxyObject); - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/InterfaceProxyWithTargetGenerator.cs b/Castle.Core/DynamicProxy/Generators/InterfaceProxyWithTargetGenerator.cs deleted file mode 100644 index dc4ac91..0000000 --- a/Castle.Core/DynamicProxy/Generators/InterfaceProxyWithTargetGenerator.cs +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators -{ - using System; - using System.Collections.Generic; - using System.Linq; - - using Castle.DynamicProxy.Contributors; - using Castle.DynamicProxy.Serialization; - - internal sealed class InterfaceProxyWithTargetGenerator : BaseInterfaceProxyGenerator - { - public InterfaceProxyWithTargetGenerator(ModuleScope scope, Type targetType, Type[] interfaces, - Type proxyTargetType, ProxyGenerationOptions options) - : base(scope, targetType, interfaces, proxyTargetType, options) - { } - - protected override bool AllowChangeTarget => false; - - protected override string GeneratorType => ProxyTypeConstants.InterfaceWithTarget; - - protected override CompositeTypeContributor GetProxyTargetContributor(Type proxyTargetType, INamingScope namingScope) - { - return new InterfaceProxyTargetContributor(proxyTargetType, AllowChangeTarget, namingScope) { Logger = Logger }; - } - - protected override ProxyTargetAccessorContributor GetProxyTargetAccessorContributor() - { - return new ProxyTargetAccessorContributor( - getTargetReference: () => targetField, - proxyTargetType); - } - - protected override void AddMappingForAdditionalInterfaces(CompositeTypeContributor contributor, Type[] proxiedInterfaces, - IDictionary typeImplementerMapping, - ICollection targetInterfaces) - { - foreach (var @interface in interfaces) - { - if (!ImplementedByTarget(targetInterfaces, @interface) || proxiedInterfaces.Contains(@interface)) - { - continue; - } - - contributor.AddInterfaceToProxy(@interface); - AddMappingNoCheck(@interface, contributor, typeImplementerMapping); - } - } - - private bool ImplementedByTarget(ICollection targetInterfaces, Type @interface) - { - return targetInterfaces.Contains(@interface); - } - } -} diff --git a/Castle.Core/DynamicProxy/Generators/InterfaceProxyWithTargetInterfaceGenerator.cs b/Castle.Core/DynamicProxy/Generators/InterfaceProxyWithTargetInterfaceGenerator.cs deleted file mode 100644 index 9ae7b10..0000000 --- a/Castle.Core/DynamicProxy/Generators/InterfaceProxyWithTargetInterfaceGenerator.cs +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators -{ - using System; - using System.Collections.Generic; - using System.Reflection; - - using Castle.DynamicProxy.Contributors; - using Castle.DynamicProxy.Generators.Emitters; - using Castle.DynamicProxy.Generators.Emitters.SimpleAST; - using Castle.DynamicProxy.Internal; - using Castle.DynamicProxy.Serialization; - - internal sealed class InterfaceProxyWithTargetInterfaceGenerator : BaseInterfaceProxyGenerator - { - public InterfaceProxyWithTargetInterfaceGenerator(ModuleScope scope, Type targetType, Type[] interfaces, - Type proxyTargetType, ProxyGenerationOptions options) - : base(scope, targetType, interfaces, proxyTargetType, options) - { - } - - protected override bool AllowChangeTarget => true; - - protected override string GeneratorType => ProxyTypeConstants.InterfaceWithTargetInterface; - - protected override CompositeTypeContributor GetProxyTargetContributor(Type proxyTargetType, INamingScope namingScope) - { - return new InterfaceProxyWithTargetInterfaceTargetContributor(proxyTargetType, AllowChangeTarget, namingScope) { Logger = Logger }; - } - - protected override ProxyTargetAccessorContributor GetProxyTargetAccessorContributor() - { - return new ProxyTargetAccessorContributor( - getTargetReference: () => targetField, - proxyTargetType); - } - - protected override void AddMappingForAdditionalInterfaces(CompositeTypeContributor contributor, Type[] proxiedInterfaces, - IDictionary typeImplementerMapping, - ICollection targetInterfaces) - { - } - - protected override InterfaceProxyWithoutTargetContributor GetContributorForAdditionalInterfaces( - INamingScope namingScope) - { - return new InterfaceProxyWithOptionalTargetContributor(namingScope, GetTargetExpression, GetTarget) - { Logger = Logger }; - } - - private Reference GetTarget(ClassEmitter @class, MethodInfo method) - { - return new AsTypeReference(@class.GetField("__target"), method.DeclaringType); - } - - private IExpression GetTargetExpression(ClassEmitter @class, MethodInfo method) - { - return GetTarget(@class, method); - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/InterfaceProxyWithoutTargetGenerator.cs b/Castle.Core/DynamicProxy/Generators/InterfaceProxyWithoutTargetGenerator.cs deleted file mode 100644 index d916e4d..0000000 --- a/Castle.Core/DynamicProxy/Generators/InterfaceProxyWithoutTargetGenerator.cs +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators -{ - using System; - using System.Collections.Generic; - - using Castle.DynamicProxy.Contributors; - using Castle.DynamicProxy.Generators.Emitters.SimpleAST; - using Castle.DynamicProxy.Serialization; - - internal sealed class InterfaceProxyWithoutTargetGenerator : BaseInterfaceProxyGenerator - { - public InterfaceProxyWithoutTargetGenerator(ModuleScope scope, Type targetType, Type[] interfaces, - Type proxyTargetType, ProxyGenerationOptions options) - : base(scope, targetType, interfaces, proxyTargetType, options) - { - } - - protected override bool AllowChangeTarget => false; - - protected override string GeneratorType => ProxyTypeConstants.InterfaceWithoutTarget; - - protected override CompositeTypeContributor GetProxyTargetContributor(Type proxyTargetType, INamingScope namingScope) - { - return new InterfaceProxyWithoutTargetContributor(namingScope, (c, m) => NullExpression.Instance) { Logger = Logger }; - } - - protected override ProxyTargetAccessorContributor GetProxyTargetAccessorContributor() - { - return new ProxyTargetAccessorContributor( - getTargetReference: () => targetField, - proxyTargetType); - } - - protected override void AddMappingForAdditionalInterfaces(CompositeTypeContributor contributor, Type[] proxiedInterfaces, - IDictionary typeImplementerMapping, - ICollection targetInterfaces) - { - } - - protected override IEnumerable GetTypeImplementerMapping(Type _, out IEnumerable contributors, INamingScope namingScope) - { - return base.GetTypeImplementerMapping(proxyTargetType: targetType, out contributors, namingScope); - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/InvocationTypeGenerator.cs b/Castle.Core/DynamicProxy/Generators/InvocationTypeGenerator.cs deleted file mode 100644 index 133d9d7..0000000 --- a/Castle.Core/DynamicProxy/Generators/InvocationTypeGenerator.cs +++ /dev/null @@ -1,311 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators -{ - using System; - using System.Collections.Generic; - using System.Reflection; - - using Castle.DynamicProxy.Contributors; - using Castle.DynamicProxy.Generators.Emitters; - using Castle.DynamicProxy.Generators.Emitters.SimpleAST; - using Castle.DynamicProxy.Internal; - using Castle.DynamicProxy.Tokens; - - internal abstract class InvocationTypeGenerator : IGenerator - { - protected readonly MetaMethod method; - protected readonly Type targetType; - private readonly MethodInfo callback; - private readonly bool canChangeTarget; - private readonly IInvocationCreationContributor contributor; - - protected InvocationTypeGenerator(Type targetType, MetaMethod method, MethodInfo callback, bool canChangeTarget, - IInvocationCreationContributor contributor) - { - this.targetType = targetType; - this.method = method; - this.callback = callback; - this.canChangeTarget = canChangeTarget; - this.contributor = contributor; - } - - /// - /// Generates the constructor for the class that extends - /// - /// - protected abstract ArgumentReference[] GetBaseCtorArguments(Type targetFieldType, - out ConstructorInfo baseConstructor); - - protected abstract Type GetBaseType(); - - protected abstract FieldReference GetTargetReference(); - - public AbstractTypeEmitter Generate(ClassEmitter @class, INamingScope namingScope) - { - var methodInfo = method.Method; - - var interfaces = new Type[0]; - - if (canChangeTarget) - { - interfaces = new[] { typeof(IChangeProxyTarget) }; - } - var invocation = GetEmitter(@class, interfaces, namingScope, methodInfo); - - // invocation only needs to mirror the generic parameters of the MethodInfo - // targetType cannot be a generic type definition (YET!) - invocation.CopyGenericParametersFromMethod(methodInfo); - - CreateConstructor(invocation); - - var targetField = GetTargetReference(); - if (canChangeTarget) - { - ImplementChangeProxyTargetInterface(@class, invocation, targetField); - } - - ImplemementInvokeMethodOnTarget(invocation, methodInfo.GetParameters(), targetField, callback); - -#if FEATURE_SERIALIZATION - invocation.DefineCustomAttribute(); -#endif - - return invocation; - } - - protected virtual MethodInvocationExpression GetCallbackMethodInvocation(AbstractTypeEmitter invocation, - IExpression[] args, MethodInfo callbackMethod, - Reference targetField, - MethodEmitter invokeMethodOnTarget) - { - if (contributor != null) - { - return contributor.GetCallbackMethodInvocation(invocation, args, targetField, invokeMethodOnTarget); - } - var methodOnTargetInvocationExpression = new MethodInvocationExpression( - new AsTypeReference(targetField, callbackMethod.DeclaringType), - callbackMethod, - args) { VirtualCall = true }; - return methodOnTargetInvocationExpression; - } - - protected virtual void ImplementInvokeMethodOnTarget(AbstractTypeEmitter invocation, ParameterInfo[] parameters, - MethodEmitter invokeMethodOnTarget, - Reference targetField) - { - var callbackMethod = GetCallbackMethod(invocation); - if (callbackMethod == null) - { - EmitCallThrowOnNoTarget(invokeMethodOnTarget); - return; - } - - var args = new IExpression[parameters.Length]; - - // Idea: instead of grab parameters one by one - // we should grab an array - var byRefArguments = new Dictionary(); - - for (var i = 0; i < parameters.Length; i++) - { - var param = parameters[i]; - - var paramType = invocation.GetClosedParameterType(param.ParameterType); - if (paramType.IsByRef) - { - var localReference = invokeMethodOnTarget.CodeBuilder.DeclareLocal(paramType.GetElementType()); - invokeMethodOnTarget.CodeBuilder - .AddStatement( - new AssignStatement(localReference, - new ConvertExpression(paramType.GetElementType(), - new MethodInvocationExpression(SelfReference.Self, - InvocationMethods.GetArgumentValue, - new LiteralIntExpression(i))))); - var byRefReference = new ByRefReference(localReference); - args[i] = byRefReference; - byRefArguments[i] = localReference; - } - else - { - args[i] = - new ConvertExpression(paramType, - new MethodInvocationExpression(SelfReference.Self, - InvocationMethods.GetArgumentValue, - new LiteralIntExpression(i))); - } - } - - if (byRefArguments.Count > 0) - { - invokeMethodOnTarget.CodeBuilder.AddStatement(new TryStatement()); - } - - var methodOnTargetInvocationExpression = GetCallbackMethodInvocation(invocation, args, callbackMethod, targetField, invokeMethodOnTarget); - - LocalReference returnValue = null; - if (callbackMethod.ReturnType != typeof(void)) - { - var returnType = invocation.GetClosedParameterType(callbackMethod.ReturnType); - returnValue = invokeMethodOnTarget.CodeBuilder.DeclareLocal(returnType); - invokeMethodOnTarget.CodeBuilder.AddStatement(new AssignStatement(returnValue, methodOnTargetInvocationExpression)); - } - else - { - invokeMethodOnTarget.CodeBuilder.AddStatement(methodOnTargetInvocationExpression); - } - - AssignBackByRefArguments(invokeMethodOnTarget, byRefArguments); - - if (callbackMethod.ReturnType != typeof(void)) - { - var setRetVal = - new MethodInvocationExpression(SelfReference.Self, - InvocationMethods.SetReturnValue, - new ConvertExpression(typeof(object), returnValue.Type, returnValue)); - - invokeMethodOnTarget.CodeBuilder.AddStatement(setRetVal); - } - - invokeMethodOnTarget.CodeBuilder.AddStatement(new ReturnStatement()); - } - - private void AssignBackByRefArguments(MethodEmitter invokeMethodOnTarget, Dictionary byRefArguments) - { - if (byRefArguments.Count == 0) - { - return; - } - - invokeMethodOnTarget.CodeBuilder.AddStatement(new FinallyStatement()); - foreach (var byRefArgument in byRefArguments) - { - var index = byRefArgument.Key; - var localReference = byRefArgument.Value; - invokeMethodOnTarget.CodeBuilder.AddStatement( - new MethodInvocationExpression( - SelfReference.Self, - InvocationMethods.SetArgumentValue, - new LiteralIntExpression(index), - new ConvertExpression( - typeof(object), - localReference.Type, - localReference))); - } - invokeMethodOnTarget.CodeBuilder.AddStatement(new EndExceptionBlockStatement()); - } - - private void CreateConstructor(AbstractTypeEmitter invocation) - { - ConstructorInfo baseConstructor; - var baseCtorArguments = GetBaseCtorArguments(targetType, out baseConstructor); - - var constructor = CreateConstructor(invocation, baseCtorArguments); - constructor.CodeBuilder.AddStatement(new ConstructorInvocationStatement(baseConstructor, baseCtorArguments)); - constructor.CodeBuilder.AddStatement(new ReturnStatement()); - } - - private ConstructorEmitter CreateConstructor(AbstractTypeEmitter invocation, ArgumentReference[] baseCtorArguments) - { - if (contributor == null) - { - return invocation.CreateConstructor(baseCtorArguments); - } - return contributor.CreateConstructor(baseCtorArguments, invocation); - } - - private void EmitCallThrowOnNoTarget(MethodEmitter invokeMethodOnTarget) - { - var throwOnNoTarget = new MethodInvocationExpression(InvocationMethods.ThrowOnNoTarget); - - invokeMethodOnTarget.CodeBuilder.AddStatement(throwOnNoTarget); - invokeMethodOnTarget.CodeBuilder.AddStatement(new ReturnStatement()); - } - - private MethodInfo GetCallbackMethod(AbstractTypeEmitter invocation) - { - if (contributor != null) - { - return contributor.GetCallbackMethod(); - } - var callbackMethod = callback; - if (callbackMethod == null) - { - return null; - } - - if (!callbackMethod.IsGenericMethod) - { - return callbackMethod; - } - - return callbackMethod.MakeGenericMethod(invocation.GetGenericArgumentsFor(callbackMethod)); - } - - private AbstractTypeEmitter GetEmitter(ClassEmitter @class, Type[] interfaces, INamingScope namingScope, - MethodInfo methodInfo) - { - var suggestedName = string.Format("Castle.Proxies.Invocations.{0}_{1}", methodInfo.DeclaringType.Name, - methodInfo.Name); - var uniqueName = namingScope.ParentScope.GetUniqueName(suggestedName); - return new ClassEmitter(@class.ModuleScope, uniqueName, GetBaseType(), interfaces, ClassEmitter.DefaultAttributes, forceUnsigned: @class.InStrongNamedModule == false); - } - - private void ImplemementInvokeMethodOnTarget(AbstractTypeEmitter invocation, ParameterInfo[] parameters, - FieldReference targetField, MethodInfo callbackMethod) - { - var invokeMethodOnTarget = invocation.CreateMethod("InvokeMethodOnTarget", typeof(void)); - ImplementInvokeMethodOnTarget(invocation, parameters, invokeMethodOnTarget, targetField); - } - - private void ImplementChangeInvocationTarget(AbstractTypeEmitter invocation, FieldReference targetField) - { - var changeInvocationTarget = invocation.CreateMethod("ChangeInvocationTarget", typeof(void), new[] { typeof(object) }); - changeInvocationTarget.CodeBuilder.AddStatement( - new AssignStatement(targetField, - new ConvertExpression(targetType, changeInvocationTarget.Arguments[0]))); - changeInvocationTarget.CodeBuilder.AddStatement(new ReturnStatement()); - } - - private void ImplementChangeProxyTarget(AbstractTypeEmitter invocation, ClassEmitter @class) - { - var changeProxyTarget = invocation.CreateMethod("ChangeProxyTarget", typeof(void), new[] { typeof(object) }); - - var proxyObject = new FieldReference(InvocationMethods.ProxyObject); - var localProxy = changeProxyTarget.CodeBuilder.DeclareLocal(typeof(IProxyTargetAccessor)); - changeProxyTarget.CodeBuilder.AddStatement( - new AssignStatement(localProxy, - new ConvertExpression(localProxy.Type, proxyObject))); - - var dynSetProxy = typeof(IProxyTargetAccessor).GetMethod(nameof(IProxyTargetAccessor.DynProxySetTarget)); - - changeProxyTarget.CodeBuilder.AddStatement( - new MethodInvocationExpression(localProxy, dynSetProxy, changeProxyTarget.Arguments[0]) - { - VirtualCall = true - }); - - changeProxyTarget.CodeBuilder.AddStatement(new ReturnStatement()); - } - - private void ImplementChangeProxyTargetInterface(ClassEmitter @class, AbstractTypeEmitter invocation, - FieldReference targetField) - { - ImplementChangeInvocationTarget(invocation, targetField); - - ImplementChangeProxyTarget(invocation, @class); - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/MetaEvent.cs b/Castle.Core/DynamicProxy/Generators/MetaEvent.cs deleted file mode 100644 index ea2e479..0000000 --- a/Castle.Core/DynamicProxy/Generators/MetaEvent.cs +++ /dev/null @@ -1,151 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators -{ - using System; - using System.Reflection; - - using Castle.DynamicProxy.Generators.Emitters; - - internal class MetaEvent : MetaTypeElement, IEquatable - { - private readonly MetaMethod adder; - private readonly MetaMethod remover; - private EventEmitter emitter; - - /// - /// Initializes a new instance of the class. - /// - /// The event. - /// The add method. - /// The remove method. - /// The attributes. - public MetaEvent(EventInfo @event, MetaMethod adder, MetaMethod remover, EventAttributes attributes) - : base(@event) - { - if (adder == null) - { - throw new ArgumentNullException(nameof(adder)); - } - if (remover == null) - { - throw new ArgumentNullException(nameof(remover)); - } - this.adder = adder; - this.remover = remover; - Attributes = attributes; - } - - public MetaMethod Adder - { - get { return adder; } - } - - public EventAttributes Attributes { get; private set; } - - public EventEmitter Emitter - { - get - { - if (emitter != null) - { - return emitter; - } - - throw new InvalidOperationException( - "Emitter is not initialized. You have to initialize it first using 'BuildEventEmitter' method"); - } - } - - public MetaMethod Remover - { - get { return remover; } - } - - private Type Type - { - get { return ((EventInfo)Member).EventHandlerType; } - } - - public void BuildEventEmitter(ClassEmitter classEmitter) - { - if (emitter != null) - { - throw new InvalidOperationException(); - } - emitter = classEmitter.CreateEvent(Name, Attributes, Type); - } - - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) - { - return false; - } - if (ReferenceEquals(this, obj)) - { - return true; - } - if (obj.GetType() != typeof(MetaEvent)) - { - return false; - } - return Equals((MetaEvent)obj); - } - - public override int GetHashCode() - { - unchecked - { - var result = (adder.Method != null ? adder.Method.GetHashCode() : 0); - result = (result*397) ^ (remover.Method != null ? remover.Method.GetHashCode() : 0); - result = (result*397) ^ Attributes.GetHashCode(); - return result; - } - } - - public bool Equals(MetaEvent other) - { - if (ReferenceEquals(null, other)) - { - return false; - } - - if (ReferenceEquals(this, other)) - { - return true; - } - - if (!Type.Equals(other.Type)) - { - return false; - } - - if (!StringComparer.OrdinalIgnoreCase.Equals(Name, other.Name)) - { - return false; - } - - return true; - } - - public override void SwitchToExplicitImplementation() - { - SwitchToExplicitImplementationName(); - adder.SwitchToExplicitImplementation(); - remover.SwitchToExplicitImplementation(); - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/MetaMethod.cs b/Castle.Core/DynamicProxy/Generators/MetaMethod.cs deleted file mode 100644 index bffa8bd..0000000 --- a/Castle.Core/DynamicProxy/Generators/MetaMethod.cs +++ /dev/null @@ -1,143 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators -{ - using System; - using System.Diagnostics; - using System.Reflection; - - [DebuggerDisplay("{Method}")] - internal class MetaMethod : MetaTypeElement, IEquatable - { - private const MethodAttributes ExplicitImplementationAttributes = MethodAttributes.Virtual | - MethodAttributes.Public | - MethodAttributes.HideBySig | - MethodAttributes.NewSlot | - MethodAttributes.Final; - - public MetaMethod(MethodInfo method, MethodInfo methodOnTarget, bool standalone, bool proxyable, bool hasTarget) - : base(method) - { - Method = method; - MethodOnTarget = methodOnTarget; - Standalone = standalone; - Proxyable = proxyable; - HasTarget = hasTarget; - Attributes = ObtainAttributes(); - } - - public MethodAttributes Attributes { get; private set; } - public bool HasTarget { get; private set; } - public MethodInfo Method { get; private set; } - - public MethodInfo MethodOnTarget { get; private set; } - - public bool Ignore { get; internal set; } - - public bool Proxyable { get; private set; } - - public bool Standalone { get; private set; } - - public bool Equals(MetaMethod other) - { - if (ReferenceEquals(null, other)) - { - return false; - } - if (ReferenceEquals(this, other)) - { - return true; - } - - if (!StringComparer.OrdinalIgnoreCase.Equals(Name, other.Name)) - { - return false; - } - - var comparer = MethodSignatureComparer.Instance; - if (!comparer.EqualSignatureTypes(Method.ReturnType, other.Method.ReturnType)) - { - return false; - } - - if (!comparer.EqualGenericParameters(Method, other.Method)) - { - return false; - } - - if (!comparer.EqualParameters(Method, other.Method)) - { - return false; - } - - return true; - } - - public override void SwitchToExplicitImplementation() - { - Attributes = ExplicitImplementationAttributes; - if (Standalone == false) - { - Attributes |= MethodAttributes.SpecialName; - } - - SwitchToExplicitImplementationName(); - } - - private MethodAttributes ObtainAttributes() - { - var methodInfo = Method; - var attributes = MethodAttributes.Virtual; - - if (methodInfo.IsFinal || Method.DeclaringType.IsInterface) - { - attributes |= MethodAttributes.NewSlot; - } - - if (methodInfo.IsPublic) - { - attributes |= MethodAttributes.Public; - } - - if (methodInfo.IsHideBySig) - { - attributes |= MethodAttributes.HideBySig; - } - if (ProxyUtil.IsInternal(methodInfo) && - ProxyUtil.AreInternalsVisibleToDynamicProxy(methodInfo.DeclaringType.Assembly)) - { - attributes |= MethodAttributes.Assembly; - } - if (methodInfo.IsFamilyAndAssembly) - { - attributes |= MethodAttributes.FamANDAssem; - } - else if (methodInfo.IsFamilyOrAssembly) - { - attributes |= MethodAttributes.FamORAssem; - } - else if (methodInfo.IsFamily) - { - attributes |= MethodAttributes.Family; - } - - if (Standalone == false) - { - attributes |= MethodAttributes.SpecialName; - } - return attributes; - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/MetaProperty.cs b/Castle.Core/DynamicProxy/Generators/MetaProperty.cs deleted file mode 100644 index b4a020f..0000000 --- a/Castle.Core/DynamicProxy/Generators/MetaProperty.cs +++ /dev/null @@ -1,199 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators -{ - using System; - using System.Collections.Generic; - using System.Reflection; - using System.Reflection.Emit; - - using Castle.DynamicProxy.Generators.Emitters; - - internal class MetaProperty : MetaTypeElement, IEquatable - { - private readonly Type[] arguments; - private readonly PropertyAttributes attributes; - private readonly IEnumerable customAttributes; - private readonly MetaMethod getter; - private readonly MetaMethod setter; - private PropertyEmitter emitter; - - public MetaProperty(PropertyInfo property, MetaMethod getter, MetaMethod setter, - IEnumerable customAttributes, Type[] arguments) - : base(property) - { - this.getter = getter; - this.setter = setter; - attributes = PropertyAttributes.None; - this.customAttributes = customAttributes; - this.arguments = arguments ?? Type.EmptyTypes; - } - - public Type[] Arguments - { - get { return arguments; } - } - - public bool CanRead - { - get { return getter != null; } - } - - public bool CanWrite - { - get { return setter != null; } - } - - public PropertyEmitter Emitter - { - get - { - if (emitter == null) - { - throw new InvalidOperationException( - "Emitter is not initialized. You have to initialize it first using 'BuildPropertyEmitter' method"); - } - return emitter; - } - } - - public MethodInfo GetMethod - { - get - { - if (!CanRead) - { - throw new InvalidOperationException(); - } - return getter.Method; - } - } - - public MetaMethod Getter - { - get { return getter; } - } - - public MethodInfo SetMethod - { - get - { - if (!CanWrite) - { - throw new InvalidOperationException(); - } - return setter.Method; - } - } - - public MetaMethod Setter - { - get { return setter; } - } - - private Type Type - { - get { return ((PropertyInfo)Member).PropertyType; } - } - - public void BuildPropertyEmitter(ClassEmitter classEmitter) - { - if (emitter != null) - { - throw new InvalidOperationException("Emitter is already created. It is illegal to invoke this method twice."); - } - - emitter = classEmitter.CreateProperty(Name, attributes, Type, arguments); - foreach (var attribute in customAttributes) - { - emitter.DefineCustomAttribute(attribute); - } - } - - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) - { - return false; - } - if (ReferenceEquals(this, obj)) - { - return true; - } - if (obj.GetType() != typeof(MetaProperty)) - { - return false; - } - return Equals((MetaProperty)obj); - } - - public override int GetHashCode() - { - unchecked - { - return ((GetMethod != null ? GetMethod.GetHashCode() : 0)*397) ^ (SetMethod != null ? SetMethod.GetHashCode() : 0); - } - } - - public bool Equals(MetaProperty other) - { - if (ReferenceEquals(null, other)) - { - return false; - } - - if (ReferenceEquals(this, other)) - { - return true; - } - - if (!Type.Equals(other.Type)) - { - return false; - } - - if (!StringComparer.OrdinalIgnoreCase.Equals(Name, other.Name)) - { - return false; - } - if (Arguments.Length != other.Arguments.Length) - { - return false; - } - for (var i = 0; i < Arguments.Length; i++) - { - if (Arguments[i].Equals(other.Arguments[i]) == false) - { - return false; - } - } - - return true; - } - - public override void SwitchToExplicitImplementation() - { - SwitchToExplicitImplementationName(); - if (setter != null) - { - setter.SwitchToExplicitImplementation(); - } - if (getter != null) - { - getter.SwitchToExplicitImplementation(); - } - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/MetaType.cs b/Castle.Core/DynamicProxy/Generators/MetaType.cs deleted file mode 100644 index cd8e04e..0000000 --- a/Castle.Core/DynamicProxy/Generators/MetaType.cs +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators -{ - using System.Collections.Generic; - using System.Reflection; - - internal class MetaType - { - private readonly MetaTypeElementCollection events = new MetaTypeElementCollection(); - private readonly MetaTypeElementCollection methods = new MetaTypeElementCollection(); - private readonly Dictionary methodsIndex = new Dictionary(); - private readonly MetaTypeElementCollection properties = new MetaTypeElementCollection(); - - public IEnumerable Events - { - get { return events; } - } - - public IEnumerable Methods - { - get { return methods; // NOTE: should be readonly - } - } - - public IEnumerable Properties - { - get { return properties; } - } - - public void AddEvent(MetaEvent @event) - { - events.Add(@event); - } - - public void AddMethod(MetaMethod method) - { - methods.Add(method); - methodsIndex.Add(method.Method, method); // shouldn't get added twice - } - - public void AddProperty(MetaProperty property) - { - properties.Add(property); - } - - public MetaMethod FindMethod(MethodInfo method) - { - return methodsIndex.TryGetValue(method, out var metaMethod) ? metaMethod : null; - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/MetaTypeElement.cs b/Castle.Core/DynamicProxy/Generators/MetaTypeElement.cs deleted file mode 100644 index 12088d8..0000000 --- a/Castle.Core/DynamicProxy/Generators/MetaTypeElement.cs +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators -{ - using System; - using System.Diagnostics; - using System.Reflection; - using System.Text; - - internal abstract class MetaTypeElement - { - private readonly MemberInfo member; - private string name; - - protected MetaTypeElement(MemberInfo member) - { - this.member = member; - this.name = member.Name; - } - - public bool CanBeImplementedExplicitly - { - get { return member.DeclaringType?.IsInterface ?? false; } - } - - public string Name - { - get { return name; } - } - - protected MemberInfo Member - { - get { return member; } - } - - public abstract void SwitchToExplicitImplementation(); - - protected void SwitchToExplicitImplementationName() - { - var name = member.Name; - var sourceType = member.DeclaringType; - var ns = sourceType.Namespace; - Debug.Assert(ns == null || ns != ""); - - if (sourceType.IsGenericType) - { - var nameBuilder = new StringBuilder(); - if (ns != null) - { - nameBuilder.Append(ns); - nameBuilder.Append('.'); - } - AppendTypeName(nameBuilder, sourceType); - nameBuilder.Append('.'); - nameBuilder.Append(name); - this.name = nameBuilder.ToString(); - } - else if (ns != null) - { - this.name = string.Concat(ns, ".", sourceType.Name, ".", name); - } - else - { - this.name = string.Concat(sourceType.Name, ".", name); - } - - static void AppendTypeName(StringBuilder nameBuilder, Type type) - { - nameBuilder.Append(type.Name); - if (type.IsGenericType) - { - nameBuilder.Append('['); - var genericTypeArguments = type.GetGenericArguments(); - for (int i = 0, n = genericTypeArguments.Length; i < n; ++i) - { - if (i > 0) - { - nameBuilder.Append(','); - } - AppendTypeName(nameBuilder, genericTypeArguments[i]); - } - nameBuilder.Append(']'); - } - } - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/MetaTypeElementCollection.cs b/Castle.Core/DynamicProxy/Generators/MetaTypeElementCollection.cs deleted file mode 100644 index 210b2f1..0000000 --- a/Castle.Core/DynamicProxy/Generators/MetaTypeElementCollection.cs +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators -{ - using System; - using System.Collections; - using System.Collections.Generic; - - internal class MetaTypeElementCollection : IEnumerable - where TElement : MetaTypeElement, IEquatable - { - private readonly ICollection items = new List(); - - public void Add(TElement item) - { - if (item.CanBeImplementedExplicitly == false) - { - items.Add(item); - return; - } - if (Contains(item)) - { - item.SwitchToExplicitImplementation(); - if (Contains(item)) - { - // there is something *really* wrong going on here - throw new DynamicProxyException("Duplicate element: " + item); - } - } - items.Add(item); - } - - public bool Contains(TElement item) - { - foreach (var element in items) - { - if (element.Equals(item)) - { - return true; - } - } - - return false; - } - - public IEnumerator GetEnumerator() - { - return items.GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/MethodFinder.cs b/Castle.Core/DynamicProxy/Generators/MethodFinder.cs deleted file mode 100644 index 976f2d5..0000000 --- a/Castle.Core/DynamicProxy/Generators/MethodFinder.cs +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators -{ - using System; - using System.Collections.Generic; - using System.Linq; - using System.Reflection; - - /// - /// Returns the methods implemented by a type. Use this instead of Type.GetMethods() to work around a CLR issue - /// where duplicate MethodInfos are returned by Type.GetMethods() after a token of a generic type's method was loaded. - /// - internal class MethodFinder - { - private static readonly Dictionary cachedMethodInfosByType = new Dictionary(); - private static readonly object lockObject = new object(); - - public static MethodInfo[] GetAllInstanceMethods(Type type, BindingFlags flags) - { - if ((flags & ~(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) != 0) - { - throw new ArgumentException("MethodFinder only supports the Public, NonPublic, and Instance binding flags.", nameof(flags)); - } - - MethodInfo[] methodsInCache; - - lock (lockObject) - { - if (!cachedMethodInfosByType.TryGetValue(type, out methodsInCache)) - { - // We always load all instance methods into the cache, we will filter them later - methodsInCache = type.GetMethods( - BindingFlags.Public | BindingFlags.NonPublic - | BindingFlags.Instance) - .Distinct(MethodSignatureComparer.Instance) - .ToArray(); - cachedMethodInfosByType.Add( - type, - methodsInCache); - } - } - return MakeFilteredCopy(methodsInCache, flags & (BindingFlags.Public | BindingFlags.NonPublic)); - } - - private static MethodInfo[] MakeFilteredCopy(MethodInfo[] methodsInCache, BindingFlags visibilityFlags) - { - if ((visibilityFlags & ~(BindingFlags.Public | BindingFlags.NonPublic)) != 0) - { - throw new ArgumentException("Only supports BindingFlags.Public and NonPublic.", nameof(visibilityFlags)); - } - - var includePublic = (visibilityFlags & BindingFlags.Public) == BindingFlags.Public; - var includeNonPublic = (visibilityFlags & BindingFlags.NonPublic) == BindingFlags.NonPublic; - - // Return a copy of the cached array, only returning the public methods unless requested otherwise - var result = new List(methodsInCache.Length); - - foreach (var method in methodsInCache) - { - if ((method.IsPublic && includePublic) || (!method.IsPublic && includeNonPublic)) - { - result.Add(method); - } - } - - return result.ToArray(); - } - - } -} diff --git a/Castle.Core/DynamicProxy/Generators/MethodGenerator.cs b/Castle.Core/DynamicProxy/Generators/MethodGenerator.cs deleted file mode 100644 index 2bf207f..0000000 --- a/Castle.Core/DynamicProxy/Generators/MethodGenerator.cs +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators -{ - using System.Reflection; - - using Castle.DynamicProxy.Contributors; - using Castle.DynamicProxy.Generators.Emitters; - - internal abstract class MethodGenerator : IGenerator - { - private readonly MetaMethod method; - private readonly OverrideMethodDelegate overrideMethod; - - protected MethodGenerator(MetaMethod method, OverrideMethodDelegate overrideMethod) - { - this.method = method; - this.overrideMethod = overrideMethod; - } - - protected MethodInfo MethodOnTarget - { - get { return method.MethodOnTarget; } - } - - protected MethodInfo MethodToOverride - { - get { return method.Method; } - } - - protected abstract MethodEmitter BuildProxiedMethodBody(MethodEmitter emitter, ClassEmitter @class, - INamingScope namingScope); - - public MethodEmitter Generate(ClassEmitter @class, INamingScope namingScope) - { - var methodEmitter = overrideMethod(method.Name, method.Attributes, MethodToOverride); - var proxiedMethod = BuildProxiedMethodBody(methodEmitter, @class, namingScope); - - if (MethodToOverride.DeclaringType.IsInterface) - { - @class.TypeBuilder.DefineMethodOverride(proxiedMethod.MethodBuilder, MethodToOverride); - } - - return proxiedMethod; - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/MethodSignatureComparer.cs b/Castle.Core/DynamicProxy/Generators/MethodSignatureComparer.cs deleted file mode 100644 index 87be2ca..0000000 --- a/Castle.Core/DynamicProxy/Generators/MethodSignatureComparer.cs +++ /dev/null @@ -1,159 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators -{ - using System; - using System.Collections.Generic; - using System.Reflection; - - internal class MethodSignatureComparer : IEqualityComparer - { - public static readonly MethodSignatureComparer Instance = new MethodSignatureComparer(); - - public bool EqualGenericParameters(MethodInfo x, MethodInfo y) - { - if (x.IsGenericMethod != y.IsGenericMethod) - { - return false; - } - - if (x.IsGenericMethod) - { - var xArgs = x.GetGenericArguments(); - var yArgs = y.GetGenericArguments(); - - if (xArgs.Length != yArgs.Length) - { - return false; - } - - for (var i = 0; i < xArgs.Length; ++i) - { - if (xArgs[i].IsGenericParameter != yArgs[i].IsGenericParameter) - { - return false; - } - - if (!xArgs[i].IsGenericParameter && !xArgs[i].Equals(yArgs[i])) - { - return false; - } - } - } - - return true; - } - - public bool EqualParameters(MethodInfo x, MethodInfo y) - { - var xArgs = x.GetParameters(); - var yArgs = y.GetParameters(); - - if (xArgs.Length != yArgs.Length) - { - return false; - } - - for (var i = 0; i < xArgs.Length; ++i) - { - if (!EqualSignatureTypes(xArgs[i].ParameterType, yArgs[i].ParameterType)) - { - return false; - } - } - - return true; - } - - public bool EqualSignatureTypes(Type x, Type y) - { - if (x.IsGenericParameter != y.IsGenericParameter) - { - return false; - } - else if (x.IsGenericType != y.IsGenericType) - { - return false; - } - - if (x.IsGenericParameter) - { - if (x.GenericParameterPosition != y.GenericParameterPosition) - { - return false; - } - } - else if (x.IsGenericType) - { - var xGenericTypeDef = x.GetGenericTypeDefinition(); - var yGenericTypeDef = y.GetGenericTypeDefinition(); - - if (xGenericTypeDef != yGenericTypeDef) - { - return false; - } - - var xArgs = x.GetGenericArguments(); - var yArgs = y.GetGenericArguments(); - - if (xArgs.Length != yArgs.Length) - { - return false; - } - - for (var i = 0; i < xArgs.Length; ++i) - { - if(!EqualSignatureTypes(xArgs[i], yArgs[i])) return false; - } - } - else - { - if (!x.Equals(y)) - { - return false; - } - } - return true; - } - - public bool Equals(MethodInfo x, MethodInfo y) - { - if (x == null && y == null) - { - return true; - } - - if (x == null || y == null) - { - return false; - } - - return EqualNames(x, y) && - EqualGenericParameters(x, y) && - EqualSignatureTypes(x.ReturnType, y.ReturnType) && - EqualParameters(x, y); - } - - public int GetHashCode(MethodInfo obj) - { - return obj.Name.GetHashCode() ^ obj.GetParameters().Length; // everything else would be too cumbersome - } - - private bool EqualNames(MethodInfo x, MethodInfo y) - { - return x.Name == y.Name; - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/MethodWithInvocationGenerator.cs b/Castle.Core/DynamicProxy/Generators/MethodWithInvocationGenerator.cs deleted file mode 100644 index 6d2b5d6..0000000 --- a/Castle.Core/DynamicProxy/Generators/MethodWithInvocationGenerator.cs +++ /dev/null @@ -1,251 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators -{ - using System; - using System.Diagnostics; - using System.Reflection; - using System.Reflection.Emit; -#if FEATURE_SERIALIZATION - using System.Xml.Serialization; -#endif - - using Castle.Core.Internal; - using Castle.DynamicProxy.Contributors; - using Castle.DynamicProxy.Generators.Emitters; - using Castle.DynamicProxy.Generators.Emitters.SimpleAST; - using Castle.DynamicProxy.Internal; - using Castle.DynamicProxy.Tokens; - - internal class MethodWithInvocationGenerator : MethodGenerator - { - private readonly IInvocationCreationContributor contributor; - private readonly GetTargetExpressionDelegate getTargetExpression; - private readonly GetTargetExpressionDelegate getTargetTypeExpression; - private readonly IExpression interceptors; - private readonly Type invocation; - - public MethodWithInvocationGenerator(MetaMethod method, IExpression interceptors, Type invocation, - GetTargetExpressionDelegate getTargetExpression, - OverrideMethodDelegate createMethod, IInvocationCreationContributor contributor) - : this(method, interceptors, invocation, getTargetExpression, null, createMethod, contributor) - { - } - - public MethodWithInvocationGenerator(MetaMethod method, IExpression interceptors, Type invocation, - GetTargetExpressionDelegate getTargetExpression, - GetTargetExpressionDelegate getTargetTypeExpression, - OverrideMethodDelegate createMethod, IInvocationCreationContributor contributor) - : base(method, createMethod) - { - this.invocation = invocation; - this.getTargetExpression = getTargetExpression; - this.getTargetTypeExpression = getTargetTypeExpression; - this.interceptors = interceptors; - this.contributor = contributor; - } - - protected FieldReference BuildMethodInterceptorsField(ClassEmitter @class, MethodInfo method, INamingScope namingScope) - { - var methodInterceptors = @class.CreateField( - namingScope.GetUniqueName(string.Format("interceptors_{0}", method.Name)), - typeof(IInterceptor[]), - false); -#if FEATURE_SERIALIZATION - @class.DefineCustomAttributeFor(methodInterceptors); -#endif - return methodInterceptors; - } - - protected override MethodEmitter BuildProxiedMethodBody(MethodEmitter emitter, ClassEmitter @class, INamingScope namingScope) - { - var invocationType = invocation; - - var genericArguments = Type.EmptyTypes; - - var constructor = invocation.GetConstructors()[0]; - - IExpression proxiedMethodTokenExpression; - if (MethodToOverride.IsGenericMethod) - { - // Not in the cache: generic method - genericArguments = emitter.MethodBuilder.GetGenericArguments(); - proxiedMethodTokenExpression = new MethodTokenExpression(MethodToOverride.MakeGenericMethod(genericArguments)); - - if (invocationType.IsGenericTypeDefinition) - { - // bind generic method arguments to invocation's type arguments - invocationType = invocationType.MakeGenericType(genericArguments); - constructor = TypeBuilder.GetConstructor(invocationType, constructor); - } - } - else - { - var proxiedMethodToken = @class.CreateStaticField(namingScope.GetUniqueName("token_" + MethodToOverride.Name), typeof(MethodInfo)); - @class.ClassConstructor.CodeBuilder.AddStatement(new AssignStatement(proxiedMethodToken, new MethodTokenExpression(MethodToOverride))); - - proxiedMethodTokenExpression = proxiedMethodToken; - } - - var methodInterceptors = SetMethodInterceptors(@class, namingScope, emitter, proxiedMethodTokenExpression); - - var dereferencedArguments = IndirectReference.WrapIfByRef(emitter.Arguments); - var hasByRefArguments = HasByRefArguments(emitter.Arguments); - - var arguments = GetCtorArguments(@class, proxiedMethodTokenExpression, dereferencedArguments, methodInterceptors); - var ctorArguments = ModifyArguments(@class, arguments); - - var invocationLocal = emitter.CodeBuilder.DeclareLocal(invocationType); - emitter.CodeBuilder.AddStatement(new AssignStatement(invocationLocal, - new NewInstanceExpression(constructor, ctorArguments))); - - if (MethodToOverride.ContainsGenericParameters) - { - EmitLoadGenricMethodArguments(emitter, MethodToOverride.MakeGenericMethod(genericArguments), invocationLocal); - } - - if (hasByRefArguments) - { - emitter.CodeBuilder.AddStatement(new TryStatement()); - } - - var proceed = new MethodInvocationExpression(invocationLocal, InvocationMethods.Proceed); - emitter.CodeBuilder.AddStatement(proceed); - - if (hasByRefArguments) - { - emitter.CodeBuilder.AddStatement(new FinallyStatement()); - } - - GeneratorUtil.CopyOutAndRefParameters(dereferencedArguments, invocationLocal, MethodToOverride, emitter); - - if (hasByRefArguments) - { - emitter.CodeBuilder.AddStatement(new EndExceptionBlockStatement()); - } - - if (MethodToOverride.ReturnType != typeof(void)) - { - var getRetVal = new MethodInvocationExpression(invocationLocal, InvocationMethods.GetReturnValue); - - // Emit code to ensure a value type return type is not null, otherwise the cast will cause a null-deref - if (emitter.ReturnType.IsValueType && !emitter.ReturnType.IsNullableType()) - { - LocalReference returnValue = emitter.CodeBuilder.DeclareLocal(typeof(object)); - emitter.CodeBuilder.AddStatement(new AssignStatement(returnValue, getRetVal)); - - emitter.CodeBuilder.AddStatement(new IfNullExpression(returnValue, new ThrowStatement(typeof(InvalidOperationException), - "Interceptors failed to set a return value, or swallowed the exception thrown by the target"))); - } - - // Emit code to return with cast from ReturnValue - emitter.CodeBuilder.AddStatement(new ReturnStatement(new ConvertExpression(emitter.ReturnType, getRetVal))); - } - else - { - emitter.CodeBuilder.AddStatement(new ReturnStatement()); - } - - return emitter; - } - - private IExpression SetMethodInterceptors(ClassEmitter @class, INamingScope namingScope, MethodEmitter emitter, IExpression proxiedMethodTokenExpression) - { - var selector = @class.GetField("__selector"); - if(selector == null) - { - return null; - } - - var methodInterceptorsField = BuildMethodInterceptorsField(@class, MethodToOverride, namingScope); - - IExpression targetTypeExpression; - if (getTargetTypeExpression != null) - { - targetTypeExpression = getTargetTypeExpression(@class, MethodToOverride); - } - else - { - targetTypeExpression = new MethodInvocationExpression(null, TypeUtilMethods.GetTypeOrNull, getTargetExpression(@class, MethodToOverride)); - } - - var emptyInterceptors = new NewArrayExpression(0, typeof(IInterceptor)); - var selectInterceptors = new MethodInvocationExpression(selector, InterceptorSelectorMethods.SelectInterceptors, - targetTypeExpression, - proxiedMethodTokenExpression, interceptors) - { VirtualCall = true }; - - emitter.CodeBuilder.AddStatement( - new IfNullExpression(methodInterceptorsField, - new AssignStatement(methodInterceptorsField, - new NullCoalescingOperatorExpression(selectInterceptors, emptyInterceptors)))); - - return methodInterceptorsField; - } - - private void EmitLoadGenricMethodArguments(MethodEmitter methodEmitter, MethodInfo method, Reference invocationLocal) - { - var genericParameters = Array.FindAll(method.GetGenericArguments(), t => t.IsGenericParameter); - var genericParamsArrayLocal = methodEmitter.CodeBuilder.DeclareLocal(typeof(Type[])); - methodEmitter.CodeBuilder.AddStatement( - new AssignStatement(genericParamsArrayLocal, new NewArrayExpression(genericParameters.Length, typeof(Type)))); - - for (var i = 0; i < genericParameters.Length; ++i) - { - methodEmitter.CodeBuilder.AddStatement( - new AssignArrayStatement(genericParamsArrayLocal, i, new TypeTokenExpression(genericParameters[i]))); - } - methodEmitter.CodeBuilder.AddStatement( - new MethodInvocationExpression(invocationLocal, - InvocationMethods.SetGenericMethodArguments, - genericParamsArrayLocal)); - } - - private IExpression[] GetCtorArguments(ClassEmitter @class, IExpression proxiedMethodTokenExpression, TypeReference[] dereferencedArguments, IExpression methodInterceptors) - { - return new[] - { - getTargetExpression(@class, MethodToOverride), - SelfReference.Self, - methodInterceptors ?? interceptors, - proxiedMethodTokenExpression, - new ReferencesToObjectArrayExpression(dereferencedArguments) - }; - } - - private IExpression[] ModifyArguments(ClassEmitter @class, IExpression[] arguments) - { - if (contributor == null) - { - return arguments; - } - - return contributor.GetConstructorInvocationArguments(arguments, @class); - } - - private bool HasByRefArguments(ArgumentReference[] arguments) - { - for (int i = 0; i < arguments.Length; i++ ) - { - if (arguments[i].Type.IsByRef) - { - return true; - } - } - - return false; - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/MinimialisticMethodGenerator.cs b/Castle.Core/DynamicProxy/Generators/MinimialisticMethodGenerator.cs deleted file mode 100644 index fae27db..0000000 --- a/Castle.Core/DynamicProxy/Generators/MinimialisticMethodGenerator.cs +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators -{ - using System.Reflection; - - using Castle.DynamicProxy.Contributors; - using Castle.DynamicProxy.Generators.Emitters; - using Castle.DynamicProxy.Generators.Emitters.SimpleAST; - - internal class MinimialisticMethodGenerator : MethodGenerator - { - public MinimialisticMethodGenerator(MetaMethod method, OverrideMethodDelegate overrideMethod) - : base(method, overrideMethod) - { - } - - protected override MethodEmitter BuildProxiedMethodBody(MethodEmitter emitter, ClassEmitter @class, - INamingScope namingScope) - { - InitOutParameters(emitter, MethodToOverride.GetParameters()); - - if (emitter.ReturnType == typeof(void)) - { - emitter.CodeBuilder.AddStatement(new ReturnStatement()); - } - else - { - emitter.CodeBuilder.AddStatement(new ReturnStatement(new DefaultValueExpression(emitter.ReturnType))); - } - - return emitter; - } - - private void InitOutParameters(MethodEmitter emitter, ParameterInfo[] parameters) - { - for (var index = 0; index < parameters.Length; index++) - { - var parameter = parameters[index]; - if (parameter.IsOut) - { - emitter.CodeBuilder.AddStatement( - new AssignArgumentStatement(new ArgumentReference(parameter.ParameterType, index + 1), - new DefaultValueExpression(parameter.ParameterType))); - } - } - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/NamingScope.cs b/Castle.Core/DynamicProxy/Generators/NamingScope.cs deleted file mode 100644 index 57958b2..0000000 --- a/Castle.Core/DynamicProxy/Generators/NamingScope.cs +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators -{ - using System.Collections.Generic; - using System.Diagnostics; - - internal class NamingScope : INamingScope - { - private readonly IDictionary names = new Dictionary(); - private readonly INamingScope parentScope; - - public NamingScope() - { - } - - private NamingScope(INamingScope parent) - { - parentScope = parent; - } - - public INamingScope ParentScope - { - get { return parentScope; } - } - - public string GetUniqueName(string suggestedName) - { - Debug.Assert(string.IsNullOrEmpty(suggestedName) == false, - "string.IsNullOrEmpty(suggestedName) == false"); - - int counter; - if (!names.TryGetValue(suggestedName, out counter)) - { - names.Add(suggestedName, 0); - return suggestedName; - } - - counter++; - names[suggestedName] = counter; - return suggestedName + "_" + counter.ToString(); - } - - public INamingScope SafeSubScope() - { - return new NamingScope(this); - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Generators/OptionallyForwardingMethodGenerator.cs b/Castle.Core/DynamicProxy/Generators/OptionallyForwardingMethodGenerator.cs deleted file mode 100644 index 51a36f2..0000000 --- a/Castle.Core/DynamicProxy/Generators/OptionallyForwardingMethodGenerator.cs +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Generators -{ - using System; - using System.Reflection; - - using Castle.DynamicProxy.Contributors; - using Castle.DynamicProxy.Generators.Emitters; - using Castle.DynamicProxy.Generators.Emitters.SimpleAST; - - internal class OptionallyForwardingMethodGenerator : MethodGenerator - { - // TODO: This class largely duplicates code from Forwarding and Minimalistic generators. Should be refactored to change that - private readonly GetTargetReferenceDelegate getTargetReference; - - public OptionallyForwardingMethodGenerator(MetaMethod method, OverrideMethodDelegate overrideMethod, - GetTargetReferenceDelegate getTargetReference) - : base(method, overrideMethod) - { - this.getTargetReference = getTargetReference; - } - - protected override MethodEmitter BuildProxiedMethodBody(MethodEmitter emitter, ClassEmitter @class, - INamingScope namingScope) - { - var targetReference = getTargetReference(@class, MethodToOverride); - - emitter.CodeBuilder.AddStatement( - new IfNullExpression( - targetReference, - IfNull(emitter.ReturnType), - IfNotNull(targetReference))); - - return emitter; - } - - private IStatement IfNotNull(Reference targetReference) - { - var statements = new BlockStatement(); - var arguments = ArgumentsUtil.ConvertToArgumentReferenceExpression(MethodToOverride.GetParameters()); - - statements.AddStatement(new ReturnStatement( - new MethodInvocationExpression( - targetReference, - MethodToOverride, - arguments) { VirtualCall = true })); - return statements; - } - - private IStatement IfNull(Type returnType) - { - var statements = new BlockStatement(); - InitOutParameters(statements, MethodToOverride.GetParameters()); - - if (returnType == typeof(void)) - { - statements.AddStatement(new ReturnStatement()); - } - else - { - statements.AddStatement(new ReturnStatement(new DefaultValueExpression(returnType))); - } - return statements; - } - - private void InitOutParameters(BlockStatement statements, ParameterInfo[] parameters) - { - for (var index = 0; index < parameters.Length; index++) - { - var parameter = parameters[index]; - if (parameter.IsOut) - { - statements.AddStatement( - new AssignArgumentStatement(new ArgumentReference(parameter.ParameterType, index + 1), - new DefaultValueExpression(parameter.ParameterType))); - } - } - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/IChangeProxyTarget.cs b/Castle.Core/DynamicProxy/IChangeProxyTarget.cs deleted file mode 100644 index 8250203..0000000 --- a/Castle.Core/DynamicProxy/IChangeProxyTarget.cs +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy -{ - using System; - - /// - /// Exposes means to change target objects of proxies and invocations. - /// - public interface IChangeProxyTarget - { - /// - /// Changes the target object () of current . - /// - /// The new value of target of invocation. - /// - /// Although the method takes the actual instance must be of type assignable to , otherwise an will be thrown. - /// Also while it's technically legal to pass null reference (Nothing in Visual Basic) as , for obvious reasons Dynamic Proxy will not be able to call the intercepted method on such target. - /// In this case last interceptor in the pipeline mustn't call or a will be throws. - /// Also while it's technically legal to pass proxy itself as , this would create stack overflow. - /// In this case last interceptor in the pipeline mustn't call or a will be throws. - /// - /// Thrown when is not assignable to the proxied type. - void ChangeInvocationTarget(object target); - - /// - /// Permanently changes the target object of the proxy. This does not affect target of the current invocation. - /// - /// The new value of target of the proxy. - /// - /// Although the method takes the actual instance must be of type assignable to proxy's target type, otherwise an will be thrown. - /// Also while it's technically legal to pass null reference (Nothing in Visual Basic) as , for obvious reasons Dynamic Proxy will not be able to call the intercepted method on such target. - /// In this case last interceptor in the pipeline mustn't call or a will be throws. - /// Also while it's technically legal to pass proxy itself as , this would create stack overflow. - /// In this case last interceptor in the pipeline mustn't call or a will be throws. - /// - /// Thrown when is not assignable to the proxied type. - [Obsolete("Use ((IProxyTargetAccessor)invocation.Proxy).DynProxySetTarget(target) instead.")] - void ChangeProxyTarget(object target); - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/IInterceptor.cs b/Castle.Core/DynamicProxy/IInterceptor.cs deleted file mode 100644 index f5f4378..0000000 --- a/Castle.Core/DynamicProxy/IInterceptor.cs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy -{ - /// - /// Provides the main DynamicProxy extension point that allows member interception. - /// - public interface IInterceptor - { - void Intercept(IInvocation invocation); - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/IInterceptorSelector.cs b/Castle.Core/DynamicProxy/IInterceptorSelector.cs deleted file mode 100644 index 86d46bd..0000000 --- a/Castle.Core/DynamicProxy/IInterceptorSelector.cs +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy -{ - using System; - using System.Reflection; - - /// - /// Provides an extension point that allows proxies to choose specific interceptors on - /// a per method basis. - /// - public interface IInterceptorSelector - { - /// - /// Selects the interceptors that should intercept calls to the given . - /// - /// The type of the target object. - /// The method that will be intercepted. - /// All interceptors registered with the proxy. - /// An array of interceptors to invoke upon calling the . - /// - /// This method is called only once per proxy instance, upon the first call to the - /// . Either an empty array or null are valid return values to indicate - /// that no interceptor should intercept calls to the method. Although it is not advised, it is - /// legal to return other implementations than these provided in - /// . - /// - IInterceptor[] SelectInterceptors(Type type, MethodInfo method, IInterceptor[] interceptors); - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/IInvocation.cs b/Castle.Core/DynamicProxy/IInvocation.cs deleted file mode 100644 index 861eaab..0000000 --- a/Castle.Core/DynamicProxy/IInvocation.cs +++ /dev/null @@ -1,135 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy -{ - using System; - using System.Reflection; - - /// - /// Encapsulates an invocation of a proxied method. - /// - public interface IInvocation - { - /// - /// Gets the arguments that the has been invoked with. - /// - /// The arguments the method was invoked with. - object[] Arguments { get; } - - /// - /// Gets the generic arguments of the method. - /// - /// The generic arguments, or null if not a generic method. - Type[] GenericArguments { get; } - - /// - /// Gets the object on which the invocation is performed. This is different from proxy object - /// because most of the time this will be the proxy target object. - /// - /// - /// The invocation target. - object InvocationTarget { get; } - - /// - /// Gets the representing the method being invoked on the proxy. - /// - /// The representing the method being invoked. - MethodInfo Method { get; } - - /// - /// For interface proxies, this will point to the on the target class. - /// - /// The method invocation target. - MethodInfo MethodInvocationTarget { get; } - - /// - /// Gets the proxy object on which the intercepted method is invoked. - /// - /// Proxy object on which the intercepted method is invoked. - object Proxy { get; } - - /// - /// Gets or sets the return value of the method. - /// - /// The return value of the method. - object ReturnValue { get; set; } - - /// - /// Gets the type of the target object for the intercepted method. - /// - /// The type of the target object. - Type TargetType { get; } - - /// - /// Gets the value of the argument at the specified . - /// - /// The index. - /// The value of the argument at the specified . - object GetArgumentValue(int index); - - /// - /// Returns the concrete instantiation of the on the proxy, with any generic - /// parameters bound to real types. - /// - /// - /// The concrete instantiation of the on the proxy, or the if - /// not a generic method. - /// - /// - /// Can be slower than calling . - /// - MethodInfo GetConcreteMethod(); - - /// - /// Returns the concrete instantiation of , with any - /// generic parameters bound to real types. - /// For interface proxies, this will point to the on the target class. - /// - /// The concrete instantiation of , or - /// if not a generic method. - /// - /// In debug builds this can be slower than calling . - /// - MethodInfo GetConcreteMethodInvocationTarget(); - - /// - /// Proceeds the call to the next interceptor in line, and ultimately to the target method. - /// - /// - /// Since interface proxies without a target don't have the target implementation to proceed to, - /// it is important, that the last interceptor does not call this method, otherwise a - /// will be thrown. - /// - void Proceed(); - - /// - /// Returns an object describing the operation for this - /// at this specific point during interception. - /// - IInvocationProceedInfo CaptureProceedInfo(); - - /// - /// Overrides the value of an argument at the given with the - /// new provided. - /// - /// - /// This method accepts an , however the value provided must be compatible - /// with the type of the argument defined on the method, otherwise an exception will be thrown. - /// - /// The index of the argument to override. - /// The new value for the argument. - void SetArgumentValue(int index, object value); - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/IInvocationProceedInfo.cs b/Castle.Core/DynamicProxy/IInvocationProceedInfo.cs deleted file mode 100644 index 4994798..0000000 --- a/Castle.Core/DynamicProxy/IInvocationProceedInfo.cs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy -{ - using System; - - /// - /// Describes the operation for an - /// at a specific point during interception. - /// - public interface IInvocationProceedInfo - { - /// - /// Executes the operation described by this instance. - /// - /// There is no interceptor, nor a proxy target object, to proceed to. - void Invoke(); - } -} diff --git a/Castle.Core/DynamicProxy/IProxyBuilder.cs b/Castle.Core/DynamicProxy/IProxyBuilder.cs deleted file mode 100644 index 84a525b..0000000 --- a/Castle.Core/DynamicProxy/IProxyBuilder.cs +++ /dev/null @@ -1,137 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy -{ - using System; - using System.Runtime.CompilerServices; - - using Castle.Core.Logging; - using Castle.DynamicProxy.Generators; - - /// - /// Abstracts the implementation of proxy type construction. - /// - public interface IProxyBuilder - { - /// - /// Gets or sets the that this logs to. - /// - ILogger Logger { get; set; } - - /// - /// Gets the associated with this builder. - /// - /// The module scope associated with this builder. - ModuleScope ModuleScope { get; } - - /// - /// Creates a proxy type for given , implementing , using provided. - /// - /// The class type to proxy. - /// Additional interface types to proxy. - /// The proxy generation options. - /// The generated proxy type. - /// - /// Implementers should return a proxy type for the specified class and interfaces. - /// Additional interfaces should be only 'mark' interfaces, that is, they should work like interface proxy without target. (See method.) - /// - /// Thrown when or any of is a generic type definition. - /// Thrown when or any of is not public. - /// Note that to avoid this exception, you can mark offending type internal, and define - /// pointing to Castle Dynamic Proxy assembly, in assembly containing that type, if this is appropriate. - /// - Type CreateClassProxyType(Type classToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options); - - Type CreateClassProxyTypeWithTarget(Type classToProxy, Type[] additionalInterfacesToProxy, - ProxyGenerationOptions options); - - /// - /// Creates a proxy type that proxies calls to members on , implementing , using provided. - /// - /// The interface type to proxy. - /// Additional interface types to proxy. - /// Type implementing on which calls to the interface members should be intercepted. - /// The proxy generation options. - /// The generated proxy type. - /// - /// Implementers should return a proxy type for the specified interface that 'proceeds' executions to the specified target. - /// Additional interfaces should be only 'mark' interfaces, that is, they should work like interface proxy without target. (See method.) - /// - /// Thrown when or any of is a generic type definition. - /// Thrown when or any of is not public. - /// Note that to avoid this exception, you can mark offending type internal, and define - /// pointing to Castle Dynamic Proxy assembly, in assembly containing that type, if this is appropriate. - /// - Type CreateInterfaceProxyTypeWithTarget(Type interfaceToProxy, Type[] additionalInterfacesToProxy, Type targetType, - ProxyGenerationOptions options); - - /// - /// Creates a proxy type for given and that delegates all calls to the provided interceptors and allows interceptors to switch the actual target of invocation. - /// - /// The interface type to proxy. - /// Additional interface types to proxy. - /// The proxy generation options. - /// The generated proxy type. - /// - /// Implementers should return a proxy type for the specified interface(s) that delegate all executions to the specified interceptors - /// and uses an instance of the interface as their targets (i.e. ), rather than a class. All classes should then implement interface, - /// to allow interceptors to switch invocation target with instance of another type implementing called interface. - /// - /// Thrown when or any of is a generic type definition. - /// Thrown when or any of is not public. - /// Note that to avoid this exception, you can mark offending type internal, and define - /// pointing to Castle Dynamic Proxy assembly, in assembly containing that type, if this is appropriate. - /// - Type CreateInterfaceProxyTypeWithTargetInterface(Type interfaceToProxy, Type[] additionalInterfacesToProxy, - ProxyGenerationOptions options); - - /// - /// Creates a proxy type for given that delegates all calls to the provided interceptors. - /// - /// The interface type to proxy. - /// Additional interface types to proxy. - /// The proxy generation options. - /// The generated proxy type. - /// - /// Implementers should return a proxy type for the specified interface and additional interfaces that delegate all executions to the specified interceptors. - /// - /// Thrown when or any of is a generic type definition. - /// Thrown when or any of is not public. - /// Note that to avoid this exception, you can mark offending type internal, and define - /// pointing to Castle Dynamic Proxy assembly, in assembly containing that type, if this is appropriate. - /// - Type CreateInterfaceProxyTypeWithoutTarget(Type interfaceToProxy, Type[] additionalInterfacesToProxy, - ProxyGenerationOptions options); - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/IProxyGenerationHook.cs b/Castle.Core/DynamicProxy/IProxyGenerationHook.cs deleted file mode 100644 index 93826e9..0000000 --- a/Castle.Core/DynamicProxy/IProxyGenerationHook.cs +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy -{ - using System; - using System.Reflection; - - /// - /// Used during the target type inspection process. Implementors have a chance to customize the - /// proxy generation process. - /// - public interface IProxyGenerationHook - { - /// - /// Invoked by the generation process to notify that the whole process has completed. - /// - void MethodsInspected(); - - /// - /// Invoked by the generation process to notify that a member was not marked as virtual. - /// - /// The type which declares the non-virtual member. - /// The non-virtual member. - /// - /// This method gives an opportunity to inspect any non-proxyable member of a type that has - /// been requested to be proxied, and if appropriate - throw an exception to notify the caller. - /// - void NonProxyableMemberNotification(Type type, MemberInfo memberInfo); - - /// - /// Invoked by the generation process to determine if the specified method should be proxied. - /// - /// The type which declares the given method. - /// The method to inspect. - /// True if the given method should be proxied; false otherwise. - bool ShouldInterceptMethod(Type type, MethodInfo methodInfo); - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/IProxyGenerator.cs b/Castle.Core/DynamicProxy/IProxyGenerator.cs deleted file mode 100644 index 82b202c..0000000 --- a/Castle.Core/DynamicProxy/IProxyGenerator.cs +++ /dev/null @@ -1,1033 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy -{ - using System; - using System.Reflection; - - using Castle.Core.Logging; - - /// - /// Provides proxy objects for classes and interfaces. - /// - [CLSCompliant(true)] - public interface IProxyGenerator - { - /// - /// Gets or sets the that this log to. - /// - ILogger Logger { get; set; } - - /// - /// Gets the proxy builder instance used to generate proxy types. - /// - /// The proxy builder. - IProxyBuilder ProxyBuilder { get; } - - /// - /// Creates proxy object intercepting calls to members of interface on object with given . - /// - /// Type of the interface implemented by which will be proxied. - /// The target object, calls to which will be intercepted. - /// The interceptors called during the invocation of proxied methods. - /// Object proxying calls to members of on object. - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given array is a null reference (Nothing in Visual Basic). - /// Thrown when given is not an interface type. - /// Thrown when no default constructor exists on actual type of object. - /// Thrown when default constructor of actual type of throws an exception. - /// - /// This method generates new proxy type for each type of , which affects performance. If you don't want to proxy types differently depending on the type of the target - /// use method. - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - TInterface CreateInterfaceProxyWithTarget(TInterface target, params IInterceptor[] interceptors) - where TInterface : class; - - /// - /// Creates proxy object intercepting calls to members of interface on object with given . - /// - /// Type of the interface implemented by which will be proxied. - /// The target object, calls to which will be intercepted. - /// The proxy generation options used to influence generated proxy type and object. - /// The interceptors called during the invocation of proxied methods. - /// - /// Object proxying calls to members of on object. - /// - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given array is a null reference (Nothing in Visual Basic). - /// Thrown when given is not an interface type. - /// Thrown when no default constructor exists on actual type of object. - /// Thrown when default constructor of actual type of throws an exception. - /// - /// This method generates new proxy type for each type of , which affects performance. If you don't want to proxy types differently depending on the type of the target - /// use method. - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - TInterface CreateInterfaceProxyWithTarget(TInterface target, ProxyGenerationOptions options, - params IInterceptor[] interceptors) - where TInterface : class; - - /// - /// Creates proxy object intercepting calls to members of interface on object with given . - /// - /// Type of the interface implemented by which will be proxied. - /// The target object, calls to which will be intercepted. - /// The interceptors called during the invocation of proxied methods. - /// - /// Object proxying calls to members of type on object. - /// - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given array is a null reference (Nothing in Visual Basic). - /// Thrown when given is a generic type definition. - /// Thrown when given is not an interface type. - /// Thrown when given does not implement interface. - /// Thrown when no default constructor exists on actual type of object. - /// Thrown when default constructor of actual type of throws an exception. - /// - /// This method generates new proxy type for each type of , which affects performance. If you don't want to proxy types differently depending on the type of the target - /// use method. - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - object CreateInterfaceProxyWithTarget(Type interfaceToProxy, object target, params IInterceptor[] interceptors); - - /// - /// Creates proxy object intercepting calls to members of interface on object with given . - /// - /// Type of the interface implemented by which will be proxied. - /// The target object, calls to which will be intercepted. - /// The proxy generation options used to influence generated proxy type and object. - /// The interceptors called during the invocation of proxied methods. - /// - /// Object proxying calls to members of type on object. - /// - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given array is a null reference (Nothing in Visual Basic). - /// Thrown when given is a generic type definition. - /// Thrown when given is not an interface type. - /// Thrown when given does not implement interface. - /// Thrown when no default constructor exists on actual type of object. - /// Thrown when default constructor of actual type of throws an exception. - /// - /// This method generates new proxy type for each type of , which affects performance. If you don't want to proxy types differently depending on the type of the target - /// use method. - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - object CreateInterfaceProxyWithTarget(Type interfaceToProxy, object target, ProxyGenerationOptions options, - params IInterceptor[] interceptors); - - /// - /// Creates proxy object intercepting calls to members of interface on object with given . - /// - /// Type of the interface implemented by which will be proxied. - /// The target object, calls to which will be intercepted. - /// Additional interface types. Calls to their members will be proxied as well. - /// The interceptors called during the invocation of proxied methods. - /// - /// Object proxying calls to members of and types on object. - /// - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given array is a null reference (Nothing in Visual Basic). - /// Thrown when given or any of is a generic type definition. - /// Thrown when given is not an interface type. - /// Thrown when given does not implement interface. - /// Thrown when no default constructor exists on actual type of object. - /// Thrown when default constructor of actual type of throws an exception. - /// - /// This method generates new proxy type for each type of , which affects performance. If you don't want to proxy types differently depending on the type of the target - /// use method. - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - object CreateInterfaceProxyWithTarget(Type interfaceToProxy, Type[] additionalInterfacesToProxy, object target, - params IInterceptor[] interceptors); - - /// - /// Creates proxy object intercepting calls to members of interface on object with given . - /// - /// Type of the interface implemented by which will be proxied. - /// The target object, calls to which will be intercepted. - /// The proxy generation options used to influence generated proxy type and object. - /// Additional interface types. Calls to their members will be proxied as well. - /// The interceptors called during the invocation of proxied methods. - /// - /// Object proxying calls to members of and types on object. - /// - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given array is a null reference (Nothing in Visual Basic). - /// Thrown when given or any of is a generic type definition. - /// Thrown when given is not an interface type. - /// Thrown when given does not implement interface. - /// Thrown when no default constructor exists on actual type of object. - /// Thrown when default constructor of actual type of throws an exception. - /// - /// This method generates new proxy type for each type of , which affects performance. If you don't want to proxy types differently depending on the type of the target - /// use method. - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - object CreateInterfaceProxyWithTarget(Type interfaceToProxy, Type[] additionalInterfacesToProxy, - object target, - ProxyGenerationOptions options, - params IInterceptor[] interceptors); - - /// - /// Creates proxy object intercepting calls to members of interface on object with given . - /// Interceptors can use interface to provide other target for method invocation than default . - /// - /// Type of the interface implemented by which will be proxied. - /// The target object, calls to which will be intercepted. - /// The interceptors called during the invocation of proxied methods. - /// - /// Object proxying calls to members of type on object or alternative implementation swapped at runtime by an interceptor. - /// - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given array is a null reference (Nothing in Visual Basic). - /// Thrown when given is a generic type definition. - /// Thrown when given is not an interface type. - /// Thrown when given does not implement interface. - /// Thrown when no default constructor exists on actual type of object. - /// Thrown when default constructor of actual type of throws an exception. - /// - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - object CreateInterfaceProxyWithTargetInterface(Type interfaceToProxy, object target, - params IInterceptor[] interceptors); - - /// - /// Creates proxy object intercepting calls to members of interface on object with given . - /// Interceptors can use interface to provide other target for method invocation than default . - /// - /// Type of the interface implemented by which will be proxied. - /// The target object, calls to which will be intercepted. - /// The interceptors called during the invocation of proxied methods. - /// - /// Object proxying calls to members of type on object or alternative implementation swapped at runtime by an interceptor. - /// - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given array is a null reference (Nothing in Visual Basic). - /// Thrown when given is not an interface type. - /// Thrown when no default constructor exists on actual type of object. - /// Thrown when default constructor of actual type of throws an exception. - /// - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - TInterface CreateInterfaceProxyWithTargetInterface(TInterface target, - params IInterceptor[] interceptors) - where TInterface : class; - - /// - /// Creates proxy object intercepting calls to members of interface on object with given . - /// Interceptors can use interface to provide other target for method invocation than default . - /// - /// Type of the interface implemented by which will be proxied. - /// The target object, calls to which will be intercepted. - /// The proxy generation options used to influence generated proxy type and object. - /// The interceptors called during the invocation of proxied methods. - /// - /// Object proxying calls to members of type on object or alternative implementation swapped at runtime by an interceptor. - /// - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given array is a null reference (Nothing in Visual Basic). - /// Thrown when given is not an interface type. - /// Thrown when no default constructor exists on actual type of object. - /// Thrown when default constructor of actual type of throws an exception. - /// - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - TInterface CreateInterfaceProxyWithTargetInterface(TInterface target, - ProxyGenerationOptions options, - params IInterceptor[] interceptors) - where TInterface : class; - - /// - /// Creates proxy object intercepting calls to members of interface on object with given . - /// Interceptors can use interface to provide other target for method invocation than default . - /// - /// Type of the interface implemented by which will be proxied. - /// The target object, calls to which will be intercepted. - /// Additional interface types. Calls to their members will be proxied as well. - /// The interceptors called during the invocation of proxied methods. - /// - /// Object proxying calls to members of and types on object or alternative implementation swapped at runtime by an interceptor. - /// - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given array is a null reference (Nothing in Visual Basic). - /// Thrown when given or any of is a generic type definition. - /// Thrown when given is not an interface type. - /// Thrown when given does not implement interface. - /// Thrown when no default constructor exists on actual type of object. - /// Thrown when default constructor of actual type of throws an exception. - /// - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - object CreateInterfaceProxyWithTargetInterface(Type interfaceToProxy, Type[] additionalInterfacesToProxy, - object target, params IInterceptor[] interceptors); - - /// - /// Creates proxy object intercepting calls to members of interface on object with given . - /// Interceptors can use interface to provide other target for method invocation than default . - /// - /// Type of the interface implemented by which will be proxied. - /// The target object, calls to which will be intercepted. - /// The proxy generation options used to influence generated proxy type and object. - /// The interceptors called during the invocation of proxied methods. - /// - /// Object proxying calls to members of type on object or alternative implementation swapped at runtime by an interceptor. - /// - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given array is a null reference (Nothing in Visual Basic). - /// Thrown when given is a generic type definition. - /// Thrown when given is not an interface type. - /// Thrown when given does not implement interface. - /// Thrown when no default constructor exists on actual type of object. - /// Thrown when default constructor of actual type of throws an exception. - /// - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - object CreateInterfaceProxyWithTargetInterface(Type interfaceToProxy, object target, - ProxyGenerationOptions options, - params IInterceptor[] interceptors); - - /// - /// Creates proxy object intercepting calls to members of interface on object with given . - /// Interceptors can use interface to provide other target for method invocation than default . - /// - /// Type of the interface implemented by which will be proxied. - /// The target object, calls to which will be intercepted. - /// The proxy generation options used to influence generated proxy type and object. - /// Additional interface types. Calls to their members will be proxied as well. - /// The interceptors called during the invocation of proxied methods. - /// - /// Object proxying calls to members of and types on object or alternative implementation swapped at runtime by an interceptor. - /// - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given array is a null reference (Nothing in Visual Basic). - /// Thrown when given or any of is a generic type definition. - /// Thrown when given is not an interface type. - /// Thrown when given does not implement interface. - /// Thrown when no default constructor exists on actual type of object. - /// Thrown when default constructor of actual type of throws an exception. - /// - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - object CreateInterfaceProxyWithTargetInterface(Type interfaceToProxy, - Type[] additionalInterfacesToProxy, - object target, ProxyGenerationOptions options, - params IInterceptor[] interceptors); - - /// - /// Creates proxy object intercepting calls to members of interface on target object generated at runtime with given . - /// - /// Type of the interface which will be proxied. - /// The interceptors called during the invocation of proxied methods. - /// - /// Object proxying calls to members of types on generated target object. - /// - /// Thrown when given array is a null reference (Nothing in Visual Basic). - /// Thrown when given is not an interface type. - /// - /// Since this method uses an empty-shell implementation of interfaces to proxy generated at runtime, the actual implementation of proxied methods must be provided by given implementations. - /// They are responsible for setting return value (and out parameters) on proxied methods. It is also illegal for an interceptor to call , since there's no actual implementation to proceed with. - /// As a result of that also at least one implementation must be provided. - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - TInterface CreateInterfaceProxyWithoutTarget(IInterceptor interceptor) - where TInterface : class; - - /// - /// Creates proxy object intercepting calls to members of interface on target object generated at runtime with given . - /// - /// Type of the interface which will be proxied. - /// The interceptors called during the invocation of proxied methods. - /// - /// Object proxying calls to members of types on generated target object. - /// - /// Thrown when given array is a null reference (Nothing in Visual Basic). - /// Thrown when given is not an interface type. - /// - /// Since this method uses an empty-shell implementation of interfaces to proxy generated at runtime, the actual implementation of proxied methods must be provided by given implementations. - /// They are responsible for setting return value (and out parameters) on proxied methods. It is also illegal for an interceptor to call , since there's no actual implementation to proceed with. - /// As a result of that also at least one implementation must be provided. - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - TInterface CreateInterfaceProxyWithoutTarget(params IInterceptor[] interceptors) - where TInterface : class; - - /// - /// Creates proxy object intercepting calls to members of interface on target object generated at runtime with given . - /// - /// Type of the interface which will be proxied. - /// The proxy generation options used to influence generated proxy type and object. - /// The interceptors called during the invocation of proxied methods. - /// - /// Object proxying calls to members of types on generated target object. - /// - /// Thrown when given array is a null reference (Nothing in Visual Basic). - /// Thrown when given is not an interface type. - /// - /// Since this method uses an empty-shell implementation of interfaces to proxy generated at runtime, the actual implementation of proxied methods must be provided by given implementations. - /// They are responsible for setting return value (and out parameters) on proxied methods. It is also illegal for an interceptor to call , since there's no actual implementation to proceed with. - /// As a result of that also at least one implementation must be provided. - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - TInterface CreateInterfaceProxyWithoutTarget(ProxyGenerationOptions options, - params IInterceptor[] interceptors) - where TInterface : class; - - /// - /// Creates proxy object intercepting calls to members of interface on target object generated at runtime with given . - /// - /// Type of the interface which will be proxied. - /// The interceptors called during the invocation of proxied methods. - /// - /// Object proxying calls to members of type on generated target object. - /// - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given array is a null reference (Nothing in Visual Basic). - /// Thrown when given is a generic type definition. - /// Thrown when given is not an interface type. - /// - /// Since this method uses an empty-shell implementation of interfaces to proxy generated at runtime, the actual implementation of proxied methods must be provided by given implementations. - /// They are responsible for setting return value (and out parameters) on proxied methods. It is also illegal for an interceptor to call , since there's no actual implementation to proceed with. - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - object CreateInterfaceProxyWithoutTarget(Type interfaceToProxy, IInterceptor interceptor); - - /// - /// Creates proxy object intercepting calls to members of interface on target object generated at runtime with given . - /// - /// Type of the interface which will be proxied. - /// The interceptors called during the invocation of proxied methods. - /// - /// Object proxying calls to members of type on generated target object. - /// - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given array is a null reference (Nothing in Visual Basic). - /// Thrown when given is a generic type definition. - /// Thrown when given is not an interface type. - /// - /// Since this method uses an empty-shell implementation of interfaces to proxy generated at runtime, the actual implementation of proxied methods must be provided by given implementations. - /// They are responsible for setting return value (and out parameters) on proxied methods. It is also illegal for an interceptor to call , since there's no actual implementation to proceed with. - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - object CreateInterfaceProxyWithoutTarget(Type interfaceToProxy, params IInterceptor[] interceptors); - - /// - /// Creates proxy object intercepting calls to members of interface on target object generated at runtime with given . - /// - /// Type of the interface which will be proxied. - /// Additional interface types. Calls to their members will be proxied as well. - /// The interceptors called during the invocation of proxied methods. - /// - /// Object proxying calls to members of and types on generated target object. - /// - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given array is a null reference (Nothing in Visual Basic). - /// Thrown when given or any of is a generic type definition. - /// Thrown when given is not an interface type. - /// - /// Since this method uses an empty-shell implementation of interfaces to proxy generated at runtime, the actual implementation of proxied methods must be provided by given implementations. - /// They are responsible for setting return value (and out parameters) on proxied methods. It is also illegal for an interceptor to call , since there's no actual implementation to proceed with. - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - object CreateInterfaceProxyWithoutTarget(Type interfaceToProxy, Type[] additionalInterfacesToProxy, - params IInterceptor[] interceptors); - - /// - /// Creates proxy object intercepting calls to members of interface on target object generated at runtime with given . - /// - /// Type of the interface which will be proxied. - /// The proxy generation options used to influence generated proxy type and object. - /// The interceptors called during the invocation of proxied methods. - /// - /// Object proxying calls to members of on generated target object. - /// - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given array is a null reference (Nothing in Visual Basic). - /// Thrown when given is a generic type definition. - /// Thrown when given is not an interface type. - /// - /// They are responsible for setting return value (and out parameters) on proxied methods. It is also illegal for an interceptor to call , since there's no actual implementation to proceed with. - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - object CreateInterfaceProxyWithoutTarget(Type interfaceToProxy, ProxyGenerationOptions options, - params IInterceptor[] interceptors); - - /// - /// Creates proxy object intercepting calls to members of interface on target object generated at runtime with given . - /// - /// Type of the interface which will be proxied. - /// The proxy generation options used to influence generated proxy type and object. - /// Additional interface types. Calls to their members will be proxied as well. - /// The interceptors called during the invocation of proxied methods. - /// - /// Object proxying calls to members of and types on generated target object. - /// - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given array is a null reference (Nothing in Visual Basic). - /// Thrown when given or any of is a generic type definition. - /// Thrown when given is not an interface type. - /// - /// Since this method uses an empty-shell implementation of to proxy generated at runtime, the actual implementation of proxied methods must be provided by given implementations. - /// They are responsible for setting return value (and out parameters) on proxied methods. It is also illegal for an interceptor to call , since there's no actual implementation to proceed with. - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - object CreateInterfaceProxyWithoutTarget(Type interfaceToProxy, Type[] additionalInterfacesToProxy, - ProxyGenerationOptions options, - params IInterceptor[] interceptors); - - /// - /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . - /// - /// Type of class which will be proxied. - /// The target object, calls to which will be intercepted. - /// The interceptors called during the invocation of proxied methods. - /// - /// New object of type proxying calls to virtual members of type. - /// - /// Thrown when given is not a class type. - /// Thrown when no default constructor exists on type . - /// Thrown when default constructor of type throws an exception. - /// - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - TClass CreateClassProxyWithTarget(TClass target, params IInterceptor[] interceptors) - where TClass : class; - - /// - /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . - /// - /// Type of class which will be proxied. - /// The target object, calls to which will be intercepted. - /// The proxy generation options used to influence generated proxy type and object. - /// The interceptors called during the invocation of proxied methods. - /// - /// New object of type proxying calls to virtual members of type. - /// - /// Thrown when given is not a class type. - /// Thrown when no default constructor exists on type . - /// Thrown when default constructor of type throws an exception. - /// - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - TClass CreateClassProxyWithTarget(TClass target, ProxyGenerationOptions options, - params IInterceptor[] interceptors) where TClass : class; - - /// - /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . - /// - /// Type of class which will be proxied. - /// Additional interface types. Calls to their members will be proxied as well. - /// The target object, calls to which will be intercepted. - /// The interceptors called during the invocation of proxied methods. - /// - /// New object of type proxying calls to virtual members of and types. - /// - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given or any of is a generic type definition. - /// Thrown when given is not a class type. - /// Thrown when no default constructor exists on type . - /// Thrown when default constructor of type throws an exception. - /// - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - object CreateClassProxyWithTarget(Type classToProxy, Type[] additionalInterfacesToProxy, object target, - params IInterceptor[] interceptors); - - /// - /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . - /// - /// Type of class which will be proxied. - /// The target object, calls to which will be intercepted. - /// The proxy generation options used to influence generated proxy type and object. - /// Arguments of constructor of type which should be used to create a new instance of that type. - /// The interceptors called during the invocation of proxied methods. - /// - /// New object of type proxying calls to virtual members of type. - /// - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given is a generic type definition. - /// Thrown when given is not a class type. - /// Thrown when no constructor exists on type with parameters matching . - /// Thrown when constructor of type throws an exception. - /// - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - object CreateClassProxyWithTarget(Type classToProxy, object target, ProxyGenerationOptions options, - object[] constructorArguments, params IInterceptor[] interceptors); - - /// - /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . - /// - /// Type of class which will be proxied. - /// The target object, calls to which will be intercepted. - /// Arguments of constructor of type which should be used to create a new instance of that type. - /// The interceptors called during the invocation of proxied methods. - /// - /// New object of type proxying calls to virtual members of type. - /// - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given is a generic type definition. - /// Thrown when given is not a class type. - /// Thrown when no constructor exists on type with parameters matching . - /// Thrown when constructor of type throws an exception. - /// - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - object CreateClassProxyWithTarget(Type classToProxy, object target, object[] constructorArguments, - params IInterceptor[] interceptors); - - /// - /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . - /// - /// Type of class which will be proxied. - /// The target object, calls to which will be intercepted. - /// The interceptors called during the invocation of proxied methods. - /// - /// New object of type proxying calls to virtual members of type. - /// - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given is a generic type definition. - /// Thrown when given is not a class type. - /// Thrown when no parameterless constructor exists on type . - /// Thrown when constructor of type throws an exception. - /// - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - object CreateClassProxyWithTarget(Type classToProxy, object target, params IInterceptor[] interceptors); - - /// - /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . - /// - /// Type of class which will be proxied. - /// The target object, calls to which will be intercepted. - /// The proxy generation options used to influence generated proxy type and object. - /// The interceptors called during the invocation of proxied methods. - /// - /// New object of type proxying calls to virtual members of type. - /// - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given is a generic type definition. - /// Thrown when given is not a class type. - /// Thrown when no default constructor exists on type . - /// Thrown when default constructor of type throws an exception. - /// - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - object CreateClassProxyWithTarget(Type classToProxy, object target, ProxyGenerationOptions options, - params IInterceptor[] interceptors); - - /// - /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . - /// - /// Type of class which will be proxied. - /// Additional interface types. Calls to their members will be proxied as well. - /// The target object, calls to which will be intercepted. - /// The proxy generation options used to influence generated proxy type and object. - /// The interceptors called during the invocation of proxied methods. - /// - /// New object of type proxying calls to virtual members of and types. - /// - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given or any of is a generic type definition. - /// Thrown when given is not a class type. - /// Thrown when no default constructor exists on type . - /// Thrown when default constructor of type throws an exception. - /// - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - object CreateClassProxyWithTarget(Type classToProxy, Type[] additionalInterfacesToProxy, object target, - ProxyGenerationOptions options, params IInterceptor[] interceptors); - - /// - /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . - /// - /// Type of class which will be proxied. - /// Additional interface types. Calls to their members will be proxied as well. - /// The target object, calls to which will be intercepted. - /// The proxy generation options used to influence generated proxy type and object. - /// Arguments of constructor of type which should be used to create a new instance of that type. - /// The interceptors called during the invocation of proxied methods. - /// - /// New object of type proxying calls to virtual members of and types. - /// - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given or any of is a generic type definition. - /// Thrown when given is not a class type. - /// Thrown when no constructor exists on type with parameters matching . - /// Thrown when constructor of type throws an exception. - /// - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - object CreateClassProxyWithTarget(Type classToProxy, Type[] additionalInterfacesToProxy, object target, - ProxyGenerationOptions options, object[] constructorArguments, - params IInterceptor[] interceptors); - - /// - /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . - /// - /// Type of class which will be proxied. - /// The interceptors called during the invocation of proxied methods. - /// - /// New object of type proxying calls to virtual members of type. - /// - /// Thrown when given is not a class type. - /// Thrown when no default constructor exists on type . - /// Thrown when default constructor of type throws an exception. - /// - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - TClass CreateClassProxy(params IInterceptor[] interceptors) where TClass : class; - - /// - /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . - /// - /// Type of class which will be proxied. - /// The proxy generation options used to influence generated proxy type and object. - /// The interceptors called during the invocation of proxied methods. - /// - /// New object of type proxying calls to virtual members of type. - /// - /// Thrown when given is not a class type. - /// Thrown when no default constructor exists on type . - /// Thrown when default constructor of type throws an exception. - /// - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - TClass CreateClassProxy(ProxyGenerationOptions options, params IInterceptor[] interceptors) - where TClass : class; - - /// - /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . - /// - /// Type of class which will be proxied. - /// Additional interface types. Calls to their members will be proxied as well. - /// The interceptors called during the invocation of proxied methods. - /// - /// New object of type proxying calls to virtual members of and types. - /// - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given or any of is a generic type definition. - /// Thrown when given is not a class type. - /// Thrown when no default constructor exists on type . - /// Thrown when default constructor of type throws an exception. - /// - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - object CreateClassProxy(Type classToProxy, Type[] additionalInterfacesToProxy, - params IInterceptor[] interceptors); - - /// - /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . - /// - /// Type of class which will be proxied. - /// The proxy generation options used to influence generated proxy type and object. - /// Arguments of constructor of type which should be used to create a new instance of that type. - /// The interceptors called during the invocation of proxied methods. - /// - /// New object of type proxying calls to virtual members of type. - /// - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given is a generic type definition. - /// Thrown when given is not a class type. - /// Thrown when no constructor exists on type with parameters matching . - /// Thrown when constructor of type throws an exception. - /// - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - object CreateClassProxy(Type classToProxy, ProxyGenerationOptions options, object[] constructorArguments, - params IInterceptor[] interceptors); - - /// - /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . - /// - /// Type of class which will be proxied. - /// Arguments of constructor of type which should be used to create a new instance of that type. - /// The interceptors called during the invocation of proxied methods. - /// - /// New object of type proxying calls to virtual members of type. - /// - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given is a generic type definition. - /// Thrown when given is not a class type. - /// Thrown when no constructor exists on type with parameters matching . - /// Thrown when constructor of type throws an exception. - /// - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - object CreateClassProxy(Type classToProxy, object[] constructorArguments, params IInterceptor[] interceptors); - - /// - /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . - /// - /// Type of class which will be proxied. - /// The interceptors called during the invocation of proxied methods. - /// - /// New object of type proxying calls to virtual members of type. - /// - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given is a generic type definition. - /// Thrown when given is not a class type. - /// Thrown when no parameterless constructor exists on type . - /// Thrown when constructor of type throws an exception. - /// - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - object CreateClassProxy(Type classToProxy, params IInterceptor[] interceptors); - - /// - /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . - /// - /// Type of class which will be proxied. - /// The proxy generation options used to influence generated proxy type and object. - /// The interceptors called during the invocation of proxied methods. - /// - /// New object of type proxying calls to virtual members of type. - /// - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given is a generic type definition. - /// Thrown when given is not a class type. - /// Thrown when no default constructor exists on type . - /// Thrown when default constructor of type throws an exception. - /// - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - object CreateClassProxy(Type classToProxy, ProxyGenerationOptions options, params IInterceptor[] interceptors); - - /// - /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . - /// - /// Type of class which will be proxied. - /// Additional interface types. Calls to their members will be proxied as well. - /// The proxy generation options used to influence generated proxy type and object. - /// The interceptors called during the invocation of proxied methods. - /// - /// New object of type proxying calls to virtual members of and types. - /// - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given or any of is a generic type definition. - /// Thrown when given is not a class type. - /// Thrown when no default constructor exists on type . - /// Thrown when default constructor of type throws an exception. - /// - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - object CreateClassProxy(Type classToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options, - params IInterceptor[] interceptors); - - /// - /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . - /// - /// Type of class which will be proxied. - /// Additional interface types. Calls to their members will be proxied as well. - /// The proxy generation options used to influence generated proxy type and object. - /// Arguments of constructor of type which should be used to create a new instance of that type. - /// The interceptors called during the invocation of proxied methods. - /// - /// New object of type proxying calls to virtual members of and types. - /// - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given or any of is a generic type definition. - /// Thrown when given is not a class type. - /// Thrown when no constructor exists on type with parameters matching . - /// Thrown when constructor of type throws an exception. - /// - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - object CreateClassProxy(Type classToProxy, Type[] additionalInterfacesToProxy, - ProxyGenerationOptions options, - object[] constructorArguments, params IInterceptor[] interceptors); - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/IProxyTargetAccessor.cs b/Castle.Core/DynamicProxy/IProxyTargetAccessor.cs deleted file mode 100644 index 172618e..0000000 --- a/Castle.Core/DynamicProxy/IProxyTargetAccessor.cs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy -{ - /// - /// Exposes access to the target object and interceptors of proxy objects. - /// This is a DynamicProxy infrastructure interface and should not be implemented yourself. - /// - public interface IProxyTargetAccessor - { - /// - /// Get the proxy target (note that null is a valid target!) - /// - object DynProxyGetTarget(); - - /// - /// Set the proxy target. - /// - /// New proxy target. - void DynProxySetTarget(object target); - - /// - /// Gets the interceptors for the proxy - /// - IInterceptor[] GetInterceptors(); - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Internal/AttributeUtil.cs b/Castle.Core/DynamicProxy/Internal/AttributeUtil.cs deleted file mode 100644 index e773080..0000000 --- a/Castle.Core/DynamicProxy/Internal/AttributeUtil.cs +++ /dev/null @@ -1,251 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Internal -{ - using System; - using System.Collections.Generic; - using System.Diagnostics; - using System.Linq; - using System.Reflection; - - using Castle.DynamicProxy.Generators; - - internal static class AttributeUtil - { - public static CustomAttributeInfo CreateInfo(CustomAttributeData attribute) - { - Debug.Assert(attribute != null, "attribute != null"); - - // .NET Core does not provide CustomAttributeData.Constructor, so we'll implement it - // by finding a constructor ourselves - Type[] constructorArgTypes; - object[] constructorArgs; - GetArguments(attribute.ConstructorArguments, out constructorArgTypes, out constructorArgs); - var constructor = attribute.AttributeType.GetConstructor(constructorArgTypes); - - PropertyInfo[] properties; - object[] propertyValues; - FieldInfo[] fields; - object[] fieldValues; - GetSettersAndFields( - attribute.AttributeType, - attribute.NamedArguments, out properties, out propertyValues, out fields, out fieldValues); - - return new CustomAttributeInfo(constructor, - constructorArgs, - properties, - propertyValues, - fields, - fieldValues); - } - - private static void GetArguments(IList constructorArguments, - out Type[] constructorArgTypes, out object[] constructorArgs) - { - constructorArgTypes = new Type[constructorArguments.Count]; - constructorArgs = new object[constructorArguments.Count]; - for (var i = 0; i < constructorArguments.Count; i++) - { - constructorArgTypes[i] = constructorArguments[i].ArgumentType; - constructorArgs[i] = ReadAttributeValue(constructorArguments[i]); - } - } - - private static object[] GetArguments(IList constructorArguments) - { - var arguments = new object[constructorArguments.Count]; - for (var i = 0; i < constructorArguments.Count; i++) - { - arguments[i] = ReadAttributeValue(constructorArguments[i]); - } - - return arguments; - } - - private static object ReadAttributeValue(CustomAttributeTypedArgument argument) - { - var value = argument.Value; - if (argument.ArgumentType.IsArray == false) - { - return value; - } - //special case for handling arrays in attributes - var arguments = GetArguments((IList)value); - var array = new object[arguments.Length]; - arguments.CopyTo(array, 0); - return array; - } - - private static void GetSettersAndFields(Type attributeType, IEnumerable namedArguments, - out PropertyInfo[] properties, out object[] propertyValues, - out FieldInfo[] fields, out object[] fieldValues) - { - var propertyList = new List(); - var propertyValuesList = new List(); - var fieldList = new List(); - var fieldValuesList = new List(); - foreach (var argument in namedArguments) - { - if (argument.IsField) - { - fieldList.Add(attributeType.GetField(argument.MemberName)); - fieldValuesList.Add(ReadAttributeValue(argument.TypedValue)); - } - else - { - propertyList.Add(attributeType.GetProperty(argument.MemberName)); - propertyValuesList.Add(ReadAttributeValue(argument.TypedValue)); - } - } - - properties = propertyList.ToArray(); - propertyValues = propertyValuesList.ToArray(); - fields = fieldList.ToArray(); - fieldValues = fieldValuesList.ToArray(); - } - - public static IEnumerable GetNonInheritableAttributes(this MemberInfo member) - { - Debug.Assert(member != null, "member != null"); - var attributes = member.CustomAttributes; - - foreach (var attribute in attributes) - { - var attributeType = attribute.AttributeType; - if (ShouldSkipAttributeReplication(attributeType, ignoreInheritance: false)) - { - continue; - } - - CustomAttributeInfo info; - try - { - info = CreateInfo(attribute); - } - catch (ArgumentException e) - { - var message = - string.Format( - "Due to limitations in CLR, DynamicProxy was unable to successfully replicate non-inheritable attribute {0} on {1}{2}. " + - "To avoid this error you can chose not to replicate this attribute type by calling '{3}.Add(typeof({0}))'.", - attributeType.FullName, - member.DeclaringType.FullName, - (member is TypeInfo) ? "" : ("." + member.Name), - typeof(AttributesToAvoidReplicating).FullName); - throw new NotSupportedException(message, e); - } - if (info != null) - { - yield return info; - } - } - } - - public static IEnumerable GetNonInheritableAttributes(this ParameterInfo parameter) - { - Debug.Assert(parameter != null, "parameter != null"); - - var attributes = parameter.CustomAttributes; - - var ignoreInheritance = parameter.Member is ConstructorInfo; - - foreach (var attribute in attributes) - { - var attributeType = attribute.AttributeType; - - if (ShouldSkipAttributeReplication(attributeType, ignoreInheritance)) - { - continue; - } - - var info = CreateInfo(attribute); - if (info != null) - { - yield return info; - } - } - } - - /// - /// Attributes should be replicated if they are non-inheritable, - /// but there are some special cases where the attributes means - /// something to the CLR, where they should be skipped. - /// - private static bool ShouldSkipAttributeReplication(Type attribute, bool ignoreInheritance) - { - if (attribute.IsPublic == false) - { - return true; - } - - if (AttributesToAvoidReplicating.ShouldAvoid(attribute)) - { - return true; - } - - // Later, there might be more special cases requiring attribute replication, - // which might justify creating a `SpecialCaseAttributeThatShouldBeReplicated` - // method and an `AttributesToAlwaysReplicate` class. For the moment, `Param- - // ArrayAttribute` is the only special case, so keep it simple for now: - if (attribute == typeof(ParamArrayAttribute)) - { - return false; - } - - if (!ignoreInheritance) - { - var attrs = attribute.GetCustomAttributes(true).ToArray(); - if (attrs.Length != 0) - { - return attrs[0].Inherited; - } - - return true; - } - - return false; - } - - public static CustomAttributeInfo CreateInfo() where TAttribute : Attribute, new() - { - var constructor = typeof(TAttribute).GetConstructor(Type.EmptyTypes); - Debug.Assert(constructor != null, "constructor != null"); - - return new CustomAttributeInfo(constructor, new object[0]); - } - - public static CustomAttributeInfo CreateInfo(Type attribute, object[] constructorArguments) - { - Debug.Assert(attribute != null, "attribute != null"); - Debug.Assert(typeof(Attribute).IsAssignableFrom(attribute), "typeof(Attribute).IsAssignableFrom(attribute)"); - Debug.Assert(constructorArguments != null, "constructorArguments != null"); - - var constructor = attribute.GetConstructor(GetTypes(constructorArguments)); - Debug.Assert(constructor != null, "constructor != null"); - - return new CustomAttributeInfo(constructor, constructorArguments); - } - - private static Type[] GetTypes(object[] objects) - { - var types = new Type[objects.Length]; - for (var i = 0; i < types.Length; i++) - { - types[i] = objects[i].GetType(); - } - return types; - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Internal/CompositionInvocation.cs b/Castle.Core/DynamicProxy/Internal/CompositionInvocation.cs deleted file mode 100644 index 0d03e56..0000000 --- a/Castle.Core/DynamicProxy/Internal/CompositionInvocation.cs +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Internal -{ - using System; - using System.Reflection; - - public abstract class CompositionInvocation : AbstractInvocation - { - protected object target; - - protected CompositionInvocation( - object target, - object proxy, - IInterceptor[] interceptors, - MethodInfo proxiedMethod, - object[] arguments) - : base(proxy, interceptors, proxiedMethod, arguments) - { - this.target = target; - } - - public override object InvocationTarget - { - get { return target; } - } - - public override MethodInfo MethodInvocationTarget - { - get { return InvocationHelper.GetMethodOnObject(target, Method); } - } - - public override Type TargetType - { - get { return TypeUtil.GetTypeOrNull(target); } - } - - protected void EnsureValidProxyTarget(object newTarget) - { - if (newTarget == null) - { - throw new ArgumentNullException(nameof(newTarget)); - } - - if (!ReferenceEquals(newTarget, proxyObject)) - { - return; - } - - var message = "This is a DynamicProxy2 error: target of proxy has been set to the proxy itself. " + - "This would result in recursively calling proxy methods over and over again until stack overflow, which may destabilize your program." + - "This usually signifies a bug in the calling code. Make sure no interceptor sets proxy as its own target."; - throw new InvalidOperationException(message); - } - - protected void EnsureValidTarget() - { - if (target == null) - { - ThrowOnNoTarget(); - } - - if (!ReferenceEquals(target, proxyObject)) - { - return; - } - - var message = "This is a DynamicProxy2 error: target of invocation has been set to the proxy itself. " + - "This may result in recursively calling the method over and over again until stack overflow, which may destabilize your program." + - "This usually signifies a bug in the calling code. Make sure no interceptor sets proxy as its invocation target."; - throw new InvalidOperationException(message); - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Internal/InheritanceInvocation.cs b/Castle.Core/DynamicProxy/Internal/InheritanceInvocation.cs deleted file mode 100644 index a3a6d7f..0000000 --- a/Castle.Core/DynamicProxy/Internal/InheritanceInvocation.cs +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Internal -{ - using System; - using System.Reflection; - - public abstract class InheritanceInvocation : AbstractInvocation - { - private readonly Type targetType; - - protected InheritanceInvocation( - Type targetType, - object proxy, - IInterceptor[] interceptors, - MethodInfo proxiedMethod, - object[] arguments) - : base(proxy, interceptors, proxiedMethod, arguments) - { - this.targetType = targetType; - } - - public override object InvocationTarget - { - get { return Proxy; } - } - - public override MethodInfo MethodInvocationTarget - { - get { return InvocationHelper.GetMethodOnType(targetType, Method); } - } - - public override Type TargetType - { - get { return targetType; } - } - - protected abstract override void InvokeMethodOnTarget(); - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Internal/InterfaceMethodWithoutTargetInvocation.cs b/Castle.Core/DynamicProxy/Internal/InterfaceMethodWithoutTargetInvocation.cs deleted file mode 100644 index a1c92a2..0000000 --- a/Castle.Core/DynamicProxy/Internal/InterfaceMethodWithoutTargetInvocation.cs +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Internal -{ - using System; - using System.ComponentModel; - using System.Diagnostics; - using System.Reflection; - -#if FEATURE_SERIALIZATION - [Serializable] -#endif - [EditorBrowsable(EditorBrowsableState.Never)] - public sealed class InterfaceMethodWithoutTargetInvocation : AbstractInvocation - { - public InterfaceMethodWithoutTargetInvocation(object target, object proxy, IInterceptor[] interceptors, MethodInfo proxiedMethod, object[] arguments) - : base(proxy, interceptors, proxiedMethod, arguments) - { - // This invocation type is suitable for interface method invocations that cannot proceed - // to a target, i.e. where `InvokeMethodOnTarget` will always throw: - - Debug.Assert(target == null, $"{nameof(InterfaceMethodWithoutTargetInvocation)} does not support targets."); - Debug.Assert(proxiedMethod.IsAbstract, $"{nameof(InterfaceMethodWithoutTargetInvocation)} does not support non-abstract methods."); - - // Why this restriction? Because it greatly benefits proxy type generation performance. - // - // For invocations that can proceed to a target, `InvokeMethodOnTarget`'s implementation - // depends on the target method's signature. Because of this, DynamicProxy needs to - // dynamically generate a separate invocation type per such method. Type generation is - // always expensive... that is, slow. - // - // However, if it is known that `InvokeMethodOnTarget` won't forward, but throw, - // no custom (dynamically generated) invocation type is needed at all, and we can use - // this unspecific invocation type instead. - } - - // The next three properties mimick the behavior seen with an interface proxy without target. - // (This is why this type's name starts with `Interface`.) A similar type could be written - // for class proxies without target, but the values returned here would be different. - - public override object InvocationTarget => null; - - public override MethodInfo MethodInvocationTarget => null; - - public override Type TargetType => null; - - protected override void InvokeMethodOnTarget() => ThrowOnNoTarget(); - } -} diff --git a/Castle.Core/DynamicProxy/Internal/InvocationHelper.cs b/Castle.Core/DynamicProxy/Internal/InvocationHelper.cs deleted file mode 100644 index 41ddbfa..0000000 --- a/Castle.Core/DynamicProxy/Internal/InvocationHelper.cs +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Internal -{ - using System; - using System.Collections.Generic; - using System.Diagnostics; - using System.Reflection; - using System.Threading; - - using Castle.Core.Internal; - using Castle.DynamicProxy.Generators; - - internal static class InvocationHelper - { - private static readonly SynchronizedDictionary cache = - new SynchronizedDictionary(); - - public static MethodInfo GetMethodOnObject(object target, MethodInfo proxiedMethod) - { - if (target == null) - { - return null; - } - - return GetMethodOnType(target.GetType(), proxiedMethod); - } - - public static MethodInfo GetMethodOnType(Type type, MethodInfo proxiedMethod) - { - if (type == null) - { - throw new ArgumentNullException(nameof(type)); - } - - Debug.Assert(proxiedMethod.DeclaringType.IsAssignableFrom(type), - "proxiedMethod.DeclaringType.IsAssignableFrom(type)"); - - var cacheKey = new CacheKey(proxiedMethod, type); - - return cache.GetOrAdd(cacheKey, ck => ObtainMethod(proxiedMethod, type)); - } - - private static MethodInfo ObtainMethod(MethodInfo proxiedMethod, Type type) - { - Type[] genericArguments = null; - if (proxiedMethod.IsGenericMethod) - { - genericArguments = proxiedMethod.GetGenericArguments(); - proxiedMethod = proxiedMethod.GetGenericMethodDefinition(); - } - var declaringType = proxiedMethod.DeclaringType; - MethodInfo methodOnTarget = null; - if (declaringType.IsInterface) - { - var mapping = type.GetInterfaceMap(declaringType); - var index = Array.IndexOf(mapping.InterfaceMethods, proxiedMethod); - Debug.Assert(index != -1); - methodOnTarget = mapping.TargetMethods[index]; - } - else - { - // NOTE: this implementation sucks, feel free to improve it. - var methods = MethodFinder.GetAllInstanceMethods(type, BindingFlags.Public | BindingFlags.NonPublic); - foreach (var method in methods) - { - if (MethodSignatureComparer.Instance.Equals(method.GetBaseDefinition(), proxiedMethod)) - { - methodOnTarget = method; - break; - } - } - } - if (methodOnTarget == null) - { - throw new ArgumentException( - string.Format("Could not find method overriding {0} on type {1}. This is most likely a bug. Please report it.", - proxiedMethod, type)); - } - - if (genericArguments == null) - { - return methodOnTarget; - } - return methodOnTarget.MakeGenericMethod(genericArguments); - } - - private struct CacheKey : IEquatable - { - public CacheKey(MethodInfo method, Type type) - { - Method = method; - Type = type; - } - public MethodInfo Method { get; } - - public Type Type { get; } - - public bool Equals(CacheKey other) - { - return object.ReferenceEquals(Method, other.Method) && object.ReferenceEquals(Type, other.Type); - } - - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) - return false; - return obj is CacheKey @struct && Equals(@struct); - } - - public override int GetHashCode() - { - unchecked - { - return ((Method != null ? Method.GetHashCode() : 0) * 397) ^ (Type != null ? Type.GetHashCode() : 0); - } - } - } - } -} diff --git a/Castle.Core/DynamicProxy/Internal/TypeUtil.cs b/Castle.Core/DynamicProxy/Internal/TypeUtil.cs deleted file mode 100644 index 63a1f2d..0000000 --- a/Castle.Core/DynamicProxy/Internal/TypeUtil.cs +++ /dev/null @@ -1,225 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Internal -{ - using System; - using System.Collections.Generic; - using System.Diagnostics; - using System.Reflection; - using System.Reflection.Emit; - - using Castle.DynamicProxy.Generators.Emitters; - - public static class TypeUtil - { - internal static bool IsNullableType(this Type type) - { - return type.IsGenericType && - type.GetGenericTypeDefinition() == typeof(Nullable<>); - } - - internal static FieldInfo[] GetAllFields(this Type type) - { - if (type == null) - { - throw new ArgumentNullException(nameof(type)); - } - - if (type.IsClass == false) - { - throw new ArgumentException(string.Format("Type {0} is not a class type. This method supports only classes", type)); - } - - var fields = new List(); - var currentType = type; - while (currentType != typeof(object)) - { - Debug.Assert(currentType != null); - var currentFields = currentType.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static); - fields.AddRange(currentFields); - currentType = currentType.BaseType; - } - - return fields.ToArray(); - } - - /// - /// Returns list of all unique interfaces implemented given types, including their base interfaces. - /// - internal static Type[] GetAllInterfaces(params Type[] types) - { - if (types == null) - { - return Type.EmptyTypes; - } - - var interfaces = new HashSet(); - for (var index = 0; index < types.Length; index++) - { - var type = types[index]; - if (type == null) - { - continue; - } - - if (type.IsInterface) - { - if (interfaces.Add(type) == false) - { - continue; - } - } - - var innerInterfaces = type.GetInterfaces(); - for (var i = 0; i < innerInterfaces.Length; i++) - { - var @interface = innerInterfaces[i]; - interfaces.Add(@interface); - } - } - - return Sort(interfaces); - } - - public static Type[] GetAllInterfaces(this Type type) // NOTE: also used by Windsor - { - return GetAllInterfaces(new[] { type }); - } - - - public static Type GetTypeOrNull(object target) - { - if (target == null) - { - return null; - } - return target.GetType(); - } - - internal static Type[] AsTypeArray(this GenericTypeParameterBuilder[] typeInfos) - { - Type[] types = new Type[typeInfos.Length]; - for (int i = 0; i < types.Length; i++) - { - types[i] = typeInfos[i]; - } - return types; - } - - internal static bool IsFinalizer(this MethodInfo methodInfo) - { - return string.Equals("Finalize", methodInfo.Name) && methodInfo.GetBaseDefinition().DeclaringType == typeof(object); - } - - internal static bool IsGetType(this MethodInfo methodInfo) - { - return methodInfo.DeclaringType == typeof(object) && string.Equals("GetType", methodInfo.Name, StringComparison.OrdinalIgnoreCase); - } - - internal static bool IsMemberwiseClone(this MethodInfo methodInfo) - { - return methodInfo.DeclaringType == typeof(object) && string.Equals("MemberwiseClone", methodInfo.Name, StringComparison.OrdinalIgnoreCase); - } - - internal static void SetStaticField(this Type type, string fieldName, BindingFlags additionalFlags, object value) - { - var flags = additionalFlags | BindingFlags.Static; - - FieldInfo field = type.GetField(fieldName, flags); - if (field == null) - { - throw new DynamicProxyException(string.Format( - "Could not find field named '{0}' on type {1}. This is likely a bug in DynamicProxy. Please report it.", - fieldName, type)); - } - - try - { - field.SetValue(null, value); - } - catch (MissingFieldException e) - { - throw new DynamicProxyException( - string.Format( - "Could not find field named '{0}' on type {1}. This is likely a bug in DynamicProxy. Please report it.", - fieldName, - type), e); - } - catch (TargetException e) - { - throw new DynamicProxyException( - string.Format( - "There was an error trying to set field named '{0}' on type {1}. This is likely a bug in DynamicProxy. Please report it.", - fieldName, - type), e); - } - catch (TargetInvocationException e) // yes, this is not documented in MSDN. Yay for documentation - { - if ((e.InnerException is TypeInitializationException) == false) - { - throw; - } - throw new DynamicProxyException( - string.Format( - "There was an error in static constructor on type {0}. This is likely a bug in DynamicProxy. Please report it.", - type), e); - } - } - - public static MemberInfo[] Sort(MemberInfo[] members) - { - var sortedMembers = new MemberInfo[members.Length]; - Array.Copy(members, sortedMembers, members.Length); - Array.Sort(sortedMembers, (l, r) => string.Compare(l.Name, r.Name, StringComparison.OrdinalIgnoreCase)); - return sortedMembers; - } - - /// - /// Checks whether the specified is a delegate type (i.e. a direct subclass of ). - /// - internal static bool IsDelegateType(this Type type) - { - return type.BaseType == typeof(MulticastDelegate); - } - - private static Type[] Sort(ICollection types) - { - var array = new Type[types.Count]; - types.CopyTo(array, 0); - //NOTE: is there a better, stable way to sort Types. We will need to revise this once we allow open generics - Array.Sort(array, TypeNameComparer.Instance); - // ^^^^^^^^^^^^^^^^^^^^^^^^^ - // Using a `IComparer` object instead of a `Comparison` delegate prevents - // an unnecessary level of indirection inside the framework (as the latter get - // wrapped as `IComparer` objects). - return array; - } - - private sealed class TypeNameComparer : IComparer - { - public static readonly TypeNameComparer Instance = new TypeNameComparer(); - - public int Compare(Type x, Type y) - { - // Comparing by `type.AssemblyQualifiedName` would give the same result, - // but it performs a hidden concatenation (and therefore string allocation) - // of `type.FullName` and `type.Assembly.FullName`. We can avoid this - // overhead by comparing the two properties separately. - int result = string.CompareOrdinal(x.FullName, y.FullName); - return result != 0 ? result : string.CompareOrdinal(x.Assembly.FullName, y.Assembly.FullName); - } - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/MixinData.cs b/Castle.Core/DynamicProxy/MixinData.cs deleted file mode 100644 index 2d26f51..0000000 --- a/Castle.Core/DynamicProxy/MixinData.cs +++ /dev/null @@ -1,210 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy -{ - using System; - using System.Collections.Generic; - using System.Diagnostics; - using System.Linq; - using System.Reflection; - - using Castle.DynamicProxy.Generators; - using Castle.DynamicProxy.Internal; - - public class MixinData - { - private readonly Dictionary mixinPositions = new Dictionary(); - private readonly List mixinsImpl = new List(); - private int delegateMixinCount = 0; - - /// - /// Because we need to cache the types based on the mixed in mixins, we do the following here: - /// - Get all the mixin interfaces - /// - Sort them by full name - /// - Return them by position - /// - /// The idea is to have reproducible behavior for the case that mixins are registered in different orders. - /// This method is here because it is required - /// - public MixinData(IEnumerable mixinInstances) - { - if (mixinInstances != null) - { - var sortedMixedInterfaceTypes = new List(); - var interface2Mixin = new Dictionary(); - delegateMixinCount = 0; - - foreach (var mixin in mixinInstances) - { - Type[] mixinInterfaces; - object target; - if (mixin is Delegate) - { - ++delegateMixinCount; - mixinInterfaces = new[] { mixin.GetType() }; - target = mixin; - } - else if (mixin is Type delegateType && delegateType.IsDelegateType()) - { - ++delegateMixinCount; - mixinInterfaces = new[] { delegateType }; - target = null; - } - else - { - mixinInterfaces = mixin.GetType().GetInterfaces(); - target = mixin; - } - - foreach (var inter in mixinInterfaces) - { - sortedMixedInterfaceTypes.Add(inter); - - if (interface2Mixin.TryGetValue(inter, out var interMixin)) - { - string message; - if (interMixin != null) - { - message = string.Format( - "The list of mixins contains two mixins implementing the same interface '{0}': {1} and {2}. An interface cannot be added by more than one mixin.", - inter.FullName, - interMixin.GetType().Name, - mixin.GetType().Name); - } - else - { - Debug.Assert(inter.IsDelegateType()); - message = string.Format( - "The list of mixins already contains a mixin for delegate type '{0}'.", - inter.FullName); - } - throw new ArgumentException(message, nameof(mixinInstances)); - } - interface2Mixin[inter] = target; - } - } - - if (delegateMixinCount > 1) - { - // If at least two delegate mixins have been added, we need to ensure that - // the `Invoke` methods contributed by them don't have identical signatures: - var invokeMethods = new HashSet(); - foreach (var mixedInType in interface2Mixin.Keys) - { - if (mixedInType.IsDelegateType()) - { - var invokeMethod = mixedInType.GetMethod("Invoke"); - if (invokeMethods.Contains(invokeMethod, MethodSignatureComparer.Instance)) - { - throw new ArgumentException("The list of mixins contains at least two delegate mixins for the same delegate signature.", nameof(mixinInstances)); - } - invokeMethods.Add(invokeMethod); - } - } - } - - sortedMixedInterfaceTypes.Sort((x, y) => string.CompareOrdinal(x.FullName, y.FullName)); - - for (var i = 0; i < sortedMixedInterfaceTypes.Count; i++) - { - var mixinInterface = sortedMixedInterfaceTypes[i]; - var mixin = interface2Mixin[mixinInterface]; - - mixinPositions[mixinInterface] = i; - mixinsImpl.Add(mixin); - } - } - } - - public IEnumerable MixinInterfaces - { - get { return mixinPositions.Keys; } - } - - public IEnumerable Mixins - { - get { return mixinsImpl; } - } - - public bool ContainsMixin(Type mixinInterfaceType) - { - return mixinPositions.ContainsKey(mixinInterfaceType); - } - - // For two MixinData objects being regarded equal, only the sorted mixin types are considered, not the actual instances. - public override bool Equals(object obj) - { - if (ReferenceEquals(this, obj)) - { - return true; - } - - var other = obj as MixinData; - if (ReferenceEquals(other, null)) - { - return false; - } - - if (mixinsImpl.Count != other.mixinsImpl.Count) - { - return false; - } - - if (delegateMixinCount != other.delegateMixinCount) - { - return false; - } - - for (var i = 0; i < mixinsImpl.Count; ++i) - { - if (mixinsImpl[i]?.GetType() != other.mixinsImpl[i]?.GetType()) - { - return false; - } - } - - if (delegateMixinCount > 0) - { - var delegateMixinTypes = mixinPositions.Select(m => m.Key).Where(TypeUtil.IsDelegateType); - var otherDelegateMixinTypes = other.mixinPositions.Select(m => m.Key).Where(TypeUtil.IsDelegateType); - return Enumerable.SequenceEqual(delegateMixinTypes, otherDelegateMixinTypes); - } - - return true; - } - - // For two MixinData objects being regarded equal, only the mixin types are considered, not the actual instances. - public override int GetHashCode() - { - var hashCode = 0; - foreach (var mixinImplementation in mixinsImpl) - { - hashCode = unchecked(29 * hashCode + mixinImplementation?.GetType().GetHashCode() ?? 307); - } - - return hashCode; - } - - public object GetMixinInstance(Type mixinInterfaceType) - { - return mixinsImpl[mixinPositions[mixinInterfaceType]]; - } - - public int GetMixinPosition(Type mixinInterfaceType) - { - return mixinPositions[mixinInterfaceType]; - } - } -} diff --git a/Castle.Core/DynamicProxy/ModuleScope.cs b/Castle.Core/DynamicProxy/ModuleScope.cs deleted file mode 100644 index b70b109..0000000 --- a/Castle.Core/DynamicProxy/ModuleScope.cs +++ /dev/null @@ -1,539 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy -{ - using System; - using System.Collections.Generic; - using System.Diagnostics; - using System.IO; - using System.Reflection; - using System.Reflection.Emit; - using System.Resources; - using System.Threading; - - using Castle.Core.Internal; - using Castle.DynamicProxy.Generators; -#if FEATURE_SERIALIZATION - using Castle.DynamicProxy.Serialization; -#endif - - public class ModuleScope - { - /// - /// The default file name used when the assembly is saved using . - /// - public static readonly string DEFAULT_FILE_NAME = "CastleDynProxy2.dll"; - - /// - /// The default assembly (simple) name used for the assemblies generated by a instance. - /// - public static readonly string DEFAULT_ASSEMBLY_NAME = "DynamicProxyGenAssembly2"; - - private ModuleBuilder moduleBuilderWithStrongName; - private ModuleBuilder moduleBuilder; - - // The names to use for the generated assemblies and the paths (including the names) of their manifest modules - private readonly string strongAssemblyName; - private readonly string weakAssemblyName; - private readonly string strongModulePath; - private readonly string weakModulePath; - - // Keeps track of generated types - private readonly SynchronizedDictionary typeCache = new SynchronizedDictionary(); - - // Used to lock the module builder creation - private readonly object moduleLocker = new object(); - - // Specified whether the generated assemblies are intended to be saved - private readonly bool savePhysicalAssembly; - private readonly bool disableSignedModule; - private readonly INamingScope namingScope; - - /// - /// Initializes a new instance of the class; assemblies created by this instance will not be saved. - /// - public ModuleScope() : this(false, false) - { - } - - /// - /// Initializes a new instance of the class, allowing to specify whether the assemblies generated by this instance - /// should be saved. - /// - /// If set to true saves the generated module. - public ModuleScope(bool savePhysicalAssembly) - : this(savePhysicalAssembly, false) - { - } - - /// - /// Initializes a new instance of the class, allowing to specify whether the assemblies generated by this instance - /// should be saved. - /// - /// If set to true saves the generated module. - /// If set to true disables ability to generate signed module. This should be used in cases where ran under constrained permissions. - public ModuleScope(bool savePhysicalAssembly, bool disableSignedModule) - : this( - savePhysicalAssembly, disableSignedModule, DEFAULT_ASSEMBLY_NAME, DEFAULT_FILE_NAME, DEFAULT_ASSEMBLY_NAME, - DEFAULT_FILE_NAME) - { - } - - /// - /// Initializes a new instance of the class, allowing to specify whether the assemblies generated by this instance - /// should be saved and what simple names are to be assigned to them. - /// - /// If set to true saves the generated module. - /// If set to true disables ability to generate signed module. This should be used in cases where ran under constrained permissions. - /// The simple name of the strong-named assembly generated by this . - /// The path and file name of the manifest module of the strong-named assembly generated by this . - /// The simple name of the weak-named assembly generated by this . - /// The path and file name of the manifest module of the weak-named assembly generated by this . - public ModuleScope(bool savePhysicalAssembly, bool disableSignedModule, string strongAssemblyName, - string strongModulePath, - string weakAssemblyName, string weakModulePath) - : this( - savePhysicalAssembly, disableSignedModule, new NamingScope(), strongAssemblyName, strongModulePath, weakAssemblyName, - weakModulePath) - { - } - - /// - /// Initializes a new instance of the class, allowing to specify whether the assemblies generated by this instance - /// should be saved and what simple names are to be assigned to them. - /// - /// If set to true saves the generated module. - /// If set to true disables ability to generate signed module. This should be used in cases where ran under constrained permissions. - /// Naming scope used to provide unique names to generated types and their members (usually via sub-scopes). - /// The simple name of the strong-named assembly generated by this . - /// The path and file name of the manifest module of the strong-named assembly generated by this . - /// The simple name of the weak-named assembly generated by this . - /// The path and file name of the manifest module of the weak-named assembly generated by this . - internal ModuleScope(bool savePhysicalAssembly, bool disableSignedModule, INamingScope namingScope, - string strongAssemblyName, string strongModulePath, - string weakAssemblyName, string weakModulePath) - { - this.savePhysicalAssembly = savePhysicalAssembly; - this.disableSignedModule = disableSignedModule; - this.namingScope = namingScope; - this.strongAssemblyName = strongAssemblyName; - this.strongModulePath = strongModulePath; - this.weakAssemblyName = weakAssemblyName; - this.weakModulePath = weakModulePath; - } - - internal INamingScope NamingScope - { - get { return namingScope; } - } - - internal SynchronizedDictionary TypeCache => typeCache; - - /// - /// Gets the key pair used to sign the strong-named assembly generated by this . - /// - public static byte[] GetKeyPair() - { - using (var stream = typeof(ModuleScope).Assembly.GetManifestResourceStream("Castle.DynamicProxy.DynProxy.snk")) - { - if (stream == null) - { - throw new MissingManifestResourceException( - "Should have a Castle.DynamicProxy.DynProxy.snk as an embedded resource, so Dynamic Proxy could sign generated assembly"); - } - - var length = (int)stream.Length; - var keyPair = new byte[length]; - stream.Read(keyPair, 0, length); - return keyPair; - } - } - - /// - /// Gets the strong-named module generated by this scope, or if none has yet been generated. - /// - /// The strong-named module generated by this scope, or if none has yet been generated. - internal ModuleBuilder StrongNamedModule - { - get { return moduleBuilderWithStrongName; } - } - - /// - /// Gets the file name of the strongly named module generated by this scope. - /// - /// The file name of the strongly named module generated by this scope. - public string StrongNamedModuleName - { - get { return Path.GetFileName(strongModulePath); } - } - -#if FEATURE_ASSEMBLYBUILDER_SAVE - /// - /// Gets the directory where the strongly named module generated by this scope will be saved, or if the current directory - /// is used. - /// - /// The directory where the strongly named module generated by this scope will be saved when is called - /// (if this scope was created to save modules). - public string StrongNamedModuleDirectory - { - get - { - var directory = Path.GetDirectoryName(strongModulePath); - if (string.IsNullOrEmpty(directory)) - { - return null; - } - return directory; - } - } -#endif - - /// - /// Gets the weak-named module generated by this scope, or if none has yet been generated. - /// - /// The weak-named module generated by this scope, or if none has yet been generated. - internal ModuleBuilder WeakNamedModule - { - get { return moduleBuilder; } - } - - /// - /// Gets the file name of the weakly named module generated by this scope. - /// - /// The file name of the weakly named module generated by this scope. - public string WeakNamedModuleName - { - get { return Path.GetFileName(weakModulePath); } - } - -#if FEATURE_ASSEMBLYBUILDER_SAVE - /// - /// Gets the directory where the weakly named module generated by this scope will be saved, or if the current directory - /// is used. - /// - /// The directory where the weakly named module generated by this scope will be saved when is called - /// (if this scope was created to save modules). - public string WeakNamedModuleDirectory - { - get - { - var directory = Path.GetDirectoryName(weakModulePath); - if (directory == string.Empty) - { - return null; - } - return directory; - } - } -#endif - - /// - /// Gets the specified module generated by this scope, creating a new one if none has yet been generated. - /// - /// If set to true, a strong-named module is returned; otherwise, a weak-named module is returned. - /// A strong-named or weak-named module generated by this scope, as specified by the parameter. - internal ModuleBuilder ObtainDynamicModule(bool isStrongNamed) - { - if (isStrongNamed) - { - return ObtainDynamicModuleWithStrongName(); - } - - return ObtainDynamicModuleWithWeakName(); - } - - /// - /// Gets the strong-named module generated by this scope, creating a new one if none has yet been generated. - /// - /// A strong-named module generated by this scope. - internal ModuleBuilder ObtainDynamicModuleWithStrongName() - { - if (disableSignedModule) - { - throw new InvalidOperationException( - "Usage of signed module has been disabled. Use unsigned module or enable signed module."); - } - lock (moduleLocker) - { - if (moduleBuilderWithStrongName == null) - { - moduleBuilderWithStrongName = CreateModule(true); - } - return moduleBuilderWithStrongName; - } - } - - /// - /// Gets the weak-named module generated by this scope, creating a new one if none has yet been generated. - /// - /// A weak-named module generated by this scope. - internal ModuleBuilder ObtainDynamicModuleWithWeakName() - { - lock (moduleLocker) - { - if (moduleBuilder == null) - { - moduleBuilder = CreateModule(false); - } - return moduleBuilder; - } - } - - private ModuleBuilder CreateModule(bool signStrongName) - { - var assemblyName = GetAssemblyName(signStrongName); - var moduleName = signStrongName ? StrongNamedModuleName : WeakNamedModuleName; -#if FEATURE_APPDOMAIN - if (savePhysicalAssembly) - { - AssemblyBuilder assemblyBuilder; - try - { - assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly( - assemblyName, AssemblyBuilderAccess.RunAndSave, signStrongName ? StrongNamedModuleDirectory : WeakNamedModuleDirectory); - } - catch (ArgumentException e) - { - if (signStrongName == false && e.StackTrace.Contains("ComputePublicKey") == false) - { - // I have no idea what that could be - throw; - } - var message = string.Format( - "There was an error creating dynamic assembly for your proxies - you don't have permissions " + - "required to sign the assembly. To workaround it you can enforce generating non-signed assembly " + - "only when creating {0}. Alternatively ensure that your account has all the required permissions.", - GetType()); - throw new ArgumentException(message, e); - } - var module = assemblyBuilder.DefineDynamicModule(moduleName, moduleName, false); - return module; - } - else -#endif - { -#if FEATURE_APPDOMAIN - var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly( - assemblyName, AssemblyBuilderAccess.Run); -#else - var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); -#endif - - var module = assemblyBuilder.DefineDynamicModule(moduleName); - return module; - } - } - - private AssemblyName GetAssemblyName(bool signStrongName) - { - var assemblyName = new AssemblyName { - Name = signStrongName ? strongAssemblyName : weakAssemblyName - }; - - if (signStrongName) - { -#if FEATURE_ASSEMBLYBUILDER_SAVE - assemblyName.KeyPair = new StrongNameKeyPair(GetKeyPair()); -#else - assemblyName.SetPublicKey(InternalsVisible.DynamicProxyGenAssembly2PublicKey); -#endif - } - - return assemblyName; - } - -#if FEATURE_ASSEMBLYBUILDER_SAVE - /// - /// Saves the generated assembly with the name and directory information given when this instance was created (or with - /// the and current directory if none was given). - /// - /// - /// - /// This method stores the generated assembly in the directory passed as part of the module information specified when this instance was - /// constructed (if any, else the current directory is used). If both a strong-named and a weak-named assembly - /// have been generated, it will throw an exception; in this case, use the overload. - /// - /// - /// If this was created without indicating that the assembly should be saved, this method does nothing. - /// - /// - /// Both a strong-named and a weak-named assembly have been generated. - /// The path of the generated assembly file, or null if no file has been generated. - public string SaveAssembly() - { - if (!savePhysicalAssembly) - { - return null; - } - - if (StrongNamedModule != null && WeakNamedModule != null) - { - throw new InvalidOperationException("Both a strong-named and a weak-named assembly have been generated."); - } - - if (StrongNamedModule != null) - { - return SaveAssembly(true); - } - - if (WeakNamedModule != null) - { - return SaveAssembly(false); - } - - return null; - } - - /// - /// Saves the specified generated assembly with the name and directory information given when this instance was created - /// (or with the and current directory if none was given). - /// - /// True if the generated assembly with a strong name should be saved (see ); - /// false if the generated assembly without a strong name should be saved (see . - /// - /// - /// This method stores the specified generated assembly in the directory passed as part of the module information specified when this instance was - /// constructed (if any, else the current directory is used). - /// - /// - /// If this was created without indicating that the assembly should be saved, this method does nothing. - /// - /// - /// No assembly has been generated that matches the parameter. - /// - /// The path of the generated assembly file, or null if no file has been generated. - public string SaveAssembly(bool strongNamed) - { - if (!savePhysicalAssembly) - { - return null; - } - - AssemblyBuilder assemblyBuilder; - string assemblyFileName; - string assemblyFilePath; - - if (strongNamed) - { - if (StrongNamedModule == null) - { - throw new InvalidOperationException("No strong-named assembly has been generated."); - } - assemblyBuilder = (AssemblyBuilder)StrongNamedModule.Assembly; - assemblyFileName = StrongNamedModuleName; - assemblyFilePath = StrongNamedModule.FullyQualifiedName; - } - else - { - if (WeakNamedModule == null) - { - throw new InvalidOperationException("No weak-named assembly has been generated."); - } - assemblyBuilder = (AssemblyBuilder)WeakNamedModule.Assembly; - assemblyFileName = WeakNamedModuleName; - assemblyFilePath = WeakNamedModule.FullyQualifiedName; - } - - if (File.Exists(assemblyFilePath)) - { - File.Delete(assemblyFilePath); - } - -#if FEATURE_SERIALIZATION - AddCacheMappings(assemblyBuilder); -#endif - - assemblyBuilder.Save(assemblyFileName); - return assemblyFilePath; - } -#endif - -#if FEATURE_SERIALIZATION - private void AddCacheMappings(AssemblyBuilder builder) - { - var mappings = new Dictionary(); - - typeCache.ForEach((key, value) => - { - // NOTE: using == returns invalid results. - // we need to use Equals here for it to work properly - if (builder.Equals(value.Assembly)) - { - mappings.Add(key, value.FullName); - } - }); - - CacheMappingsAttribute.ApplyTo(builder, mappings); - } - - /// - /// Loads the generated types from the given assembly into this 's cache. - /// - /// The assembly to load types from. This assembly must have been saved via or - /// , or it must have the manually applied. - /// - /// This method can be used to load previously generated and persisted proxy types from disk into this scope's type cache, e.g. in order - /// to avoid the performance hit associated with proxy generation. - /// - public void LoadAssemblyIntoCache(Assembly assembly) - { - if (assembly == null) - { - throw new ArgumentNullException(nameof(assembly)); - } - - var cacheMappings = - (CacheMappingsAttribute[])assembly.GetCustomAttributes(typeof(CacheMappingsAttribute), false); - - if (cacheMappings.Length == 0) - { - var message = string.Format( - "The given assembly '{0}' does not contain any cache information for generated types.", - assembly.FullName); - throw new ArgumentException(message, nameof(assembly)); - } - - foreach (var mapping in cacheMappings[0].GetDeserializedMappings()) - { - var loadedType = assembly.GetType(mapping.Value); - - if (loadedType != null) - { - typeCache.AddOrUpdateWithoutTakingLock(mapping.Key, loadedType); - } - } - } -#endif - - internal TypeBuilder DefineType(bool inSignedModulePreferably, string name, TypeAttributes flags) - { - var module = ObtainDynamicModule(disableSignedModule == false && inSignedModulePreferably); - return module.DefineType(name, flags); - } - } -} diff --git a/Castle.Core/DynamicProxy/PersistentProxyBuilder.cs b/Castle.Core/DynamicProxy/PersistentProxyBuilder.cs deleted file mode 100644 index c874f9b..0000000 --- a/Castle.Core/DynamicProxy/PersistentProxyBuilder.cs +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#if FEATURE_ASSEMBLYBUILDER_SAVE - -namespace Castle.DynamicProxy -{ - /// - /// ProxyBuilder that persists the generated type. - /// - /// - /// The saved assembly contains just the last generated type. - /// - public class PersistentProxyBuilder : DefaultProxyBuilder - { - /// - /// Initializes a new instance of the class. - /// - public PersistentProxyBuilder() : base(new ModuleScope(true)) - { - } - - /// - /// Saves the generated assembly to a physical file. Note that this renders the unusable. - /// - /// The path of the generated assembly file, or null if no assembly has been generated. - /// - /// This method does not support saving multiple files. If both a signed and an unsigned module have been generated, use the - /// respective methods of the . - /// - public string SaveAssembly() - { - return ModuleScope.SaveAssembly(); - } - } -} - -#endif \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/ProxyGenerationOptions.cs b/Castle.Core/DynamicProxy/ProxyGenerationOptions.cs deleted file mode 100644 index 515de4b..0000000 --- a/Castle.Core/DynamicProxy/ProxyGenerationOptions.cs +++ /dev/null @@ -1,353 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy -{ - using System; - using System.Collections.Generic; - using System.Linq; - using System.Reflection; - using System.Reflection.Emit; -#if FEATURE_SERIALIZATION - using System.Runtime.Serialization; -#endif - - using Castle.DynamicProxy.Internal; - - /// - /// allows customization of the behavior of proxies created by - /// an (or proxy types generated by an ). - /// - /// You should not modify an instance of once it has been - /// used to create a proxy (or proxy type). - /// - /// -#if FEATURE_SERIALIZATION - [Serializable] -#endif - public class ProxyGenerationOptions -#if FEATURE_SERIALIZATION - : ISerializable -#endif - { - public static readonly ProxyGenerationOptions Default = new ProxyGenerationOptions(); - - private List mixins; - private readonly IList additionalAttributes = new List(); - -#if FEATURE_SERIALIZATION - [NonSerialized] -#endif - private MixinData mixinData; // this is calculated dynamically on proxy type creation - - /// - /// Initializes a new instance of the class. - /// - /// The hook. - public ProxyGenerationOptions(IProxyGenerationHook hook) - { - BaseTypeForInterfaceProxy = typeof(object); - Hook = hook; - } - - /// - /// Initializes a new instance of the class. - /// - public ProxyGenerationOptions() - : this(new AllMethodsHook()) - { - } - -#if FEATURE_SERIALIZATION - private ProxyGenerationOptions(SerializationInfo info, StreamingContext context) - { - Hook = (IProxyGenerationHook)info.GetValue("hook", typeof(IProxyGenerationHook)); - Selector = (IInterceptorSelector)info.GetValue("selector", typeof(IInterceptorSelector)); - mixins = (List)info.GetValue("mixins", typeof(List)); - BaseTypeForInterfaceProxy = Type.GetType(info.GetString("baseTypeForInterfaceProxy.AssemblyQualifiedName")); - } -#endif - - public void Initialize() - { - if (mixinData == null) - { - try - { - mixinData = new MixinData(mixins); - } - catch (ArgumentException ex) - { - throw new InvalidOperationException( - "There is a problem with the mixins added to this ProxyGenerationOptions. See the inner exception for details.", ex); - } - } - } - -#if FEATURE_SERIALIZATION - public void GetObjectData(SerializationInfo info, StreamingContext context) - { - info.AddValue("hook", Hook); - info.AddValue("selector", Selector); - info.AddValue("mixins", mixins); - info.AddValue("baseTypeForInterfaceProxy.AssemblyQualifiedName", BaseTypeForInterfaceProxy.AssemblyQualifiedName); - } -#endif - - /// - /// Gets or sets the that should be used during proxy type - /// generation. Defaults to an instance of . - /// - /// You should not modify this property once this instance - /// has been used to create a proxy. - /// - /// - public IProxyGenerationHook Hook { get; set; } - - /// - /// Gets or sets the that should be used by created proxies - /// to determine which interceptors to use for an interception. If set to - /// (which is the default), created proxies will not use any selector. - /// - /// You should not modify this property once this instance - /// has been used to create a proxy. - /// - /// - public IInterceptorSelector Selector { get; set; } - - /// - /// Gets or sets the class type from which generated interface proxy types will be derived. - /// Defaults to (). - /// - /// You should not modify this property once this instance - /// has been used to create a proxy. - /// - /// - public Type BaseTypeForInterfaceProxy { get; set; } - - /// - /// Gets the collection of additional custom attributes that will be put on generated proxy types. - /// This collection is initially empty. - /// - /// You should not modify this collection once this instance - /// has been used to create a proxy. - /// - /// - public IList AdditionalAttributes - { - get { return additionalAttributes; } - } - - public MixinData MixinData - { - get - { - if (mixinData == null) - { - throw new InvalidOperationException("Call Initialize before accessing the MixinData property."); - } - return mixinData; - } - } - - /// - /// Adds a delegate type to the list of mixins that will be added to generated proxies. - /// That is, generated proxies will have a `Invoke` method with a signature matching that - /// of the specified . - /// - /// You should not call this method once this instance - /// has been used to create a proxy. - /// - /// - /// The delegate type whose `Invoke` method should be reproduced in generated proxies. - /// is . - /// is not a delegate type. - public void AddDelegateTypeMixin(Type delegateType) - { - if (delegateType == null) throw new ArgumentNullException(nameof(delegateType)); - if (!delegateType.IsDelegateType()) throw new ArgumentException("Type must be a delegate type.", nameof(delegateType)); - - AddMixinImpl(delegateType); - } - - /// - /// Adds a delegate to be mixed into generated proxies. The - /// will act as the target for calls to a `Invoke` method with a signature matching that - /// of the delegate. - /// - /// You should not call this method once this instance - /// has been used to create a proxy. - /// - /// - /// The delegate that should act as the target for calls to `Invoke` methods with a matching signature. - /// is . - public void AddDelegateMixin(Delegate @delegate) - { - if (@delegate == null) throw new ArgumentNullException(nameof(@delegate)); - - AddMixinImpl(@delegate); - } - - /// - /// Mixes the interfaces implemented by the specified object into - /// created proxies, and uses as the target for these mixed-in interfaces. - /// - /// You should not call this method once this instance - /// has been used to create a proxy. - /// - /// - /// The object that should act as the target for all of its implemented interfaces' methods. - /// is . - /// is an instance of . - public void AddMixinInstance(object instance) - { - if (instance == null) throw new ArgumentNullException(nameof(instance)); - if (instance is Type) throw new ArgumentException("You may not mix in types using this method.", nameof(instance)); - - AddMixinImpl(instance); - } - - private void AddMixinImpl(object instanceOrType) - { - if (mixins == null) - { - mixins = new List(); - } - - mixins.Add(instanceOrType); - mixinData = null; - } - - public object[] MixinsAsArray() - { - if (mixins == null) - { - return new object[0]; - } - - return mixins.ToArray(); - } - - public bool HasMixins - { - get { return mixins != null && mixins.Count != 0; } - } - - public override bool Equals(object obj) - { - if (ReferenceEquals(this, obj)) - { - return true; - } - - var proxyGenerationOptions = obj as ProxyGenerationOptions; - if (ReferenceEquals(proxyGenerationOptions, null)) - { - return false; - } - - // ensure initialization before accessing MixinData - Initialize(); - proxyGenerationOptions.Initialize(); - - if (!Equals(Hook, proxyGenerationOptions.Hook)) - { - return false; - } - if (!Equals(Selector == null, proxyGenerationOptions.Selector == null)) - { - return false; - } - if (!Equals(MixinData, proxyGenerationOptions.MixinData)) - { - return false; - } - if (!Equals(BaseTypeForInterfaceProxy, proxyGenerationOptions.BaseTypeForInterfaceProxy)) - { - return false; - } - if (!HasEquivalentAdditionalAttributes(proxyGenerationOptions)) - { - return false; - } - return true; - } - - public override int GetHashCode() - { - // ensure initialization before accessing MixinData - Initialize(); - - var result = Hook != null ? Hook.GetType().GetHashCode() : 0; - result = 29*result + (Selector != null ? 1 : 0); - result = 29*result + MixinData.GetHashCode(); - result = 29*result + (BaseTypeForInterfaceProxy != null ? BaseTypeForInterfaceProxy.GetHashCode() : 0); - result = 29*result + GetAdditionalAttributesHashCode(); - return result; - } - - private int GetAdditionalAttributesHashCode() - { - var result = 0; - for (var i = 0; i < additionalAttributes.Count; i++) - { - if (additionalAttributes[i] != null) - { - // simply add since order does not matter - result += additionalAttributes[i].GetHashCode(); - } - } - - return result; - } - - private bool HasEquivalentAdditionalAttributes(ProxyGenerationOptions other) - { - var listA = additionalAttributes; - var listB = other.additionalAttributes; - - if (listA.Count != listB.Count) - { - return false; - } - - // copy contents to another list so that contents can be removed as they are found, - // in order to consider duplicates - var listBAvailableContents = listB.ToList(); - - // order is not important, just make sure that each entry in A is also found in B - for (var i = 0; i < listA.Count; i++) - { - var found = false; - - for (var j = 0; j < listBAvailableContents.Count; j++) - { - if (Equals(listA[i], listBAvailableContents[j])) - { - found = true; - listBAvailableContents.RemoveAt(j); - break; - } - } - - if (!found) - { - return false; - } - } - - return true; - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/ProxyGenerator.cs b/Castle.Core/DynamicProxy/ProxyGenerator.cs deleted file mode 100644 index 019b230..0000000 --- a/Castle.Core/DynamicProxy/ProxyGenerator.cs +++ /dev/null @@ -1,1564 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy -{ - using System; - using System.Collections.Generic; - using System.Diagnostics; - using System.Reflection; - using System.Runtime.InteropServices; - using System.Text; - - using Castle.Core.Internal; - using Castle.Core.Logging; - using Castle.DynamicProxy.Generators; - - /// - /// Provides proxy objects for classes and interfaces. - /// - [CLSCompliant(true)] - public class ProxyGenerator : IProxyGenerator - { - private ILogger logger = NullLogger.Instance; - private readonly IProxyBuilder proxyBuilder; - - /// - /// Initializes a new instance of the class. - /// - /// Proxy types builder. - public ProxyGenerator(IProxyBuilder builder) - { - proxyBuilder = builder; - - Logger = NullLogger.Instance; - } - - /// - /// Initializes a new instance of the class. - /// - public ProxyGenerator() : this(new DefaultProxyBuilder()) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// If true forces all types to be generated into an unsigned module. - public ProxyGenerator(bool disableSignedModule) : this(new DefaultProxyBuilder(new ModuleScope(false, disableSignedModule))) - { - } - - /// - /// Gets or sets the that this log to. - /// - public ILogger Logger - { - get { return logger; } - set - { - logger = value; - proxyBuilder.Logger = value; - } - } - - /// - /// Gets the proxy builder instance used to generate proxy types. - /// - /// The proxy builder. - public IProxyBuilder ProxyBuilder - { - get { return proxyBuilder; } - } - - /// - /// Creates proxy object intercepting calls to members of interface on object with given . - /// - /// Type of the interface implemented by which will be proxied. - /// The target object, calls to which will be intercepted. - /// The interceptors called during the invocation of proxied methods. - /// Object proxying calls to members of on object. - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given array is a null reference (Nothing in Visual Basic). - /// Thrown when given is not an interface type. - /// Thrown when no default constructor exists on actual type of object. - /// Thrown when default constructor of actual type of throws an exception. - /// - /// This method generates new proxy type for each type of , which affects performance. If you don't want to proxy types differently depending on the type of the target - /// use method. - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - public TInterface CreateInterfaceProxyWithTarget(TInterface target, params IInterceptor[] interceptors) - where TInterface : class - { - // NOTE: we don't need to document exception case where interface type is null, since it can never be for a generic method. - // If we leave target as being of type TInterface we also have covered exception where target does not implement TInterface. - - // NOTE: Can any other Activator.CreateInstance exception be thrown in this context? - - return - (TInterface) - CreateInterfaceProxyWithTarget(typeof(TInterface), target, ProxyGenerationOptions.Default, interceptors); - } - - /// - /// Creates proxy object intercepting calls to members of interface on object with given . - /// - /// Type of the interface implemented by which will be proxied. - /// The target object, calls to which will be intercepted. - /// The proxy generation options used to influence generated proxy type and object. - /// The interceptors called during the invocation of proxied methods. - /// - /// Object proxying calls to members of on object. - /// - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given array is a null reference (Nothing in Visual Basic). - /// Thrown when given is not an interface type. - /// Thrown when no default constructor exists on actual type of object. - /// Thrown when default constructor of actual type of throws an exception. - /// - /// This method generates new proxy type for each type of , which affects performance. If you don't want to proxy types differently depending on the type of the target - /// use method. - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - public TInterface CreateInterfaceProxyWithTarget(TInterface target, ProxyGenerationOptions options, - params IInterceptor[] interceptors) - where TInterface : class - { - return (TInterface)CreateInterfaceProxyWithTarget(typeof(TInterface), target, options, interceptors); - } - - /// - /// Creates proxy object intercepting calls to members of interface on object with given . - /// - /// Type of the interface implemented by which will be proxied. - /// The target object, calls to which will be intercepted. - /// The interceptors called during the invocation of proxied methods. - /// - /// Object proxying calls to members of type on object. - /// - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given array is a null reference (Nothing in Visual Basic). - /// Thrown when given is a generic type definition. - /// Thrown when given is not an interface type. - /// Thrown when given does not implement interface. - /// Thrown when no default constructor exists on actual type of object. - /// Thrown when default constructor of actual type of throws an exception. - /// - /// This method generates new proxy type for each type of , which affects performance. If you don't want to proxy types differently depending on the type of the target - /// use method. - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - public object CreateInterfaceProxyWithTarget(Type interfaceToProxy, object target, params IInterceptor[] interceptors) - { - return CreateInterfaceProxyWithTarget(interfaceToProxy, target, ProxyGenerationOptions.Default, interceptors); - } - - /// - /// Creates proxy object intercepting calls to members of interface on object with given . - /// - /// Type of the interface implemented by which will be proxied. - /// The target object, calls to which will be intercepted. - /// The proxy generation options used to influence generated proxy type and object. - /// The interceptors called during the invocation of proxied methods. - /// - /// Object proxying calls to members of type on object. - /// - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given array is a null reference (Nothing in Visual Basic). - /// Thrown when given is a generic type definition. - /// Thrown when given is not an interface type. - /// Thrown when given does not implement interface. - /// Thrown when no default constructor exists on actual type of object. - /// Thrown when default constructor of actual type of throws an exception. - /// - /// This method generates new proxy type for each type of , which affects performance. If you don't want to proxy types differently depending on the type of the target - /// use method. - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - public object CreateInterfaceProxyWithTarget(Type interfaceToProxy, object target, ProxyGenerationOptions options, - params IInterceptor[] interceptors) - { - return CreateInterfaceProxyWithTarget(interfaceToProxy, null, target, options, interceptors); - } - - /// - /// Creates proxy object intercepting calls to members of interface on object with given . - /// - /// Type of the interface implemented by which will be proxied. - /// The target object, calls to which will be intercepted. - /// Additional interface types. Calls to their members will be proxied as well. - /// The interceptors called during the invocation of proxied methods. - /// - /// Object proxying calls to members of and types on object. - /// - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given array is a null reference (Nothing in Visual Basic). - /// Thrown when given or any of is a generic type definition. - /// Thrown when given is not an interface type. - /// Thrown when given does not implement interface. - /// Thrown when no default constructor exists on actual type of object. - /// Thrown when default constructor of actual type of throws an exception. - /// - /// This method generates new proxy type for each type of , which affects performance. If you don't want to proxy types differently depending on the type of the target - /// use method. - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - public object CreateInterfaceProxyWithTarget(Type interfaceToProxy, Type[] additionalInterfacesToProxy, object target, - params IInterceptor[] interceptors) - { - return CreateInterfaceProxyWithTarget(interfaceToProxy, additionalInterfacesToProxy, target, - ProxyGenerationOptions.Default, interceptors); - } - - /// - /// Creates proxy object intercepting calls to members of interface on object with given . - /// - /// Type of the interface implemented by which will be proxied. - /// The target object, calls to which will be intercepted. - /// The proxy generation options used to influence generated proxy type and object. - /// Additional interface types. Calls to their members will be proxied as well. - /// The interceptors called during the invocation of proxied methods. - /// - /// Object proxying calls to members of and types on object. - /// - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given array is a null reference (Nothing in Visual Basic). - /// Thrown when given or any of is a generic type definition. - /// Thrown when given is not an interface type. - /// Thrown when given does not implement interface. - /// Thrown when no default constructor exists on actual type of object. - /// Thrown when default constructor of actual type of throws an exception. - /// - /// This method generates new proxy type for each type of , which affects performance. If you don't want to proxy types differently depending on the type of the target - /// use method. - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - public virtual object CreateInterfaceProxyWithTarget(Type interfaceToProxy, Type[] additionalInterfacesToProxy, - object target, - ProxyGenerationOptions options, - params IInterceptor[] interceptors) - { - if (interfaceToProxy == null) - { - throw new ArgumentNullException(nameof(interfaceToProxy)); - } - if (target == null) - { - throw new ArgumentNullException(nameof(target)); - } - if (interceptors == null) - { - throw new ArgumentNullException(nameof(interceptors)); - } - - if (!interfaceToProxy.IsInterface) - { - throw new ArgumentException("Specified type is not an interface", nameof(interfaceToProxy)); - } - - var targetType = target.GetType(); - if (!interfaceToProxy.IsAssignableFrom(targetType)) - { - throw new ArgumentException("Target does not implement interface " + interfaceToProxy.FullName, nameof(target)); - } - - CheckNotGenericTypeDefinition(interfaceToProxy, nameof(interfaceToProxy)); - CheckNotGenericTypeDefinitions(additionalInterfacesToProxy, nameof(additionalInterfacesToProxy)); - - var generatedType = CreateInterfaceProxyTypeWithTarget(interfaceToProxy, additionalInterfacesToProxy, targetType, - options); - - var arguments = GetConstructorArguments(target, interceptors, options); - return Activator.CreateInstance(generatedType, arguments.ToArray()); - } - - protected List GetConstructorArguments(object target, IInterceptor[] interceptors, - ProxyGenerationOptions options) - { - // create constructor arguments (initialized with mixin implementations, interceptors and target type constructor arguments) - var arguments = new List(options.MixinData.Mixins) { interceptors, target }; - if (options.Selector != null) - { - arguments.Add(options.Selector); - } - return arguments; - } - - /// - /// Creates proxy object intercepting calls to members of interface on object with given . - /// Interceptors can use interface to provide other target for method invocation than default . - /// - /// Type of the interface implemented by which will be proxied. - /// The target object, calls to which will be intercepted. - /// The interceptors called during the invocation of proxied methods. - /// - /// Object proxying calls to members of type on object or alternative implementation swapped at runtime by an interceptor. - /// - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given array is a null reference (Nothing in Visual Basic). - /// Thrown when given is a generic type definition. - /// Thrown when given is not an interface type. - /// Thrown when given does not implement interface. - /// Thrown when no default constructor exists on actual type of object. - /// Thrown when default constructor of actual type of throws an exception. - /// - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - public object CreateInterfaceProxyWithTargetInterface(Type interfaceToProxy, object target, - params IInterceptor[] interceptors) - { - return CreateInterfaceProxyWithTargetInterface(interfaceToProxy, target, ProxyGenerationOptions.Default, interceptors); - } - - /// - /// Creates proxy object intercepting calls to members of interface on object with given . - /// Interceptors can use interface to provide other target for method invocation than default . - /// - /// Type of the interface implemented by which will be proxied. - /// The target object, calls to which will be intercepted. - /// The interceptors called during the invocation of proxied methods. - /// - /// Object proxying calls to members of type on object or alternative implementation swapped at runtime by an interceptor. - /// - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given array is a null reference (Nothing in Visual Basic). - /// Thrown when given is not an interface type. - /// Thrown when no default constructor exists on actual type of object. - /// Thrown when default constructor of actual type of throws an exception. - /// - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - public TInterface CreateInterfaceProxyWithTargetInterface(TInterface target, - params IInterceptor[] interceptors) - where TInterface : class - { - return (TInterface)CreateInterfaceProxyWithTargetInterface(typeof(TInterface), - target, - ProxyGenerationOptions.Default, - interceptors); - } - - /// - /// Creates proxy object intercepting calls to members of interface on object with given . - /// Interceptors can use interface to provide other target for method invocation than default . - /// - /// Type of the interface implemented by which will be proxied. - /// The target object, calls to which will be intercepted. - /// The proxy generation options used to influence generated proxy type and object. - /// The interceptors called during the invocation of proxied methods. - /// - /// Object proxying calls to members of type on object or alternative implementation swapped at runtime by an interceptor. - /// - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given array is a null reference (Nothing in Visual Basic). - /// Thrown when given is not an interface type. - /// Thrown when no default constructor exists on actual type of object. - /// Thrown when default constructor of actual type of throws an exception. - /// - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - public TInterface CreateInterfaceProxyWithTargetInterface(TInterface target, - ProxyGenerationOptions options, - params IInterceptor[] interceptors) - where TInterface : class - { - return (TInterface)CreateInterfaceProxyWithTargetInterface(typeof(TInterface), - target, - options, - interceptors); - } - - /// - /// Creates proxy object intercepting calls to members of interface on object with given . - /// Interceptors can use interface to provide other target for method invocation than default . - /// - /// Type of the interface implemented by which will be proxied. - /// The target object, calls to which will be intercepted. - /// Additional interface types. Calls to their members will be proxied as well. - /// The interceptors called during the invocation of proxied methods. - /// - /// Object proxying calls to members of and types on object or alternative implementation swapped at runtime by an interceptor. - /// - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given array is a null reference (Nothing in Visual Basic). - /// Thrown when given or any of is a generic type definition. - /// Thrown when given is not an interface type. - /// Thrown when given does not implement interface. - /// Thrown when no default constructor exists on actual type of object. - /// Thrown when default constructor of actual type of throws an exception. - /// - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - public object CreateInterfaceProxyWithTargetInterface(Type interfaceToProxy, Type[] additionalInterfacesToProxy, - object target, params IInterceptor[] interceptors) - { - return CreateInterfaceProxyWithTargetInterface(interfaceToProxy, additionalInterfacesToProxy, target, - ProxyGenerationOptions.Default, interceptors); - } - - /// - /// Creates proxy object intercepting calls to members of interface on object with given . - /// Interceptors can use interface to provide other target for method invocation than default . - /// - /// Type of the interface implemented by which will be proxied. - /// The target object, calls to which will be intercepted. - /// The proxy generation options used to influence generated proxy type and object. - /// The interceptors called during the invocation of proxied methods. - /// - /// Object proxying calls to members of type on object or alternative implementation swapped at runtime by an interceptor. - /// - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given array is a null reference (Nothing in Visual Basic). - /// Thrown when given is a generic type definition. - /// Thrown when given is not an interface type. - /// Thrown when given does not implement interface. - /// Thrown when no default constructor exists on actual type of object. - /// Thrown when default constructor of actual type of throws an exception. - /// - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - public object CreateInterfaceProxyWithTargetInterface(Type interfaceToProxy, object target, - ProxyGenerationOptions options, - params IInterceptor[] interceptors) - { - return CreateInterfaceProxyWithTargetInterface(interfaceToProxy, null, target, options, interceptors); - } - - /// - /// Creates proxy object intercepting calls to members of interface on object with given . - /// Interceptors can use interface to provide other target for method invocation than default . - /// - /// Type of the interface implemented by which will be proxied. - /// The target object, calls to which will be intercepted. - /// The proxy generation options used to influence generated proxy type and object. - /// Additional interface types. Calls to their members will be proxied as well. - /// The interceptors called during the invocation of proxied methods. - /// - /// Object proxying calls to members of and types on object or alternative implementation swapped at runtime by an interceptor. - /// - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given array is a null reference (Nothing in Visual Basic). - /// Thrown when given or any of is a generic type definition. - /// Thrown when given is not an interface type. - /// Thrown when given does not implement interface. - /// Thrown when no default constructor exists on actual type of object. - /// Thrown when default constructor of actual type of throws an exception. - /// - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - public virtual object CreateInterfaceProxyWithTargetInterface(Type interfaceToProxy, - Type[] additionalInterfacesToProxy, - object target, ProxyGenerationOptions options, - params IInterceptor[] interceptors) - { - //TODO: add to xml comments to show how to use IChangeProxyTarget - - if (interfaceToProxy == null) - { - throw new ArgumentNullException(nameof(interfaceToProxy)); - } - // In the case of a transparent proxy, the call to IsInstanceOfType was executed on the real object. - if (target != null && interfaceToProxy.IsInstanceOfType(target) == false) - { - throw new ArgumentException("Target does not implement interface " + interfaceToProxy.FullName, nameof(target)); - } - if (interceptors == null) - { - throw new ArgumentNullException(nameof(interceptors)); - } - - if (!interfaceToProxy.IsInterface) - { - throw new ArgumentException("Specified type is not an interface", nameof(interfaceToProxy)); - } - - if (target != null) - { - if (Marshal.IsComObject(target)) - { - var interfaceId = interfaceToProxy.GUID; - if (interfaceId != Guid.Empty) - { - var iUnknown = Marshal.GetIUnknownForObject(target); // Increment the reference count - var interfacePointer = IntPtr.Zero; - var result = Marshal.QueryInterface(iUnknown, ref interfaceId, out interfacePointer); // Increment the reference count - var isInterfacePointerNull = interfacePointer == IntPtr.Zero; - Marshal.Release(iUnknown); // Decrement the reference count - if (!isInterfacePointerNull) - { - Marshal.Release(interfacePointer); // Decrement the reference count - } - - if (result == 0 && isInterfacePointerNull) - { - throw new ArgumentException("Target COM object does not implement interface " + interfaceToProxy.FullName, - nameof(target)); - } - } - } - } - - CheckNotGenericTypeDefinition(interfaceToProxy, nameof(interfaceToProxy)); - CheckNotGenericTypeDefinitions(additionalInterfacesToProxy, nameof(additionalInterfacesToProxy)); - - var generatedType = CreateInterfaceProxyTypeWithTargetInterface(interfaceToProxy, additionalInterfacesToProxy, - options); - var arguments = GetConstructorArguments(target, interceptors, options); - return Activator.CreateInstance(generatedType, arguments.ToArray()); - } - - /// - /// Creates proxy object intercepting calls to members of interface on target object generated at runtime with given . - /// - /// Type of the interface which will be proxied. - /// The interceptors called during the invocation of proxied methods. - /// - /// Object proxying calls to members of types on generated target object. - /// - /// Thrown when given array is a null reference (Nothing in Visual Basic). - /// Thrown when given is not an interface type. - /// - /// Since this method uses an empty-shell implementation of interfaces to proxy generated at runtime, the actual implementation of proxied methods must be provided by given implementations. - /// They are responsible for setting return value (and out parameters) on proxied methods. It is also illegal for an interceptor to call , since there's no actual implementation to proceed with. - /// As a result of that also at least one implementation must be provided. - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - public TInterface CreateInterfaceProxyWithoutTarget(IInterceptor interceptor) - where TInterface : class - { - return (TInterface)CreateInterfaceProxyWithoutTarget(typeof(TInterface), interceptor); - } - - /// - /// Creates proxy object intercepting calls to members of interface on target object generated at runtime with given . - /// - /// Type of the interface which will be proxied. - /// The interceptors called during the invocation of proxied methods. - /// - /// Object proxying calls to members of types on generated target object. - /// - /// Thrown when given array is a null reference (Nothing in Visual Basic). - /// Thrown when given is not an interface type. - /// - /// Since this method uses an empty-shell implementation of interfaces to proxy generated at runtime, the actual implementation of proxied methods must be provided by given implementations. - /// They are responsible for setting return value (and out parameters) on proxied methods. It is also illegal for an interceptor to call , since there's no actual implementation to proceed with. - /// As a result of that also at least one implementation must be provided. - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - public TInterface CreateInterfaceProxyWithoutTarget(params IInterceptor[] interceptors) - where TInterface : class - { - return (TInterface)CreateInterfaceProxyWithoutTarget(typeof(TInterface), interceptors); - } - - /// - /// Creates proxy object intercepting calls to members of interface on target object generated at runtime with given . - /// - /// Type of the interface which will be proxied. - /// The proxy generation options used to influence generated proxy type and object. - /// The interceptors called during the invocation of proxied methods. - /// - /// Object proxying calls to members of types on generated target object. - /// - /// Thrown when given array is a null reference (Nothing in Visual Basic). - /// Thrown when given is not an interface type. - /// - /// Since this method uses an empty-shell implementation of interfaces to proxy generated at runtime, the actual implementation of proxied methods must be provided by given implementations. - /// They are responsible for setting return value (and out parameters) on proxied methods. It is also illegal for an interceptor to call , since there's no actual implementation to proceed with. - /// As a result of that also at least one implementation must be provided. - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - public TInterface CreateInterfaceProxyWithoutTarget(ProxyGenerationOptions options, - params IInterceptor[] interceptors) - where TInterface : class - { - return (TInterface)CreateInterfaceProxyWithoutTarget(typeof(TInterface), Type.EmptyTypes, options, interceptors); - } - - /// - /// Creates proxy object intercepting calls to members of interface on target object generated at runtime with given . - /// - /// Type of the interface which will be proxied. - /// The interceptors called during the invocation of proxied methods. - /// - /// Object proxying calls to members of type on generated target object. - /// - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given array is a null reference (Nothing in Visual Basic). - /// Thrown when given is a generic type definition. - /// Thrown when given is not an interface type. - /// - /// Since this method uses an empty-shell implementation of interfaces to proxy generated at runtime, the actual implementation of proxied methods must be provided by given implementations. - /// They are responsible for setting return value (and out parameters) on proxied methods. It is also illegal for an interceptor to call , since there's no actual implementation to proceed with. - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - public object CreateInterfaceProxyWithoutTarget(Type interfaceToProxy, IInterceptor interceptor) - { - return CreateInterfaceProxyWithoutTarget(interfaceToProxy, Type.EmptyTypes, ProxyGenerationOptions.Default, - interceptor); - } - - /// - /// Creates proxy object intercepting calls to members of interface on target object generated at runtime with given . - /// - /// Type of the interface which will be proxied. - /// The interceptors called during the invocation of proxied methods. - /// - /// Object proxying calls to members of type on generated target object. - /// - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given array is a null reference (Nothing in Visual Basic). - /// Thrown when given is a generic type definition. - /// Thrown when given is not an interface type. - /// - /// Since this method uses an empty-shell implementation of interfaces to proxy generated at runtime, the actual implementation of proxied methods must be provided by given implementations. - /// They are responsible for setting return value (and out parameters) on proxied methods. It is also illegal for an interceptor to call , since there's no actual implementation to proceed with. - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - public object CreateInterfaceProxyWithoutTarget(Type interfaceToProxy, params IInterceptor[] interceptors) - { - return CreateInterfaceProxyWithoutTarget(interfaceToProxy, Type.EmptyTypes, ProxyGenerationOptions.Default, - interceptors); - } - - /// - /// Creates proxy object intercepting calls to members of interface on target object generated at runtime with given . - /// - /// Type of the interface which will be proxied. - /// Additional interface types. Calls to their members will be proxied as well. - /// The interceptors called during the invocation of proxied methods. - /// - /// Object proxying calls to members of and types on generated target object. - /// - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given array is a null reference (Nothing in Visual Basic). - /// Thrown when given or any of is a generic type definition. - /// Thrown when given is not an interface type. - /// - /// Since this method uses an empty-shell implementation of interfaces to proxy generated at runtime, the actual implementation of proxied methods must be provided by given implementations. - /// They are responsible for setting return value (and out parameters) on proxied methods. It is also illegal for an interceptor to call , since there's no actual implementation to proceed with. - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - public object CreateInterfaceProxyWithoutTarget(Type interfaceToProxy, Type[] additionalInterfacesToProxy, - params IInterceptor[] interceptors) - { - return CreateInterfaceProxyWithoutTarget(interfaceToProxy, additionalInterfacesToProxy, - ProxyGenerationOptions.Default, interceptors); - } - - /// - /// Creates proxy object intercepting calls to members of interface on target object generated at runtime with given . - /// - /// Type of the interface which will be proxied. - /// The proxy generation options used to influence generated proxy type and object. - /// The interceptors called during the invocation of proxied methods. - /// - /// Object proxying calls to members of on generated target object. - /// - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given array is a null reference (Nothing in Visual Basic). - /// Thrown when given is a generic type definition. - /// Thrown when given is not an interface type. - /// - /// They are responsible for setting return value (and out parameters) on proxied methods. It is also illegal for an interceptor to call , since there's no actual implementation to proceed with. - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - public object CreateInterfaceProxyWithoutTarget(Type interfaceToProxy, ProxyGenerationOptions options, - params IInterceptor[] interceptors) - { - return CreateInterfaceProxyWithoutTarget(interfaceToProxy, Type.EmptyTypes, options, interceptors); - } - - /// - /// Creates proxy object intercepting calls to members of interface on target object generated at runtime with given . - /// - /// Type of the interface which will be proxied. - /// The proxy generation options used to influence generated proxy type and object. - /// Additional interface types. Calls to their members will be proxied as well. - /// The interceptors called during the invocation of proxied methods. - /// - /// Object proxying calls to members of and types on generated target object. - /// - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given array is a null reference (Nothing in Visual Basic). - /// Thrown when given or any of is a generic type definition. - /// Thrown when given is not an interface type. - /// - /// Since this method uses an empty-shell implementation of to proxy generated at runtime, the actual implementation of proxied methods must be provided by given implementations. - /// They are responsible for setting return value (and out parameters) on proxied methods. It is also illegal for an interceptor to call , since there's no actual implementation to proceed with. - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - public virtual object CreateInterfaceProxyWithoutTarget(Type interfaceToProxy, Type[] additionalInterfacesToProxy, - ProxyGenerationOptions options, - params IInterceptor[] interceptors) - { - if (interfaceToProxy == null) - { - throw new ArgumentNullException(nameof(interfaceToProxy)); - } - if (interceptors == null) - { - throw new ArgumentNullException(nameof(interceptors)); - } - - if (!interfaceToProxy.IsInterface) - { - throw new ArgumentException("Specified type is not an interface", nameof(interfaceToProxy)); - } - - CheckNotGenericTypeDefinition(interfaceToProxy, nameof(interfaceToProxy)); - CheckNotGenericTypeDefinitions(additionalInterfacesToProxy, nameof(additionalInterfacesToProxy)); - - var generatedType = CreateInterfaceProxyTypeWithoutTarget(interfaceToProxy, additionalInterfacesToProxy, options); - var arguments = GetConstructorArguments(null, interceptors, options); - return Activator.CreateInstance(generatedType, arguments.ToArray()); - } - - /// - /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . - /// - /// Type of class which will be proxied. - /// The target object, calls to which will be intercepted. - /// The interceptors called during the invocation of proxied methods. - /// - /// New object of type proxying calls to virtual members of type. - /// - /// Thrown when given is not a class type. - /// Thrown when no default constructor exists on type . - /// Thrown when default constructor of type throws an exception. - /// - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - public TClass CreateClassProxyWithTarget(TClass target, params IInterceptor[] interceptors) - where TClass : class - { - return (TClass)CreateClassProxyWithTarget(typeof(TClass), - Type.EmptyTypes, - target, - ProxyGenerationOptions.Default, - new object[0], - interceptors); - } - - /// - /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . - /// - /// Type of class which will be proxied. - /// The target object, calls to which will be intercepted. - /// The proxy generation options used to influence generated proxy type and object. - /// The interceptors called during the invocation of proxied methods. - /// - /// New object of type proxying calls to virtual members of type. - /// - /// Thrown when given is not a class type. - /// Thrown when no default constructor exists on type . - /// Thrown when default constructor of type throws an exception. - /// - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - public TClass CreateClassProxyWithTarget(TClass target, ProxyGenerationOptions options, - params IInterceptor[] interceptors) where TClass : class - { - return (TClass)CreateClassProxyWithTarget(typeof(TClass), - Type.EmptyTypes, - target, - options, - new object[0], - interceptors); - } - - /// - /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . - /// - /// Type of class which will be proxied. - /// Additional interface types. Calls to their members will be proxied as well. - /// The target object, calls to which will be intercepted. - /// The interceptors called during the invocation of proxied methods. - /// - /// New object of type proxying calls to virtual members of and types. - /// - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given or any of is a generic type definition. - /// Thrown when given is not a class type. - /// Thrown when no default constructor exists on type . - /// Thrown when default constructor of type throws an exception. - /// - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - public object CreateClassProxyWithTarget(Type classToProxy, Type[] additionalInterfacesToProxy, object target, - params IInterceptor[] interceptors) - { - return CreateClassProxyWithTarget(classToProxy, - additionalInterfacesToProxy, - target, - ProxyGenerationOptions.Default, - new object[0], - interceptors); - } - - /// - /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . - /// - /// Type of class which will be proxied. - /// The target object, calls to which will be intercepted. - /// The proxy generation options used to influence generated proxy type and object. - /// Arguments of constructor of type which should be used to create a new instance of that type. - /// The interceptors called during the invocation of proxied methods. - /// - /// New object of type proxying calls to virtual members of type. - /// - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given is a generic type definition. - /// Thrown when given is not a class type. - /// Thrown when no constructor exists on type with parameters matching . - /// Thrown when constructor of type throws an exception. - /// - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - public object CreateClassProxyWithTarget(Type classToProxy, object target, ProxyGenerationOptions options, - object[] constructorArguments, params IInterceptor[] interceptors) - { - return CreateClassProxyWithTarget(classToProxy, - Type.EmptyTypes, - target, - options, - constructorArguments, - interceptors); - } - - /// - /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . - /// - /// Type of class which will be proxied. - /// The target object, calls to which will be intercepted. - /// Arguments of constructor of type which should be used to create a new instance of that type. - /// The interceptors called during the invocation of proxied methods. - /// - /// New object of type proxying calls to virtual members of type. - /// - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given is a generic type definition. - /// Thrown when given is not a class type. - /// Thrown when no constructor exists on type with parameters matching . - /// Thrown when constructor of type throws an exception. - /// - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - public object CreateClassProxyWithTarget(Type classToProxy, object target, object[] constructorArguments, - params IInterceptor[] interceptors) - { - return CreateClassProxyWithTarget(classToProxy, - Type.EmptyTypes, - target, - ProxyGenerationOptions.Default, - constructorArguments, - interceptors); - } - - /// - /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . - /// - /// Type of class which will be proxied. - /// The target object, calls to which will be intercepted. - /// The interceptors called during the invocation of proxied methods. - /// - /// New object of type proxying calls to virtual members of type. - /// - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given is a generic type definition. - /// Thrown when given is not a class type. - /// Thrown when no parameterless constructor exists on type . - /// Thrown when constructor of type throws an exception. - /// - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - public object CreateClassProxyWithTarget(Type classToProxy, object target, params IInterceptor[] interceptors) - { - return CreateClassProxyWithTarget(classToProxy, - Type.EmptyTypes, - target, - ProxyGenerationOptions.Default, - new object[0], - interceptors); - } - - /// - /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . - /// - /// Type of class which will be proxied. - /// The target object, calls to which will be intercepted. - /// The proxy generation options used to influence generated proxy type and object. - /// The interceptors called during the invocation of proxied methods. - /// - /// New object of type proxying calls to virtual members of type. - /// - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given is a generic type definition. - /// Thrown when given is not a class type. - /// Thrown when no default constructor exists on type . - /// Thrown when default constructor of type throws an exception. - /// - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - public object CreateClassProxyWithTarget(Type classToProxy, object target, ProxyGenerationOptions options, - params IInterceptor[] interceptors) - { - return CreateClassProxyWithTarget(classToProxy, - Type.EmptyTypes, - target, - options, - new object[0], - interceptors); - } - - /// - /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . - /// - /// Type of class which will be proxied. - /// Additional interface types. Calls to their members will be proxied as well. - /// The target object, calls to which will be intercepted. - /// The proxy generation options used to influence generated proxy type and object. - /// The interceptors called during the invocation of proxied methods. - /// - /// New object of type proxying calls to virtual members of and types. - /// - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given or any of is a generic type definition. - /// Thrown when given is not a class type. - /// Thrown when no default constructor exists on type . - /// Thrown when default constructor of type throws an exception. - /// - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - public object CreateClassProxyWithTarget(Type classToProxy, Type[] additionalInterfacesToProxy, object target, - ProxyGenerationOptions options, params IInterceptor[] interceptors) - { - return CreateClassProxyWithTarget(classToProxy, - additionalInterfacesToProxy, - target, - options, - new object[0], - interceptors); - } - - /// - /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . - /// - /// Type of class which will be proxied. - /// Additional interface types. Calls to their members will be proxied as well. - /// The target object, calls to which will be intercepted. - /// The proxy generation options used to influence generated proxy type and object. - /// Arguments of constructor of type which should be used to create a new instance of that type. - /// The interceptors called during the invocation of proxied methods. - /// - /// New object of type proxying calls to virtual members of and types. - /// - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given or any of is a generic type definition. - /// Thrown when given is not a class type. - /// Thrown when no constructor exists on type with parameters matching . - /// Thrown when constructor of type throws an exception. - /// - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - public virtual object CreateClassProxyWithTarget(Type classToProxy, Type[] additionalInterfacesToProxy, object target, - ProxyGenerationOptions options, object[] constructorArguments, - params IInterceptor[] interceptors) - { - if (classToProxy == null) - { - throw new ArgumentNullException(nameof(classToProxy)); - } - if (options == null) - { - throw new ArgumentNullException(nameof(options)); - } - if (!classToProxy.IsClass) - { - throw new ArgumentException("'classToProxy' must be a class", nameof(classToProxy)); - } - - CheckNotGenericTypeDefinition(classToProxy, nameof(classToProxy)); - CheckNotGenericTypeDefinitions(additionalInterfacesToProxy, nameof(additionalInterfacesToProxy)); - - var proxyType = CreateClassProxyTypeWithTarget(classToProxy, additionalInterfacesToProxy, options); - - // create constructor arguments (initialized with mixin implementations, interceptors and target type constructor arguments) - var arguments = BuildArgumentListForClassProxyWithTarget(target, options, interceptors); - if (constructorArguments != null && constructorArguments.Length != 0) - { - arguments.AddRange(constructorArguments); - } - return CreateClassProxyInstance(proxyType, arguments, classToProxy, constructorArguments); - } - - /// - /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . - /// - /// Type of class which will be proxied. - /// The interceptors called during the invocation of proxied methods. - /// - /// New object of type proxying calls to virtual members of type. - /// - /// Thrown when given is not a class type. - /// Thrown when no default constructor exists on type . - /// Thrown when default constructor of type throws an exception. - /// - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - public TClass CreateClassProxy(params IInterceptor[] interceptors) where TClass : class - { - return (TClass)CreateClassProxy(typeof(TClass), ProxyGenerationOptions.Default, interceptors); - } - - /// - /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . - /// - /// Type of class which will be proxied. - /// The proxy generation options used to influence generated proxy type and object. - /// The interceptors called during the invocation of proxied methods. - /// - /// New object of type proxying calls to virtual members of type. - /// - /// Thrown when given is not a class type. - /// Thrown when no default constructor exists on type . - /// Thrown when default constructor of type throws an exception. - /// - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - public TClass CreateClassProxy(ProxyGenerationOptions options, params IInterceptor[] interceptors) - where TClass : class - { - return (TClass)CreateClassProxy(typeof(TClass), options, interceptors); - } - - /// - /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . - /// - /// Type of class which will be proxied. - /// Additional interface types. Calls to their members will be proxied as well. - /// The interceptors called during the invocation of proxied methods. - /// - /// New object of type proxying calls to virtual members of and types. - /// - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given or any of is a generic type definition. - /// Thrown when given is not a class type. - /// Thrown when no default constructor exists on type . - /// Thrown when default constructor of type throws an exception. - /// - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - public object CreateClassProxy(Type classToProxy, Type[] additionalInterfacesToProxy, - params IInterceptor[] interceptors) - { - return CreateClassProxy(classToProxy, additionalInterfacesToProxy, ProxyGenerationOptions.Default, interceptors); - } - - /// - /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . - /// - /// Type of class which will be proxied. - /// The proxy generation options used to influence generated proxy type and object. - /// Arguments of constructor of type which should be used to create a new instance of that type. - /// The interceptors called during the invocation of proxied methods. - /// - /// New object of type proxying calls to virtual members of type. - /// - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given is a generic type definition. - /// Thrown when given is not a class type. - /// Thrown when no constructor exists on type with parameters matching . - /// Thrown when constructor of type throws an exception. - /// - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - public object CreateClassProxy(Type classToProxy, ProxyGenerationOptions options, object[] constructorArguments, - params IInterceptor[] interceptors) - { - return CreateClassProxy(classToProxy, null, options, constructorArguments, interceptors); - } - - /// - /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . - /// - /// Type of class which will be proxied. - /// Arguments of constructor of type which should be used to create a new instance of that type. - /// The interceptors called during the invocation of proxied methods. - /// - /// New object of type proxying calls to virtual members of type. - /// - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given is a generic type definition. - /// Thrown when given is not a class type. - /// Thrown when no constructor exists on type with parameters matching . - /// Thrown when constructor of type throws an exception. - /// - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - public object CreateClassProxy(Type classToProxy, object[] constructorArguments, params IInterceptor[] interceptors) - { - return CreateClassProxy(classToProxy, null, ProxyGenerationOptions.Default, constructorArguments, interceptors); - } - - /// - /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . - /// - /// Type of class which will be proxied. - /// The interceptors called during the invocation of proxied methods. - /// - /// New object of type proxying calls to virtual members of type. - /// - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given is a generic type definition. - /// Thrown when given is not a class type. - /// Thrown when no parameterless constructor exists on type . - /// Thrown when constructor of type throws an exception. - /// - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - public object CreateClassProxy(Type classToProxy, params IInterceptor[] interceptors) - { - return CreateClassProxy(classToProxy, null, ProxyGenerationOptions.Default, - null, interceptors); - } - - /// - /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . - /// - /// Type of class which will be proxied. - /// The proxy generation options used to influence generated proxy type and object. - /// The interceptors called during the invocation of proxied methods. - /// - /// New object of type proxying calls to virtual members of type. - /// - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given is a generic type definition. - /// Thrown when given is not a class type. - /// Thrown when no default constructor exists on type . - /// Thrown when default constructor of type throws an exception. - /// - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - public object CreateClassProxy(Type classToProxy, ProxyGenerationOptions options, params IInterceptor[] interceptors) - { - return CreateClassProxy(classToProxy, null, options, interceptors); - } - - /// - /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . - /// - /// Type of class which will be proxied. - /// Additional interface types. Calls to their members will be proxied as well. - /// The proxy generation options used to influence generated proxy type and object. - /// The interceptors called during the invocation of proxied methods. - /// - /// New object of type proxying calls to virtual members of and types. - /// - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given or any of is a generic type definition. - /// Thrown when given is not a class type. - /// Thrown when no default constructor exists on type . - /// Thrown when default constructor of type throws an exception. - /// - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - public object CreateClassProxy(Type classToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options, - params IInterceptor[] interceptors) - { - return CreateClassProxy(classToProxy, additionalInterfacesToProxy, options, null, interceptors); - } - - /// - /// Creates proxy object intercepting calls to virtual members of type on newly created instance of that type with given . - /// - /// Type of class which will be proxied. - /// Additional interface types. Calls to their members will be proxied as well. - /// The proxy generation options used to influence generated proxy type and object. - /// Arguments of constructor of type which should be used to create a new instance of that type. - /// The interceptors called during the invocation of proxied methods. - /// - /// New object of type proxying calls to virtual members of and types. - /// - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given object is a null reference (Nothing in Visual Basic). - /// Thrown when given or any of is a generic type definition. - /// Thrown when given is not a class type. - /// Thrown when no constructor exists on type with parameters matching . - /// Thrown when constructor of type throws an exception. - /// - /// This method uses implementation to generate a proxy type. - /// As such caller should expect any type of exception that given implementation may throw. - /// - public virtual object CreateClassProxy(Type classToProxy, Type[] additionalInterfacesToProxy, - ProxyGenerationOptions options, - object[] constructorArguments, params IInterceptor[] interceptors) - { - if (classToProxy == null) - { - throw new ArgumentNullException(nameof(classToProxy)); - } - if (options == null) - { - throw new ArgumentNullException(nameof(options)); - } - if (!classToProxy.IsClass) - { - throw new ArgumentException("'classToProxy' must be a class", nameof(classToProxy)); - } - - CheckNotGenericTypeDefinition(classToProxy, nameof(classToProxy)); - CheckNotGenericTypeDefinitions(additionalInterfacesToProxy, nameof(additionalInterfacesToProxy)); - - var proxyType = CreateClassProxyType(classToProxy, additionalInterfacesToProxy, options); - - // create constructor arguments (initialized with mixin implementations, interceptors and target type constructor arguments) - var arguments = BuildArgumentListForClassProxy(options, interceptors); - if (constructorArguments != null && constructorArguments.Length != 0) - { - arguments.AddRange(constructorArguments); - } - return CreateClassProxyInstance(proxyType, arguments, classToProxy, constructorArguments); - } - - protected object CreateClassProxyInstance(Type proxyType, List proxyArguments, Type classToProxy, - object[] constructorArguments) - { - try - { - return Activator.CreateInstance(proxyType, proxyArguments.ToArray()); - } - catch (MissingMethodException ex) - { - var message = new StringBuilder(); - message.AppendFormat("Can not instantiate proxy of class: {0}.", classToProxy.FullName); - message.AppendLine(); - if (constructorArguments == null || constructorArguments.Length == 0) - { - message.Append("Could not find a parameterless constructor."); - } - else - { - message.AppendLine("Could not find a constructor that would match given arguments:"); - foreach (var argument in constructorArguments) - { - var argumentText = argument == null ? "" : argument.GetType().ToString(); - message.AppendLine(argumentText); - } - } - - throw new ArgumentException(message.ToString(), nameof(constructorArguments), ex); - } - } - - protected void CheckNotGenericTypeDefinition(Type type, string argumentName) - { - if (type != null && type.IsGenericTypeDefinition) - { - throw new ArgumentException( - $"Can not create proxy for type {type.GetBestName()} because it is an open generic type.", - argumentName); - } - } - - protected void CheckNotGenericTypeDefinitions(IEnumerable types, string argumentName) - { - if (types == null) - { - return; - } - foreach (var t in types) - { - CheckNotGenericTypeDefinition(t, argumentName); - } - } - - protected List BuildArgumentListForClassProxyWithTarget(object target, ProxyGenerationOptions options, - IInterceptor[] interceptors) - { - var arguments = new List(); - arguments.Add(target); - arguments.AddRange(options.MixinData.Mixins); - arguments.Add(interceptors); - if (options.Selector != null) - { - arguments.Add(options.Selector); - } - return arguments; - } - - protected List BuildArgumentListForClassProxy(ProxyGenerationOptions options, IInterceptor[] interceptors) - { - var arguments = new List(options.MixinData.Mixins) { interceptors }; - if (options.Selector != null) - { - arguments.Add(options.Selector); - } - return arguments; - } - - /// - /// Creates the proxy type for class proxy with given class, implementing given and using provided . - /// - /// The base class for proxy type. - /// The interfaces that proxy type should implement. - /// The options for proxy generation process. - /// of proxy. - protected Type CreateClassProxyType(Type classToProxy, Type[] additionalInterfacesToProxy, - ProxyGenerationOptions options) - { - // create proxy - return ProxyBuilder.CreateClassProxyType(classToProxy, additionalInterfacesToProxy, options); - } - - /// - /// Creates the proxy type for interface proxy with target for given interface, implementing given on given and using provided . - /// - /// The interface proxy type should implement. - /// The additional interfaces proxy type should implement. - /// Actual type that the proxy type will encompass. - /// The options for proxy generation process. - /// of proxy. - protected Type CreateInterfaceProxyTypeWithTarget(Type interfaceToProxy, Type[] additionalInterfacesToProxy, - Type targetType, - ProxyGenerationOptions options) - { - // create proxy - return ProxyBuilder.CreateInterfaceProxyTypeWithTarget(interfaceToProxy, additionalInterfacesToProxy, targetType, - options); - } - - /// - /// Creates the proxy type for interface proxy with target interface for given interface, implementing given on given and using provided . - /// - /// The interface proxy type should implement. - /// The additional interfaces proxy type should implement. - /// The options for proxy generation process. - /// of proxy. - protected Type CreateInterfaceProxyTypeWithTargetInterface(Type interfaceToProxy, Type[] additionalInterfacesToProxy, - ProxyGenerationOptions options) - { - // create proxy - return ProxyBuilder.CreateInterfaceProxyTypeWithTargetInterface(interfaceToProxy, additionalInterfacesToProxy, - options); - } - - /// - /// Creates the proxy type for interface proxy without target for given interface, implementing given and using provided . - /// - /// The interface proxy type should implement. - /// The additional interfaces proxy type should implement. - /// The options for proxy generation process. - /// of proxy. - protected Type CreateInterfaceProxyTypeWithoutTarget(Type interfaceToProxy, Type[] additionalInterfacesToProxy, - ProxyGenerationOptions options) - { - // create proxy - return ProxyBuilder.CreateInterfaceProxyTypeWithoutTarget(interfaceToProxy, additionalInterfacesToProxy, options); - } - - protected Type CreateClassProxyTypeWithTarget(Type classToProxy, Type[] additionalInterfacesToProxy, - ProxyGenerationOptions options) - { - // create proxy - return ProxyBuilder.CreateClassProxyTypeWithTarget(classToProxy, additionalInterfacesToProxy, options); - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/ProxyUtil.cs b/Castle.Core/DynamicProxy/ProxyUtil.cs deleted file mode 100644 index cf94e77..0000000 --- a/Castle.Core/DynamicProxy/ProxyUtil.cs +++ /dev/null @@ -1,236 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy -{ - using System; - using System.Collections.Generic; - using System.Linq; - using System.Reflection; - using System.Runtime.CompilerServices; - using System.Threading; - - using Castle.Core.Internal; - using Castle.DynamicProxy.Generators; - using Castle.DynamicProxy.Internal; - - public static class ProxyUtil - { - private static readonly SynchronizedDictionary internalsVisibleToDynamicProxy = new SynchronizedDictionary(); - - /// - /// Creates a delegate of the specified type to a suitable `Invoke` method - /// on the given instance. - /// - /// The proxy instance to which the delegate should be bound. - /// The type of delegate that should be created. - /// - /// The does not have an `Invoke` method that is compatible with - /// the requested type. - /// - public static TDelegate CreateDelegateToMixin(object proxy) - { - return (TDelegate)(object)CreateDelegateToMixin(proxy, typeof(TDelegate)); - } - - /// - /// Creates a delegate of the specified type to a suitable `Invoke` method - /// on the given instance. - /// - /// The proxy instance to which the delegate should be bound. - /// The type of delegate that should be created. - /// - /// The does not have an `Invoke` method that is compatible with - /// the requested . - /// - public static Delegate CreateDelegateToMixin(object proxy, Type delegateType) - { - if (proxy == null) throw new ArgumentNullException(nameof(proxy)); - if (delegateType == null) throw new ArgumentNullException(nameof(delegateType)); - if (!delegateType.IsDelegateType()) throw new ArgumentException("Type is not a delegate type.", nameof(delegateType)); - - var invokeMethod = delegateType.GetMethod("Invoke"); - var proxiedInvokeMethod = - proxy - .GetType() - .GetMember("Invoke", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) - .Cast() - .FirstOrDefault(m => MethodSignatureComparer.Instance.EqualParameters(m, invokeMethod)); - - if (proxiedInvokeMethod == null) - { - throw new MissingMethodException("The proxy does not have an Invoke method " + - "that is compatible with the requested delegate type."); - } - else - { - return Delegate.CreateDelegate(delegateType, proxy, proxiedInvokeMethod); - } - } - - public static object GetUnproxiedInstance(object instance) - { - if (instance is IProxyTargetAccessor accessor) - { - instance = accessor.DynProxyGetTarget(); - } - - return instance; - } - - public static Type GetUnproxiedType(object instance) - { - if (instance is IProxyTargetAccessor accessor) - { - var target = accessor.DynProxyGetTarget(); - if (target != null) - { - if (ReferenceEquals(target, instance)) - { - return instance.GetType().BaseType; - } - - instance = target; - } - } - - return instance.GetType(); - } - - public static bool IsProxy(object instance) - { - return instance is IProxyTargetAccessor; - } - - public static bool IsProxyType(Type type) - { - return typeof(IProxyTargetAccessor).IsAssignableFrom(type); - } - - /// - /// Checks whether the specified method is accessible to DynamicProxy. - /// The method to check. - /// true if the method is accessible to DynamicProxy, false otherwise. - public static bool IsAccessible(MethodBase method) - { - return IsAccessibleMethod(method) && IsAccessibleType(method.DeclaringType); - } - - /// - /// Checks whether the specified method is accessible to DynamicProxy. - /// The method to check. - /// If the method is accessible to DynamicProxy, null; otherwise, an explanation of why the method is not accessible. - /// true if the method is accessible to DynamicProxy, false otherwise. - public static bool IsAccessible(MethodBase method, out string message) - { - if (IsAccessible(method)) - { - message = null; - return true; - } - - message = CreateMessageForInaccessibleMethod(method); - return false; - } - - /// - /// Checks whether the specified type is accessible to DynamicProxy. - /// The type to check. - /// true if the type is accessible to DynamicProxy, false otherwise. - public static bool IsAccessible(Type type) - { - return IsAccessibleType(type); - } - - /// - /// Determines whether this assembly has internals visible to DynamicProxy. - /// - /// The assembly to inspect. - internal static bool AreInternalsVisibleToDynamicProxy(Assembly asm) - { - return internalsVisibleToDynamicProxy.GetOrAdd(asm, a => - { - var internalsVisibleTo = asm.GetCustomAttributes(); - return internalsVisibleTo.Any(attr => attr.AssemblyName.Contains(ModuleScope.DEFAULT_ASSEMBLY_NAME)); - }); - } - - internal static bool IsAccessibleType(Type target) - { - var isPublic = target.IsPublic || target.IsNestedPublic; - if (isPublic) - { - return true; - } - - var isTargetNested = target.IsNested; - var isNestedAndInternal = isTargetNested && (target.IsNestedAssembly || target.IsNestedFamORAssem); - var isInternalNotNested = target.IsVisible == false && isTargetNested == false; - var isInternal = isInternalNotNested || isNestedAndInternal; - if (isInternal && AreInternalsVisibleToDynamicProxy(target.Assembly)) - { - return true; - } - - return false; - } - - /// - /// Checks whether the specified method is accessible to DynamicProxy. - /// Unlike with , the declaring type's accessibility is ignored. - /// - /// The method to check. - /// true if the method is accessible to DynamicProxy, false otherwise. - internal static bool IsAccessibleMethod(MethodBase method) - { - if (method.IsPublic || method.IsFamily || method.IsFamilyOrAssembly) - { - return true; - } - - if (method.IsAssembly || method.IsFamilyAndAssembly) - { - return AreInternalsVisibleToDynamicProxy(method.DeclaringType.Assembly); - } - - return false; - } - - /// - /// Determines whether the specified method is internal. - /// - /// The method. - /// - /// true if the specified method is internal; otherwise, false. - /// - internal static bool IsInternal(MethodBase method) - { - return method.IsAssembly || (method.IsFamilyAndAssembly && !method.IsFamilyOrAssembly); - } - - private static string CreateMessageForInaccessibleMethod(MethodBase inaccessibleMethod) - { - var containingType = inaccessibleMethod.DeclaringType; - var targetAssembly = containingType.Assembly; - - var messageFormat = "Can not create proxy for method {0} because it or its declaring type is not accessible. "; - - var message = string.Format(messageFormat, - inaccessibleMethod); - - var instructions = ExceptionMessageBuilder.CreateInstructionsToMakeVisible(targetAssembly); - return message + instructions; - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Serialization/CacheMappingsAttribute.cs b/Castle.Core/DynamicProxy/Serialization/CacheMappingsAttribute.cs deleted file mode 100644 index c9c5a31..0000000 --- a/Castle.Core/DynamicProxy/Serialization/CacheMappingsAttribute.cs +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#if FEATURE_SERIALIZATION - -namespace Castle.DynamicProxy.Serialization -{ - using System; - using System.Collections.Generic; - using System.IO; - using System.Reflection; - using System.Reflection.Emit; - using System.Runtime.Serialization.Formatters.Binary; - - using Castle.DynamicProxy.Generators; - - /// - /// Applied to the assemblies saved by in order to persist the cache data included in the persisted assembly. - /// - [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = false)] - [CLSCompliant(false)] - public class CacheMappingsAttribute : Attribute - { - private static readonly ConstructorInfo constructor = - typeof(CacheMappingsAttribute).GetConstructor(new[] { typeof(byte[]) }); - - private readonly byte[] serializedCacheMappings; - - public CacheMappingsAttribute(byte[] serializedCacheMappings) - { - this.serializedCacheMappings = serializedCacheMappings; - } - - public byte[] SerializedCacheMappings - { - get { return serializedCacheMappings; } - } - - internal Dictionary GetDeserializedMappings() - { - using (var stream = new MemoryStream(SerializedCacheMappings)) - { - var formatter = new BinaryFormatter(); - return (Dictionary)formatter.Deserialize(stream); - } - } - - internal static void ApplyTo(AssemblyBuilder assemblyBuilder, Dictionary mappings) - { - using (var stream = new MemoryStream()) - { - var formatter = new BinaryFormatter(); - formatter.Serialize(stream, mappings); - var bytes = stream.ToArray(); - var attributeBuilder = new CustomAttributeBuilder(constructor, new object[] { bytes }); - assemblyBuilder.SetCustomAttribute(attributeBuilder); - } - } - } -} - -#endif \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Serialization/ProxyObjectReference.cs b/Castle.Core/DynamicProxy/Serialization/ProxyObjectReference.cs deleted file mode 100644 index 461715e..0000000 --- a/Castle.Core/DynamicProxy/Serialization/ProxyObjectReference.cs +++ /dev/null @@ -1,294 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#if FEATURE_SERIALIZATION - -namespace Castle.DynamicProxy.Serialization -{ - using System; - using System.Collections.Generic; - using System.Diagnostics; - using System.Reflection; - using System.Runtime.Serialization; - - using Castle.DynamicProxy.Generators; - using Castle.DynamicProxy.Internal; - - /// - /// Handles the deserialization of proxies. - /// - [Serializable] - public class ProxyObjectReference : IObjectReference, ISerializable, IDeserializationCallback - { - private static ModuleScope scope = new ModuleScope(); - - private readonly SerializationInfo info; - private readonly StreamingContext context; - - private readonly Type baseType; - private readonly Type[] interfaces; - private readonly object proxy; - private readonly ProxyGenerationOptions proxyGenerationOptions; - - private bool isInterfaceProxy; - private bool delegateToBase; - - /// - /// Resets the used for deserialization to a new scope. - /// - /// - /// This is useful for test cases. - /// - public static void ResetScope() - { - SetScope(new ModuleScope()); - } - - /// - /// Resets the used for deserialization to a given . - /// - /// The scope to be used for deserialization. - /// - /// By default, the deserialization process uses a different scope than the rest of the application, which can lead to multiple proxies - /// being generated for the same type. By explicitly setting the deserialization scope to the application's scope, this can be avoided. - /// - public static void SetScope(ModuleScope scope) - { - if (scope == null) - { - throw new ArgumentNullException(nameof(scope)); - } - ProxyObjectReference.scope = scope; - } - - /// - /// Gets the used for deserialization. - /// - /// As has no way of automatically determining the scope used by the application (and the application might use more than one scope at the same time), uses a dedicated scope instance for deserializing proxy types. This instance can be reset and set to a specific value via and . - public static ModuleScope ModuleScope - { - get { return scope; } - } - - protected ProxyObjectReference(SerializationInfo info, StreamingContext context) - { - this.info = info; - this.context = context; - - baseType = DeserializeTypeFromString("__baseType"); - - var _interfaceNames = (string[])info.GetValue("__interfaces", typeof(string[])); - interfaces = new Type[_interfaceNames.Length]; - - for (var i = 0; i < _interfaceNames.Length; i++) - { - interfaces[i] = Type.GetType(_interfaceNames[i]); - } - - proxyGenerationOptions = - (ProxyGenerationOptions)info.GetValue("__proxyGenerationOptions", typeof(ProxyGenerationOptions)); - proxy = RecreateProxy(); - - // We'll try to deserialize as much of the proxy state as possible here. This is just best effort; due to deserialization dependency reasons, - // we need to repeat this in OnDeserialization to guarantee correct state deserialization. - DeserializeProxyState(); - } - - private Type DeserializeTypeFromString(string key) - { - return Type.GetType(info.GetString(key), true, false); - } - - protected virtual object RecreateProxy() - { - var generatorType = GetValue("__proxyTypeId"); - if (generatorType.Equals(ProxyTypeConstants.Class)) - { - isInterfaceProxy = false; - return RecreateClassProxy(); - } - if (generatorType.Equals(ProxyTypeConstants.ClassWithTarget)) - { - isInterfaceProxy = false; - return RecreateClassProxyWithTarget(); - } - isInterfaceProxy = true; - return RecreateInterfaceProxy(generatorType); - } - - private object RecreateClassProxyWithTarget() - { - var generator = new ClassProxyWithTargetGenerator(scope, baseType, interfaces, proxyGenerationOptions); - var proxyType = generator.GetProxyType(); - return InstantiateClassProxy(proxyType); - } - - public object RecreateInterfaceProxy(string generatorType) - { - var @interface = DeserializeTypeFromString("__theInterface"); - var targetType = DeserializeTypeFromString("__targetFieldType"); - - BaseInterfaceProxyGenerator generator; - if (generatorType == ProxyTypeConstants.InterfaceWithTarget) - { - generator = new InterfaceProxyWithTargetGenerator(scope, @interface, interfaces, targetType, proxyGenerationOptions); - } - else if (generatorType == ProxyTypeConstants.InterfaceWithoutTarget) - { - generator = new InterfaceProxyWithoutTargetGenerator(scope, @interface, interfaces, targetType, proxyGenerationOptions); - } - else if (generatorType == ProxyTypeConstants.InterfaceWithTargetInterface) - { - generator = new InterfaceProxyWithTargetInterfaceGenerator(scope, @interface, interfaces, targetType, proxyGenerationOptions); - } - else - { - throw new InvalidOperationException( - string.Format( - "Got value {0} for the interface generator type, which is not known for the purpose of serialization.", - generatorType)); - } - - var proxyType = generator.GetProxyType(); - return FormatterServices.GetSafeUninitializedObject(proxyType); - } - - public object RecreateClassProxy() - { - var generator = new ClassProxyGenerator(scope, baseType, interfaces, proxyGenerationOptions); - var proxyType = generator.GetProxyType(); - return InstantiateClassProxy(proxyType); - } - - private object InstantiateClassProxy(Type proxy_type) - { - delegateToBase = GetValue("__delegateToBase"); - if (delegateToBase) - { - return Activator.CreateInstance(proxy_type, new object[] { info, context }); - } - else - { - return FormatterServices.GetSafeUninitializedObject(proxy_type); - } - } - - protected void InvokeCallback(object target) - { - if (target is IDeserializationCallback) - { - (target as IDeserializationCallback).OnDeserialization(this); - } - } - - public object GetRealObject(StreamingContext context) - { - return proxy; - } - - public void GetObjectData(SerializationInfo info, StreamingContext context) - { - // There is no need to implement this method as - // this class would never be serialized. - } - - public void OnDeserialization(object sender) - { - var interceptors = GetValue("__interceptors"); - SetInterceptors(interceptors); - - DeserializeProxyMembers(); - - // Get the proxy state again, to get all those members we couldn't get in the constructor due to deserialization ordering. - DeserializeProxyState(); - InvokeCallback(proxy); - } - - private void DeserializeProxyMembers() - { - var proxyType = proxy.GetType(); - var members = FormatterServices.GetSerializableMembers(proxyType); - - var deserializedMembers = new List(); - var deserializedValues = new List(); - for (var i = 0; i < members.Length; i++) - { - var member = members[i] as FieldInfo; - // we get some inherited members... - if (member.DeclaringType != proxyType) - { - continue; - } - - Debug.Assert(member != null); - var value = info.GetValue(member.Name, member.FieldType); - deserializedMembers.Add(member); - deserializedValues.Add(value); - } - FormatterServices.PopulateObjectMembers(proxy, deserializedMembers.ToArray(), deserializedValues.ToArray()); - } - - private void DeserializeProxyState() - { - if (isInterfaceProxy) - { - var target = GetValue("__target"); - SetTarget(target); - } - else if (!delegateToBase) - { - var baseMemberData = GetValue("__data"); - var members = FormatterServices.GetSerializableMembers(baseType); - - // Sort to keep order on both serialize and deserialize side the same, c.f DYNPROXY-ISSUE-127 - members = TypeUtil.Sort(members); - - FormatterServices.PopulateObjectMembers(proxy, members, baseMemberData); - } - } - - private void SetTarget(object target) - { - var targetField = proxy.GetType().GetField("__target", BindingFlags.Instance | BindingFlags.NonPublic); - if (targetField == null) - { - throw new SerializationException( - "The SerializationInfo specifies an invalid interface proxy type, which has no __target field."); - } - - targetField.SetValue(proxy, target); - } - - private void SetInterceptors(IInterceptor[] interceptors) - { - var interceptorField = proxy.GetType().GetField("__interceptors", BindingFlags.Instance | BindingFlags.NonPublic); - if (interceptorField == null) - { - throw new SerializationException( - "The SerializationInfo specifies an invalid proxy type, which has no __interceptors field."); - } - - interceptorField.SetValue(proxy, interceptors); - } - - private T GetValue(string name) - { - return (T)info.GetValue(name, typeof(T)); - } - } -} - -#endif \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Serialization/ProxyTypeConstants.cs b/Castle.Core/DynamicProxy/Serialization/ProxyTypeConstants.cs deleted file mode 100644 index c4e055a..0000000 --- a/Castle.Core/DynamicProxy/Serialization/ProxyTypeConstants.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Serialization -{ - internal static class ProxyTypeConstants - { - public static readonly string Class = "class"; - public static readonly string ClassWithTarget = "class.with.target"; - public static readonly string InterfaceWithTarget = "interface.with.target"; - public static readonly string InterfaceWithTargetInterface = "interface.with.target.interface"; - public static readonly string InterfaceWithoutTarget = "interface.without.target"; - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/StandardInterceptor.cs b/Castle.Core/DynamicProxy/StandardInterceptor.cs deleted file mode 100644 index 05163c1..0000000 --- a/Castle.Core/DynamicProxy/StandardInterceptor.cs +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy -{ - using System; - -#if FEATURE_SERIALIZATION - [Serializable] -#endif - public class StandardInterceptor : IInterceptor - { - public void Intercept(IInvocation invocation) - { - PreProceed(invocation); - PerformProceed(invocation); - PostProceed(invocation); - } - - protected virtual void PerformProceed(IInvocation invocation) - { - invocation.Proceed(); - } - - protected virtual void PreProceed(IInvocation invocation) - { - } - - protected virtual void PostProceed(IInvocation invocation) - { - } - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Tokens/DelegateMethods.cs b/Castle.Core/DynamicProxy/Tokens/DelegateMethods.cs deleted file mode 100644 index e0886d3..0000000 --- a/Castle.Core/DynamicProxy/Tokens/DelegateMethods.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Tokens -{ - using System; - using System.Reflection; - - internal static class DelegateMethods - { - public static readonly MethodInfo CreateDelegate = - typeof(Delegate).GetMethod("CreateDelegate", new[] { typeof(Type), typeof(object), typeof(MethodInfo) }); - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Tokens/FormatterServicesMethods.cs b/Castle.Core/DynamicProxy/Tokens/FormatterServicesMethods.cs deleted file mode 100644 index 0754821..0000000 --- a/Castle.Core/DynamicProxy/Tokens/FormatterServicesMethods.cs +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#if FEATURE_SERIALIZATION - -namespace Castle.DynamicProxy.Tokens -{ - using System; - using System.Reflection; - using System.Runtime.Serialization; - - internal static class FormatterServicesMethods - { - public static readonly MethodInfo GetObjectData = - typeof(FormatterServices).GetMethod("GetObjectData", new[] { typeof(object), typeof(MemberInfo[]) }); - - public static readonly MethodInfo GetSerializableMembers = - typeof(FormatterServices).GetMethod("GetSerializableMembers", new[] { typeof(Type) }); - } -} - -#endif \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Tokens/InterceptorSelectorMethods.cs b/Castle.Core/DynamicProxy/Tokens/InterceptorSelectorMethods.cs deleted file mode 100644 index 9f74b0a..0000000 --- a/Castle.Core/DynamicProxy/Tokens/InterceptorSelectorMethods.cs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Tokens -{ - using System.Reflection; - - internal static class InterceptorSelectorMethods - { - public static readonly MethodInfo SelectInterceptors = typeof(IInterceptorSelector).GetMethod("SelectInterceptors", BindingFlags.Instance | BindingFlags.Public); - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Tokens/InvocationMethods.cs b/Castle.Core/DynamicProxy/Tokens/InvocationMethods.cs deleted file mode 100644 index 52cf16e..0000000 --- a/Castle.Core/DynamicProxy/Tokens/InvocationMethods.cs +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Tokens -{ - using System; - using System.Reflection; - - using Castle.DynamicProxy.Internal; - - /// - /// Holds objects representing methods of class. - /// - internal static class InvocationMethods - { - public static readonly ConstructorInfo CompositionInvocationConstructor = - typeof(CompositionInvocation).GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, - new[] - { - typeof(object), - typeof(object), - typeof(IInterceptor[]), - typeof(MethodInfo), - typeof(object[]) - }, - null); - - public static readonly MethodInfo CompositionInvocationEnsureValidTarget = - typeof(CompositionInvocation).GetMethod("EnsureValidTarget", BindingFlags.Instance | BindingFlags.NonPublic); - - public static readonly MethodInfo GetArgumentValue = - typeof(AbstractInvocation).GetMethod("GetArgumentValue"); - - public static readonly MethodInfo GetArguments = - typeof(AbstractInvocation).GetMethod("get_Arguments"); - - public static readonly MethodInfo GetReturnValue = - typeof(AbstractInvocation).GetMethod("get_ReturnValue"); - - public static readonly ConstructorInfo InheritanceInvocationConstructor = - typeof(InheritanceInvocation).GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, - new[] - { - typeof(Type), - typeof(object), - typeof(IInterceptor[]), - typeof(MethodInfo), - typeof(object[]) - }, - null); - - public static readonly ConstructorInfo InheritanceInvocationConstructorWithSelector = - typeof(InheritanceInvocation).GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, - new[] - { - typeof(Type), - typeof(object), - typeof(IInterceptor[]), - typeof(MethodInfo), - typeof(object[]), - typeof(IInterceptorSelector), - typeof(IInterceptor[]).MakeByRefType() - }, - null); - - public static readonly MethodInfo Proceed = - typeof(AbstractInvocation).GetMethod("Proceed", BindingFlags.Instance | BindingFlags.Public); - - public static readonly FieldInfo ProxyObject = - typeof(AbstractInvocation).GetField("proxyObject", BindingFlags.Instance | BindingFlags.NonPublic); - - public static readonly MethodInfo SetArgumentValue = - typeof(AbstractInvocation).GetMethod("SetArgumentValue"); - - public static readonly MethodInfo SetGenericMethodArguments = - typeof(AbstractInvocation).GetMethod("SetGenericMethodArguments", new[] { typeof(Type[]) }); - - public static readonly MethodInfo SetReturnValue = - typeof(AbstractInvocation).GetMethod("set_ReturnValue"); - - public static readonly FieldInfo CompositionInvocationTarget = - typeof(CompositionInvocation).GetField("target", BindingFlags.Instance | BindingFlags.NonPublic); - - public static readonly MethodInfo ThrowOnNoTarget = - typeof(AbstractInvocation).GetMethod("ThrowOnNoTarget", BindingFlags.Instance | BindingFlags.NonPublic); - - // The following two fields are not used internally, but kept for back-compatibility - // because we renamed the public fields `EnsureValidTarget` and `Target`: - public static readonly MethodInfo EnsureValidTarget = CompositionInvocationEnsureValidTarget; - public static readonly FieldInfo Target = CompositionInvocationTarget; - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Tokens/MethodBaseMethods.cs b/Castle.Core/DynamicProxy/Tokens/MethodBaseMethods.cs deleted file mode 100644 index 7df1821..0000000 --- a/Castle.Core/DynamicProxy/Tokens/MethodBaseMethods.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Tokens -{ - using System; - using System.Reflection; - - internal static class MethodBaseMethods - { - public static readonly MethodInfo GetMethodFromHandle = - typeof(MethodBase).GetMethod("GetMethodFromHandle", new[] { typeof(RuntimeMethodHandle), typeof(RuntimeTypeHandle) }); - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Tokens/SerializationInfoMethods.cs b/Castle.Core/DynamicProxy/Tokens/SerializationInfoMethods.cs deleted file mode 100644 index 7a22bda..0000000 --- a/Castle.Core/DynamicProxy/Tokens/SerializationInfoMethods.cs +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#if FEATURE_SERIALIZATION - -namespace Castle.DynamicProxy.Tokens -{ - using System; - using System.Reflection; - using System.Runtime.Serialization; - - /// - /// Holds objects representing methods of class. - /// - internal static class SerializationInfoMethods - { - /// - /// - /// - public static readonly MethodInfo AddValue_Bool = - typeof(SerializationInfo).GetMethod("AddValue", new[] { typeof(string), typeof(bool) }); - - /// - /// - /// - public static readonly MethodInfo AddValue_Int32 = - typeof(SerializationInfo).GetMethod("AddValue", new[] { typeof(string), typeof(int) }); - - /// - /// - /// - public static readonly MethodInfo AddValue_Object = - typeof(SerializationInfo).GetMethod("AddValue", new[] { typeof(string), typeof(object) }); - - /// - /// - /// - public static readonly MethodInfo GetValue = - typeof(SerializationInfo).GetMethod("GetValue", new[] { typeof(string), typeof(Type) }); - - /// - /// - /// - public static readonly MethodInfo SetType = - typeof(SerializationInfo).GetMethod("SetType"); - } -} - -#endif \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Tokens/TypeMethods.cs b/Castle.Core/DynamicProxy/Tokens/TypeMethods.cs deleted file mode 100644 index 0ac5fb0..0000000 --- a/Castle.Core/DynamicProxy/Tokens/TypeMethods.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Tokens -{ - using System; - using System.Reflection; - - internal static class TypeMethods - { - public static readonly MethodInfo GetTypeFromHandle = typeof(Type).GetMethod("GetTypeFromHandle"); - - public static readonly MethodInfo StaticGetType = typeof(Type).GetMethod("GetType", new[] { typeof(string), typeof(bool), typeof(bool) }); - } -} \ No newline at end of file diff --git a/Castle.Core/DynamicProxy/Tokens/TypeUtilMethods.cs b/Castle.Core/DynamicProxy/Tokens/TypeUtilMethods.cs deleted file mode 100644 index 3e89f83..0000000 --- a/Castle.Core/DynamicProxy/Tokens/TypeUtilMethods.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.DynamicProxy.Tokens -{ - using System.Reflection; - - using Castle.DynamicProxy.Internal; - - internal static class TypeUtilMethods - { - public static readonly MethodInfo Sort = typeof(TypeUtil).GetMethod("Sort", BindingFlags.Public | BindingFlags.Static); - public static readonly MethodInfo GetTypeOrNull = typeof(TypeUtil).GetMethod("GetTypeOrNull", BindingFlags.Public | BindingFlags.Static); - } -} \ No newline at end of file diff --git a/Castle.Core/Properties/InternalsVisibleToTests.cs b/Castle.Core/Properties/InternalsVisibleToTests.cs deleted file mode 100644 index d70d590..0000000 --- a/Castle.Core/Properties/InternalsVisibleToTests.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -using System.Runtime.CompilerServices; - -[assembly: InternalsVisibleTo("Castle.Core.Tests, PublicKey=002400000480000094000000060200000024000052534131000400000100010077f5e87030dadccce6902c6adab7a987bd69cb5819991531f560785eacfc89b6fcddf6bb2a00743a7194e454c0273447fc6eec36474ba8e5a3823147d214298e4f9a631b1afee1a51ffeae4672d498f14b000e3d321453cdd8ac064de7e1cf4d222b7e81f54d4fd46725370d702a05b48738cc29d09228f1aa722ae1a9ca02fb")] diff --git a/SimpleProxy.sln b/SimpleProxy.sln index 2ea4d5c..8f54b0e 100644 --- a/SimpleProxy.sln +++ b/SimpleProxy.sln @@ -7,12 +7,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimpleProxy", "SimpleProxy\ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Core", "Core", "{4A4DE7A9-6C40-4F7F-9E49-0090BAA9B1E1}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CastleCore", "CastleCore", "{FC20E617-CC98-4E90-A382-8A417A8F4A4A}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Castle.Core", "Castle.Core\Castle.Core.csproj", "{41621639-2171-41BE-A1E3-E27C77DE8C61}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Castle.Core.AsyncInterceptor", "Castle.Core.AsyncInterceptor\Castle.Core.AsyncInterceptor.csproj", "{75792845-FF7F-454B-B826-79DBB4D40B4C}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -23,22 +17,12 @@ Global {076C09AD-12A5-4CE0-BE41-B461606FED62}.Debug|Any CPU.Build.0 = Debug|Any CPU {076C09AD-12A5-4CE0-BE41-B461606FED62}.Release|Any CPU.ActiveCfg = Release|Any CPU {076C09AD-12A5-4CE0-BE41-B461606FED62}.Release|Any CPU.Build.0 = Release|Any CPU - {41621639-2171-41BE-A1E3-E27C77DE8C61}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {41621639-2171-41BE-A1E3-E27C77DE8C61}.Debug|Any CPU.Build.0 = Debug|Any CPU - {41621639-2171-41BE-A1E3-E27C77DE8C61}.Release|Any CPU.ActiveCfg = Release|Any CPU - {41621639-2171-41BE-A1E3-E27C77DE8C61}.Release|Any CPU.Build.0 = Release|Any CPU - {75792845-FF7F-454B-B826-79DBB4D40B4C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {75792845-FF7F-454B-B826-79DBB4D40B4C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {75792845-FF7F-454B-B826-79DBB4D40B4C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {75792845-FF7F-454B-B826-79DBB4D40B4C}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution {076C09AD-12A5-4CE0-BE41-B461606FED62} = {4A4DE7A9-6C40-4F7F-9E49-0090BAA9B1E1} - {41621639-2171-41BE-A1E3-E27C77DE8C61} = {FC20E617-CC98-4E90-A382-8A417A8F4A4A} - {75792845-FF7F-454B-B826-79DBB4D40B4C} = {FC20E617-CC98-4E90-A382-8A417A8F4A4A} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {8F627740-E1C8-4756-8BA6-39E4135E9350}