Imported Upstream version 5.0.0.42

Former-commit-id: fd56571888259555122d8a0f58c68838229cea2b
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2017-04-10 11:41:01 +00:00
parent 1190d13a04
commit 6bdd276d05
19939 changed files with 3099680 additions and 93811 deletions

View File

@@ -0,0 +1,47 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.22609.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Reflection.DispatchProxy.Tests", "tests\System.Reflection.DispatchProxy.Tests.csproj", "{089444FE-8FF5-4D8F-A51B-32D026425F6B}"
ProjectSection(ProjectDependencies) = postProject
{1E689C1B-690C-4799-BDE9-6E7990585894} = {1E689C1B-690C-4799-BDE9-6E7990585894}
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Reflection.DispatchProxy", "src\System.Reflection.DispatchProxy.csproj", "{1E689C1B-690C-4799-BDE9-6E7990585894}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{20F85A9C-FC0B-4220-B11F-38205E6F67F8}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
DebugNETCoreAppnetcore50aot-Windows_NTnetstandard1.3|AnyCPU = DebugNETCoreAppnetcore50aot-Windows_NTnetstandard1.3|AnyCPU
ReleaseNETCoreAppnetcore50aot-Windows_NTnetstandard1.3|AnyCPU = ReleaseNETCoreAppnetcore50aot-Windows_NTnetstandard1.3|AnyCPU
DebugNETCoreAppnetstandard1.3netstandard1.3|AnyCPU = DebugNETCoreAppnetstandard1.3netstandard1.3|AnyCPU
ReleaseNETCoreAppnetstandard1.3netstandard1.3|AnyCPU = ReleaseNETCoreAppnetstandard1.3netstandard1.3|AnyCPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{089444FE-8FF5-4D8F-A51B-32D026425F6B}.DebugNETCoreAppnetcore50aot-Windows_NTnetstandard1.3|AnyCPU.ActiveCfg = netstandard1.3-Debug|Any CPU
{089444FE-8FF5-4D8F-A51B-32D026425F6B}.DebugNETCoreAppnetcore50aot-Windows_NTnetstandard1.3|AnyCPU.Build.0 = netstandard1.3-Debug|Any CPU
{089444FE-8FF5-4D8F-A51B-32D026425F6B}.ReleaseNETCoreAppnetcore50aot-Windows_NTnetstandard1.3|AnyCPU.ActiveCfg = netstandard1.3-Release|Any CPU
{089444FE-8FF5-4D8F-A51B-32D026425F6B}.ReleaseNETCoreAppnetcore50aot-Windows_NTnetstandard1.3|AnyCPU.Build.0 = netstandard1.3-Release|Any CPU
{089444FE-8FF5-4D8F-A51B-32D026425F6B}.DebugNETCoreAppnetstandard1.3netstandard1.3|AnyCPU.ActiveCfg = netstandard1.3-Debug|Any CPU
{089444FE-8FF5-4D8F-A51B-32D026425F6B}.DebugNETCoreAppnetstandard1.3netstandard1.3|AnyCPU.Build.0 = netstandard1.3-Debug|Any CPU
{089444FE-8FF5-4D8F-A51B-32D026425F6B}.ReleaseNETCoreAppnetstandard1.3netstandard1.3|AnyCPU.ActiveCfg = netstandard1.3-Release|Any CPU
{089444FE-8FF5-4D8F-A51B-32D026425F6B}.ReleaseNETCoreAppnetstandard1.3netstandard1.3|AnyCPU.Build.0 = netstandard1.3-Release|Any CPU
{1E689C1B-690C-4799-BDE9-6E7990585894}.DebugNETCoreAppnetcore50aot-Windows_NTnetstandard1.3|AnyCPU.ActiveCfg = netcore50aot-Windows_NT-Debug|Any CPU
{1E689C1B-690C-4799-BDE9-6E7990585894}.DebugNETCoreAppnetcore50aot-Windows_NTnetstandard1.3|AnyCPU.Build.0 = netcore50aot-Windows_NT-Debug|Any CPU
{1E689C1B-690C-4799-BDE9-6E7990585894}.ReleaseNETCoreAppnetcore50aot-Windows_NTnetstandard1.3|AnyCPU.ActiveCfg = netcore50aot-Windows_NT-Release|Any CPU
{1E689C1B-690C-4799-BDE9-6E7990585894}.ReleaseNETCoreAppnetcore50aot-Windows_NTnetstandard1.3|AnyCPU.Build.0 = netcore50aot-Windows_NT-Release|Any CPU
{1E689C1B-690C-4799-BDE9-6E7990585894}.DebugNETCoreAppnetstandard1.3netstandard1.3|AnyCPU.ActiveCfg = netstandard1.3-Debug|Any CPU
{1E689C1B-690C-4799-BDE9-6E7990585894}.DebugNETCoreAppnetstandard1.3netstandard1.3|AnyCPU.Build.0 = netstandard1.3-Debug|Any CPU
{1E689C1B-690C-4799-BDE9-6E7990585894}.ReleaseNETCoreAppnetstandard1.3netstandard1.3|AnyCPU.ActiveCfg = netstandard1.3-Release|Any CPU
{1E689C1B-690C-4799-BDE9-6E7990585894}.ReleaseNETCoreAppnetstandard1.3netstandard1.3|AnyCPU.Build.0 = netstandard1.3-Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{089444FE-8FF5-4D8F-A51B-32D026425F6B} = {089444FE-8FF5-4D8F-A51B-32D026425F6B}
{1E689C1B-690C-4799-BDE9-6E7990585894} = {1E689C1B-690C-4799-BDE9-6E7990585894}
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\dir.props" />
<PropertyGroup>
<AssemblyVersion>4.0.3.0</AssemblyVersion>
<IsNETCoreApp>true</IsNETCoreApp>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<ItemGroup>
<Project Include="System.Reflection.DispatchProxy.pkgproj" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.traversal.targets))\dir.traversal.targets" />
</Project>

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<ItemGroup>
<ProjectReference Include="..\ref\System.Reflection.DispatchProxy.csproj">
<SupportedFramework>net46;netcore50;netcoreapp1.0;$(AllXamarinFrameworks)</SupportedFramework>
<!-- Make sure this doesn't get stripped during harvesting.
We have an implementation that will work on desktop, thus needs a unique assembly version -->
<Preserve>true</Preserve>
</ProjectReference>
<ProjectReference Include="..\src\System.Reflection.DispatchProxy.builds" />
</ItemGroup>
<ItemGroup>
<InboxOnTargetFramework Include="MonoAndroid10" />
<InboxOnTargetFramework Include="MonoTouch10" />
<InboxOnTargetFramework Include="xamarinios10" />
<InboxOnTargetFramework Include="xamarinmac20" />
<InboxOnTargetFramework Include="xamarintvos10" />
<InboxOnTargetFramework Include="xamarinwatchos10" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<BuildConfigurations>
netstandard;
</BuildConfigurations>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,17 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
// ------------------------------------------------------------------------------
// Changes to this file must follow the http://aka.ms/api-review process.
// ------------------------------------------------------------------------------
namespace System.Reflection
{
public abstract partial class DispatchProxy
{
protected DispatchProxy() { }
public static T Create<T, TProxy>() where TProxy : System.Reflection.DispatchProxy { throw null; }
protected abstract object Invoke(System.Reflection.MethodInfo targetMethod, object[] args);
}
}

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<PropertyGroup>
<ProjectGuid>{7DF3C428-AAD6-41C7-98E6-6CACFD5C391E}</ProjectGuid>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Release|AnyCPU'" />
<ItemGroup>
<Compile Include="System.Reflection.DispatchProxy.cs" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project>

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<BuildConfigurations>
netcore50aot-Windows_NT;
netcoreapp;
uap;
</BuildConfigurations>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,132 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="BaseType_Cannot_Be_Sealed" xml:space="preserve">
<value>The base type '{0}' cannot be sealed.</value>
</data>
<data name="BaseType_Must_Have_Default_Ctor" xml:space="preserve">
<value>The base type '{0}' must have a public parameterless constructor.</value>
</data>
<data name="InterfaceType_Must_Be_Interface" xml:space="preserve">
<value>The type '{0}' must be an interface, not a class.</value>
</data>
<data name="BaseType_Cannot_Be_Abstract" xml:space="preserve">
<value>The base type '{0}' cannot be abstract.</value>
</data>
</root>

View File

@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build">
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<PropertyGroup>
<ProjectGuid>{1E689C1B-690C-4799-BDE9-6E7990585894}</ProjectGuid>
<AssemblyName>System.Reflection.DispatchProxy</AssemblyName>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<IsPartialFacadeAssembly Condition="'$(TargetGroup)' == 'netcore50aot'">true</IsPartialFacadeAssembly>
<ResourcesSourceOutputDirectory Condition="'$(TargetGroup)' == 'netcore50aot'">None</ResourcesSourceOutputDirectory>
</PropertyGroup>
<!-- Default configurations to help VS understand the configurations -->
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcore50aot-Windows_NT-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcore50aot-Windows_NT-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Release|AnyCPU'" />
<ItemGroup Condition="'$(IsPartialFacadeAssembly)' != 'true'">
<Compile Include="System\Reflection\DispatchProxy.cs" />
<Compile Include="System\Reflection\DispatchProxyGenerator.cs" />
</ItemGroup>
<ItemGroup Condition="'$(TargetGroup)' == 'netcore50aot'">
<TargetingPackReference Include="System.Private.Interop" />
</ItemGroup>
<ItemGroup Condition="'$(IsPartialFacadeAssembly)' != 'true'">
<Reference Include="System.Collections" />
<Reference Include="System.Diagnostics.Debug" />
<Reference Include="System.Linq" />
<Reference Include="System.Reflection" />
<Reference Include="System.Reflection.Emit" />
<Reference Include="System.Reflection.Emit.ILGeneration" />
<Reference Include="System.Reflection.Extensions" />
<Reference Include="System.Reflection.Primitives" />
<Reference Include="System.Resources.ResourceManager" />
<Reference Include="System.Runtime" />
<Reference Include="System.Threading" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project>

View File

@@ -0,0 +1,44 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Reflection;
namespace System.Reflection
{
/// <summary>
/// DispatchProxy provides a mechanism for the instantiation of proxy objects and handling of
/// their method dispatch.
/// </summary>
public abstract class DispatchProxy
{
protected DispatchProxy()
{
}
/// <summary>
/// Whenever any method on the generated proxy type is called, this method
/// will be invoked to dispatch control.
/// </summary>
/// <param name="targetMethod">The method the caller invoked</param>
/// <param name="args">The arguments the caller passed to the method</param>
/// <returns>The object to return to the caller, or <c>null</c> for void methods</returns>
protected abstract object Invoke(MethodInfo targetMethod, object[] args);
/// <summary>
/// Creates an object instance that derives from class <typeparamref name="TProxy"/>
/// and implements interface <typeparamref name="T"/>.
/// </summary>
/// <typeparam name="T">The interface the proxy should implement.</typeparam>
/// <typeparam name="TProxy">The base class to use for the proxy class.</typeparam>
/// <returns>An object instance that implements <typeparamref name="T"/>.</returns>
/// <exception cref="System.ArgumentException"><typeparamref name="T"/> is a class,
/// or <typeparamref name="TProxy"/> is sealed or does not have a parameterless constructor</exception>
public static T Create<T, TProxy>()
where TProxy : DispatchProxy
{
return (T)DispatchProxyGenerator.CreateProxyInstance(typeof(TProxy), typeof(T));
}
}
}

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<BuildConfigurations>
netstandard1.3;
</BuildConfigurations>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,497 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;
using Xunit;
namespace DispatchProxyTests
{
public static class DispatchProxyTests
{
[Fact]
public static void Create_Proxy_Derives_From_DispatchProxy_BaseType()
{
TestType_IHelloService proxy = DispatchProxy.Create<TestType_IHelloService, TestDispatchProxy>();
Assert.NotNull(proxy);
Assert.IsAssignableFrom<TestDispatchProxy>(proxy);
}
[Fact]
public static void Create_Proxy_Implements_All_Interfaces()
{
TestType_IHelloAndGoodbyeService proxy = DispatchProxy.Create<TestType_IHelloAndGoodbyeService, TestDispatchProxy>();
Assert.NotNull(proxy);
Type[] implementedInterfaces = typeof(TestType_IHelloAndGoodbyeService).GetTypeInfo().ImplementedInterfaces.ToArray();
foreach (Type t in implementedInterfaces)
{
Assert.IsAssignableFrom(t, proxy);
}
}
[Fact]
public static void Create_Proxy_Internal_Interface()
{
TestType_InternalInterfaceService proxy = DispatchProxy.Create<TestType_InternalInterfaceService, TestDispatchProxy>();
Assert.NotNull(proxy);
}
[Fact]
public static void Create_Proxy_Implements_Internal_Interfaces()
{
TestType_InternalInterfaceService proxy = DispatchProxy.Create<TestType_PublicInterfaceService_Implements_Internal, TestDispatchProxy>();
Assert.NotNull(proxy);
}
[Fact]
public static void Create_Same_Proxy_Type_And_Base_Type_Reuses_Same_Generated_Type()
{
TestType_IHelloService proxy1 = DispatchProxy.Create<TestType_IHelloService, TestDispatchProxy>();
TestType_IHelloService proxy2 = DispatchProxy.Create<TestType_IHelloService, TestDispatchProxy>();
Assert.NotNull(proxy1);
Assert.NotNull(proxy2);
Assert.IsType(proxy1.GetType(), proxy2);
}
[Fact]
public static void Create_Proxy_Instances_Of_Same_Proxy_And_Base_Type_Are_Unique()
{
TestType_IHelloService proxy1 = DispatchProxy.Create<TestType_IHelloService, TestDispatchProxy>();
TestType_IHelloService proxy2 = DispatchProxy.Create<TestType_IHelloService, TestDispatchProxy>();
Assert.NotNull(proxy1);
Assert.NotNull(proxy2);
Assert.False(object.ReferenceEquals(proxy1, proxy2),
String.Format("First and second instance of proxy type {0} were the same instance", proxy1.GetType().Name));
}
[Fact]
public static void Create_Same_Proxy_Type_With_Different_BaseType_Uses_Different_Generated_Type()
{
TestType_IHelloService proxy1 = DispatchProxy.Create<TestType_IHelloService, TestDispatchProxy>();
TestType_IHelloService proxy2 = DispatchProxy.Create<TestType_IHelloService, TestDispatchProxy2>();
Assert.NotNull(proxy1);
Assert.NotNull(proxy2);
Assert.False(proxy1.GetType() == proxy2.GetType(),
String.Format("Proxy generated for base type {0} used same for base type {1}", typeof(TestDispatchProxy).Name, typeof(TestDispatchProxy).Name));
}
[Fact]
public static void Created_Proxy_With_Different_Proxy_Type_Use_Different_Generated_Type()
{
TestType_IHelloService proxy1 = DispatchProxy.Create<TestType_IHelloService, TestDispatchProxy>();
TestType_IGoodbyeService proxy2 = DispatchProxy.Create<TestType_IGoodbyeService, TestDispatchProxy>();
Assert.NotNull(proxy1);
Assert.NotNull(proxy2);
Assert.False(proxy1.GetType() == proxy2.GetType(),
String.Format("Proxy generated for type {0} used same for type {1}", typeof(TestType_IHelloService).Name, typeof(TestType_IGoodbyeService).Name));
}
[Fact]
public static void Create_Using_Concrete_Proxy_Type_Throws_ArgumentException()
{
Assert.Throws<ArgumentException>("T", () => DispatchProxy.Create<TestType_ConcreteClass, TestDispatchProxy>());
}
[Fact]
public static void Create_Using_Sealed_BaseType_Throws_ArgumentException()
{
Assert.Throws<ArgumentException>("TProxy", () => DispatchProxy.Create<TestType_IHelloService, Sealed_TestDispatchProxy>());
}
[Fact]
public static void Create_Using_Abstract_BaseType_Throws_ArgumentException()
{
Assert.Throws<ArgumentException>("TProxy", () => DispatchProxy.Create<TestType_IHelloService, Abstract_TestDispatchProxy>());
}
[Fact]
public static void Create_Using_BaseType_Without_Default_Ctor_Throws_ArgumentException()
{
Assert.Throws<ArgumentException>("TProxy", () => DispatchProxy.Create<TestType_IHelloService, NoDefaultCtor_TestDispatchProxy>());
}
[Fact]
public static void Invoke_Receives_Correct_MethodInfo_And_Arguments()
{
bool wasInvoked = false;
StringBuilder errorBuilder = new StringBuilder();
// This Func is called whenever we call a method on the proxy.
// This is where we validate it received the correct arguments and methods
Func<MethodInfo, object[], object> invokeCallback = (method, args) =>
{
wasInvoked = true;
if (method == null)
{
string error = String.Format("Proxy for {0} was called with null method", typeof(TestType_IHelloService).Name);
errorBuilder.AppendLine(error);
return null;
}
else
{
MethodInfo expectedMethod = typeof(TestType_IHelloService).GetTypeInfo().GetDeclaredMethod("Hello");
if (expectedMethod != method)
{
string error = String.Format("Proxy for {0} was called with incorrect method. Expected = {1}, Actual = {2}",
typeof(TestType_IHelloService).Name, expectedMethod, method);
errorBuilder.AppendLine(error);
return null;
}
}
return "success";
};
TestType_IHelloService proxy = DispatchProxy.Create<TestType_IHelloService, TestDispatchProxy>();
Assert.NotNull(proxy);
TestDispatchProxy dispatchProxy = proxy as TestDispatchProxy;
Assert.NotNull(dispatchProxy);
// Redirect Invoke to our own Func above
dispatchProxy.CallOnInvoke = invokeCallback;
// Calling this method now will invoke the Func above which validates correct method
proxy.Hello("testInput");
Assert.True(wasInvoked, "The invoke method was not called");
Assert.True(errorBuilder.Length == 0, errorBuilder.ToString());
}
[Fact]
public static void Invoke_Receives_Correct_MethodInfo()
{
MethodInfo invokedMethod = null;
TestType_IHelloService proxy = DispatchProxy.Create<TestType_IHelloService, TestDispatchProxy>();
((TestDispatchProxy)proxy).CallOnInvoke = (method, args) =>
{
invokedMethod = method;
return String.Empty;
};
proxy.Hello("testInput");
MethodInfo expectedMethod = typeof(TestType_IHelloService).GetTypeInfo().GetDeclaredMethod("Hello");
Assert.True(invokedMethod != null && expectedMethod == invokedMethod, String.Format("Invoke expected method {0} but actual was {1}", expectedMethod, invokedMethod));
}
[Fact]
public static void Invoke_Receives_Correct_Arguments()
{
object[] actualArgs = null;
TestType_IHelloService proxy = DispatchProxy.Create<TestType_IHelloService, TestDispatchProxy>();
((TestDispatchProxy)proxy).CallOnInvoke = (method, args) =>
{
actualArgs = args;
return String.Empty;
};
proxy.Hello("testInput");
object[] expectedArgs = new object[] { "testInput" };
Assert.True(actualArgs != null && actualArgs.Length == expectedArgs.Length,
String.Format("Invoked expected object[] of length {0} but actual was {1}",
expectedArgs.Length, (actualArgs == null ? "null" : actualArgs.Length.ToString())));
for (int i = 0; i < expectedArgs.Length; ++i)
{
Assert.True(expectedArgs[i].Equals(actualArgs[i]),
String.Format("Expected arg[{0}] = '{1}' but actual was '{2}'",
i, expectedArgs[i], actualArgs[i]));
}
}
[Fact]
public static void Invoke_Returns_Correct_Value()
{
TestType_IHelloService proxy = DispatchProxy.Create<TestType_IHelloService, TestDispatchProxy>();
((TestDispatchProxy)proxy).CallOnInvoke = (method, args) =>
{
return "testReturn";
};
string expectedResult = "testReturn";
string actualResult = proxy.Hello(expectedResult);
Assert.Equal(expectedResult, actualResult);
}
[Fact]
public static void Invoke_Multiple_Parameters_Receives_Correct_Arguments()
{
object[] invokedArgs = null;
object[] expectedArgs = new object[] { (int)42, "testString", (double)5.0 };
TestType_IMultipleParameterService proxy = DispatchProxy.Create<TestType_IMultipleParameterService, TestDispatchProxy>();
((TestDispatchProxy)proxy).CallOnInvoke = (method, args) =>
{
invokedArgs = args;
return 0.0;
};
proxy.TestMethod((int)expectedArgs[0], (string)expectedArgs[1], (double)expectedArgs[2]);
Assert.True(invokedArgs != null && invokedArgs.Length == expectedArgs.Length,
String.Format("Expected {0} arguments but actual was {1}",
expectedArgs.Length, invokedArgs == null ? "null" : invokedArgs.Length.ToString()));
for (int i = 0; i < expectedArgs.Length; ++i)
{
Assert.True(expectedArgs[i].Equals(invokedArgs[i]),
String.Format("Expected arg[{0}] = '{1}' but actual was '{2}'",
i, expectedArgs[i], invokedArgs[i]));
}
}
[Fact]
public static void Invoke_Multiple_Parameters_Via_Params_Receives_Correct_Arguments()
{
object[] actualArgs = null;
object[] invokedArgs = null;
object[] expectedArgs = new object[] { 42, "testString", 5.0 };
TestType_IMultipleParameterService proxy = DispatchProxy.Create<TestType_IMultipleParameterService, TestDispatchProxy>();
((TestDispatchProxy)proxy).CallOnInvoke = (method, args) =>
{
invokedArgs = args;
return String.Empty;
};
proxy.ParamsMethod((int)expectedArgs[0], (string)expectedArgs[1], (double)expectedArgs[2]);
// All separate params should have become a single object[1] array
Assert.True(invokedArgs != null && invokedArgs.Length == 1,
String.Format("Expected single element object[] but actual was {0}",
invokedArgs == null ? "null" : invokedArgs.Length.ToString()));
// That object[1] should contain an object[3] containing the args
actualArgs = invokedArgs[0] as object[];
Assert.True(actualArgs != null && actualArgs.Length == expectedArgs.Length,
String.Format("Invoked expected object[] of length {0} but actual was {1}",
expectedArgs.Length, (actualArgs == null ? "null" : actualArgs.Length.ToString())));
for (int i = 0; i < expectedArgs.Length; ++i)
{
Assert.True(expectedArgs[i].Equals(actualArgs[i]),
String.Format("Expected arg[{0}] = '{1}' but actual was '{2}'",
i, expectedArgs[i], actualArgs[i]));
}
}
[Fact]
public static void Invoke_Void_Returning_Method_Accepts_Null_Return()
{
MethodInfo invokedMethod = null;
TestType_IOneWay proxy = DispatchProxy.Create<TestType_IOneWay, TestDispatchProxy>();
((TestDispatchProxy)proxy).CallOnInvoke = (method, args) =>
{
invokedMethod = method;
return null;
};
proxy.OneWay();
MethodInfo expectedMethod = typeof(TestType_IOneWay).GetTypeInfo().GetDeclaredMethod("OneWay");
Assert.True(invokedMethod != null && expectedMethod == invokedMethod, String.Format("Invoke expected method {0} but actual was {1}", expectedMethod, invokedMethod));
}
[Fact]
public static void Invoke_Same_Method_Multiple_Interfaces_Calls_Correct_Method()
{
List<MethodInfo> invokedMethods = new List<MethodInfo>();
TestType_IHelloService1And2 proxy = DispatchProxy.Create<TestType_IHelloService1And2, TestDispatchProxy>();
((TestDispatchProxy)proxy).CallOnInvoke = (method, args) =>
{
invokedMethods.Add(method);
return null;
};
((TestType_IHelloService)proxy).Hello("calling 1");
((TestType_IHelloService2)proxy).Hello("calling 2");
Assert.True(invokedMethods.Count == 2, String.Format("Expected 2 method invocations but received {0}", invokedMethods.Count));
MethodInfo expectedMethod = typeof(TestType_IHelloService).GetTypeInfo().GetDeclaredMethod("Hello");
Assert.True(invokedMethods[0] != null && expectedMethod == invokedMethods[0], String.Format("First invoke should have been TestType_IHelloService.Hello but actual was {0}", invokedMethods[0]));
expectedMethod = typeof(TestType_IHelloService2).GetTypeInfo().GetDeclaredMethod("Hello");
Assert.True(invokedMethods[1] != null && expectedMethod == invokedMethods[1], String.Format("Second invoke should have been TestType_IHelloService2.Hello but actual was {0}", invokedMethods[1]));
}
[Fact]
public static void Invoke_Thrown_Exception_Rethrown_To_Caller()
{
Exception actualException = null;
InvalidOperationException expectedException = new InvalidOperationException("testException");
TestType_IHelloService proxy = DispatchProxy.Create<TestType_IHelloService, TestDispatchProxy>();
((TestDispatchProxy)proxy).CallOnInvoke = (method, args) =>
{
throw expectedException;
};
try
{
proxy.Hello("testCall");
}
catch (Exception e)
{
actualException = e;
}
Assert.Equal(expectedException, actualException);
}
[Fact]
public static void Invoke_Property_Setter_And_Getter_Invokes_Correct_Methods()
{
List<MethodInfo> invokedMethods = new List<MethodInfo>();
TestType_IPropertyService proxy = DispatchProxy.Create<TestType_IPropertyService, TestDispatchProxy>();
((TestDispatchProxy)proxy).CallOnInvoke = (method, args) =>
{
invokedMethods.Add(method);
return null;
};
proxy.ReadWrite = "testValue";
string actualValue = proxy.ReadWrite;
Assert.True(invokedMethods.Count == 2, String.Format("Expected 2 method invocations but received {0}", invokedMethods.Count));
PropertyInfo propertyInfo = typeof(TestType_IPropertyService).GetTypeInfo().GetDeclaredProperty("ReadWrite");
Assert.NotNull(propertyInfo);
MethodInfo expectedMethod = propertyInfo.SetMethod;
Assert.True(invokedMethods[0] != null && expectedMethod == invokedMethods[0], String.Format("First invoke should have been {0} but actual was {1}",
expectedMethod.Name, invokedMethods[0]));
expectedMethod = propertyInfo.GetMethod;
Assert.True(invokedMethods[1] != null && expectedMethod == invokedMethods[1], String.Format("Second invoke should have been {0} but actual was {1}",
expectedMethod.Name, invokedMethods[1]));
Assert.Null(actualValue);
}
[Fact]
public static void Proxy_Declares_Interface_Properties()
{
TestType_IPropertyService proxy = DispatchProxy.Create<TestType_IPropertyService, TestDispatchProxy>();
PropertyInfo propertyInfo = proxy.GetType().GetTypeInfo().GetDeclaredProperty("ReadWrite");
Assert.NotNull(propertyInfo);
}
[Fact]
public static void Invoke_Event_Add_And_Remove_And_Raise_Invokes_Correct_Methods()
{
// C# cannot emit raise_Xxx method for the event, so we must use System.Reflection.Emit to generate such event.
AssemblyBuilder ab = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("EventBuilder"), AssemblyBuilderAccess.Run);
ModuleBuilder modb = ab.DefineDynamicModule("mod");
TypeBuilder tb = modb.DefineType("TestType_IEventService", TypeAttributes.Public | TypeAttributes.Interface | TypeAttributes.Abstract);
EventBuilder eb = tb.DefineEvent("AddRemoveRaise", EventAttributes.None, typeof(EventHandler));
eb.SetAddOnMethod(tb.DefineMethod("add_AddRemoveRaise", MethodAttributes.Public | MethodAttributes.Abstract | MethodAttributes.Virtual, typeof(void), new Type[] { typeof(EventHandler) }));
eb.SetRemoveOnMethod( tb.DefineMethod("remove_AddRemoveRaise", MethodAttributes.Public | MethodAttributes.Abstract | MethodAttributes.Virtual, typeof(void), new Type[] { typeof(EventHandler) }));
eb.SetRaiseMethod(tb.DefineMethod("raise_AddRemoveRaise", MethodAttributes.Public | MethodAttributes.Abstract | MethodAttributes.Virtual, typeof(void), new Type[] { typeof(EventArgs) }));
TypeInfo ieventServiceTypeInfo = tb.CreateTypeInfo();
List<MethodInfo> invokedMethods = new List<MethodInfo>();
object proxy =
typeof(DispatchProxy)
.GetRuntimeMethod("Create", Array.Empty<Type>()).MakeGenericMethod(ieventServiceTypeInfo.AsType(), typeof(TestDispatchProxy))
.Invoke(null, null);
((TestDispatchProxy)proxy).CallOnInvoke = (method, args) =>
{
invokedMethods.Add(method);
return null;
};
EventHandler handler = new EventHandler((sender, e) => {});
proxy.GetType().GetRuntimeMethods().Single(m => m.Name == "add_AddRemoveRaise").Invoke(proxy, new object[] { handler });
proxy.GetType().GetRuntimeMethods().Single(m => m.Name == "raise_AddRemoveRaise").Invoke(proxy, new object[] { EventArgs.Empty });
proxy.GetType().GetRuntimeMethods().Single(m => m.Name == "remove_AddRemoveRaise").Invoke(proxy, new object[] { handler });
Assert.True(invokedMethods.Count == 3, String.Format("Expected 3 method invocations but received {0}", invokedMethods.Count));
EventInfo eventInfo = ieventServiceTypeInfo.GetDeclaredEvent("AddRemoveRaise");
Assert.NotNull(eventInfo);
MethodInfo expectedMethod = eventInfo.AddMethod;
Assert.True(invokedMethods[0] != null && expectedMethod == invokedMethods[0], String.Format("First invoke should have been {0} but actual was {1}",
expectedMethod.Name, invokedMethods[0]));
expectedMethod = eventInfo.RaiseMethod;
Assert.True(invokedMethods[1] != null && expectedMethod == invokedMethods[1], String.Format("Second invoke should have been {0} but actual was {1}",
expectedMethod.Name, invokedMethods[1]));
expectedMethod = eventInfo.RemoveMethod;
Assert.True(invokedMethods[2] != null && expectedMethod == invokedMethods[2], String.Format("Third invoke should have been {0} but actual was {1}",
expectedMethod.Name, invokedMethods[1]));
}
[Fact]
public static void Proxy_Declares_Interface_Events()
{
TestType_IEventService proxy = DispatchProxy.Create<TestType_IEventService, TestDispatchProxy>();
EventInfo eventInfo = proxy.GetType().GetTypeInfo().GetDeclaredEvent("AddRemove");
Assert.NotNull(eventInfo);
}
[Fact]
public static void Invoke_Indexer_Setter_And_Getter_Invokes_Correct_Methods()
{
List<MethodInfo> invokedMethods = new List<MethodInfo>();
TestType_IIndexerService proxy = DispatchProxy.Create<TestType_IIndexerService, TestDispatchProxy>();
((TestDispatchProxy)proxy).CallOnInvoke = (method, args) =>
{
invokedMethods.Add(method);
return null;
};
proxy["key"] = "testValue";
string actualValue = proxy["key"];
Assert.True(invokedMethods.Count == 2, String.Format("Expected 2 method invocations but received {0}", invokedMethods.Count));
PropertyInfo propertyInfo = typeof(TestType_IIndexerService).GetTypeInfo().GetDeclaredProperty("Item");
Assert.NotNull(propertyInfo);
MethodInfo expectedMethod = propertyInfo.SetMethod;
Assert.True(invokedMethods[0] != null && expectedMethod == invokedMethods[0], String.Format("First invoke should have been {0} but actual was {1}",
expectedMethod.Name, invokedMethods[0]));
expectedMethod = propertyInfo.GetMethod;
Assert.True(invokedMethods[1] != null && expectedMethod == invokedMethods[1], String.Format("Second invoke should have been {0} but actual was {1}",
expectedMethod.Name, invokedMethods[1]));
Assert.Null(actualValue);
}
[Fact]
public static void Proxy_Declares_Interface_Indexers()
{
TestType_IIndexerService proxy = DispatchProxy.Create<TestType_IIndexerService, TestDispatchProxy>();
PropertyInfo propertyInfo = proxy.GetType().GetTypeInfo().GetDeclaredProperty("Item");
Assert.NotNull(propertyInfo);
}
}
}

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<ItemGroup>
<Project Include="System.Reflection.DispatchProxy.Tests.csproj" />
<Project Include="System.Reflection.DispatchProxy.Tests.csproj">
<OSGroup>Windows_NT</OSGroup>
<TestTFMs>net46</TestTFMs>
</Project>
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.traversal.targets))\dir.traversal.targets" />
</Project>

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<PropertyGroup>
<ProjectGuid>{089444FE-8FF5-4D8F-A51B-32D026425F6B}</ProjectGuid>
</PropertyGroup>
<!-- Default configurations to help VS understand the configurations -->
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='netstandard1.3-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='netstandard1.3-Release|AnyCPU'" />
<ItemGroup>
<Compile Include="DispatchProxyTests.cs" />
<Compile Include="TestTypes.cs" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project>

View File

@@ -0,0 +1,142 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
// Test types used to make proxies.
public interface TestType_IHelloService
{
string Hello(string message);
}
public interface TestType_IGoodbyeService
{
string Goodbye(string message);
}
// Demonstrates interface implementing multiple other interfaces
public interface TestType_IHelloAndGoodbyeService : TestType_IHelloService, TestType_IGoodbyeService
{
}
// Deliberately contains method with same signature of TestType_IHelloService (see TestType_IHelloService1And2).
public interface TestType_IHelloService2
{
string Hello(string message);
}
// Demonstrates 2 interfaces containing same method name dispatches to the right one
public interface TestType_IHelloService1And2 : TestType_IHelloService, TestType_IHelloService2
{
}
// Demonstrates methods taking multiple parameters as well as a params parameter
public interface TestType_IMultipleParameterService
{
double TestMethod(int i, string s, double d);
object ParamsMethod(params object[] parameters);
}
// Demonstrate a void-returning method and parameterless method
public interface TestType_IOneWay
{
void OneWay();
}
// Demonstrates proxies can be made for properties.
public interface TestType_IPropertyService
{
string ReadWrite { get; set; }
}
// Demonstrates proxies can be made for events.
public interface TestType_IEventService
{
event EventHandler AddRemove;
}
// Demonstrates proxies can be made for indexed properties.
public interface TestType_IIndexerService
{
string this[string key] { get; set; }
}
// Demonstrates proxies can be made for internal types
internal interface TestType_InternalInterfaceService
{
string Echo(string message);
}
// Demonstrates proxies can be made for public types implementing internal interfaces
internal interface TestType_PublicInterfaceService_Implements_Internal : TestType_InternalInterfaceService
{
string Echo2(string message);
}
// Negative -- demonstrates trying to use a class for the interface type for the proxy
public class TestType_ConcreteClass
{
public string Echo(string s) { return null; }
}
// Negative -- demonstrates base type that is sealed and should generate exception
public sealed class Sealed_TestDispatchProxy : DispatchProxy
{
protected override object Invoke(MethodInfo targetMethod, object[] args)
{
throw new InvalidOperationException();
}
}
// This test double creates a proxy instance for the requested 'ProxyT' type.
// When methods are invoked on that proxy, it will call a registered callback.
public class TestDispatchProxy : DispatchProxy
{
// Gets or sets the Action to invoke when clients call methods on the proxy.
public Func<MethodInfo, object[], object> CallOnInvoke { get; set; }
// Gets the proxy itself (which is always 'this')
public object GetProxy()
{
return this;
}
// Implementation of DispatchProxy.Invoke() just calls back to given Action
protected override object Invoke(MethodInfo targetMethod, object[] args)
{
return CallOnInvoke(targetMethod, args);
}
}
public class TestDispatchProxy2 : TestDispatchProxy
{
}
// Negative test -- demonstrates base type that is abstract
public abstract class Abstract_TestDispatchProxy : DispatchProxy
{
protected override object Invoke(MethodInfo targetMethod, object[] args)
{
throw new InvalidOperationException();
}
}
// Negative -- demonstrates base type that has no public default ctor
public class NoDefaultCtor_TestDispatchProxy : DispatchProxy
{
private NoDefaultCtor_TestDispatchProxy()
{
}
protected override object Invoke(MethodInfo targetMethod, object[] args)
{
throw new InvalidOperationException();
}
}