Ver código fonte

Hide UI types in facade reference assemblies

Ian Griffiths 3 meses atrás
pai
commit
8df98cb6a9

+ 27 - 0
Rx.NET/Source/System.Reactive.sln

@@ -78,6 +78,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Reactive.For.Windows
 EndProject
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Reactive", "facades\System.Reactive\System.Reactive.csproj", "{BC5F1E6F-858E-4AF8-80CD-DBB5B6CE5FE1}"
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Reactive", "facades\System.Reactive\System.Reactive.csproj", "{BC5F1E6F-858E-4AF8-80CD-DBB5B6CE5FE1}"
 EndProject
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Reactive.MakeRefAssemblies", "facades\System.Reactive.MakeRefAssemblies\System.Reactive.MakeRefAssemblies.csproj", "{20DF1979-FD74-DD5D-60B3-CE5874101E31}"
+EndProject
 Global
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug (with UWP)|Any CPU = Debug (with UWP)|Any CPU
 		Debug (with UWP)|Any CPU = Debug (with UWP)|Any CPU
@@ -624,6 +626,30 @@ Global
 		{BC5F1E6F-858E-4AF8-80CD-DBB5B6CE5FE1}.Release|x64.Build.0 = Release|Any CPU
 		{BC5F1E6F-858E-4AF8-80CD-DBB5B6CE5FE1}.Release|x64.Build.0 = Release|Any CPU
 		{BC5F1E6F-858E-4AF8-80CD-DBB5B6CE5FE1}.Release|x86.ActiveCfg = Release|Any CPU
 		{BC5F1E6F-858E-4AF8-80CD-DBB5B6CE5FE1}.Release|x86.ActiveCfg = Release|Any CPU
 		{BC5F1E6F-858E-4AF8-80CD-DBB5B6CE5FE1}.Release|x86.Build.0 = Release|Any CPU
 		{BC5F1E6F-858E-4AF8-80CD-DBB5B6CE5FE1}.Release|x86.Build.0 = Release|Any CPU
+		{20DF1979-FD74-DD5D-60B3-CE5874101E31}.Debug (with UWP)|Any CPU.ActiveCfg = Debug|Any CPU
+		{20DF1979-FD74-DD5D-60B3-CE5874101E31}.Debug (with UWP)|Any CPU.Build.0 = Debug|Any CPU
+		{20DF1979-FD74-DD5D-60B3-CE5874101E31}.Debug (with UWP)|ARM.ActiveCfg = Debug|Any CPU
+		{20DF1979-FD74-DD5D-60B3-CE5874101E31}.Debug (with UWP)|ARM.Build.0 = Debug|Any CPU
+		{20DF1979-FD74-DD5D-60B3-CE5874101E31}.Debug (with UWP)|x64.ActiveCfg = Debug|Any CPU
+		{20DF1979-FD74-DD5D-60B3-CE5874101E31}.Debug (with UWP)|x64.Build.0 = Debug|Any CPU
+		{20DF1979-FD74-DD5D-60B3-CE5874101E31}.Debug (with UWP)|x86.ActiveCfg = Debug|Any CPU
+		{20DF1979-FD74-DD5D-60B3-CE5874101E31}.Debug (with UWP)|x86.Build.0 = Debug|Any CPU
+		{20DF1979-FD74-DD5D-60B3-CE5874101E31}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{20DF1979-FD74-DD5D-60B3-CE5874101E31}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{20DF1979-FD74-DD5D-60B3-CE5874101E31}.Debug|ARM.ActiveCfg = Debug|Any CPU
+		{20DF1979-FD74-DD5D-60B3-CE5874101E31}.Debug|ARM.Build.0 = Debug|Any CPU
+		{20DF1979-FD74-DD5D-60B3-CE5874101E31}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{20DF1979-FD74-DD5D-60B3-CE5874101E31}.Debug|x64.Build.0 = Debug|Any CPU
+		{20DF1979-FD74-DD5D-60B3-CE5874101E31}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{20DF1979-FD74-DD5D-60B3-CE5874101E31}.Debug|x86.Build.0 = Debug|Any CPU
+		{20DF1979-FD74-DD5D-60B3-CE5874101E31}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{20DF1979-FD74-DD5D-60B3-CE5874101E31}.Release|Any CPU.Build.0 = Release|Any CPU
+		{20DF1979-FD74-DD5D-60B3-CE5874101E31}.Release|ARM.ActiveCfg = Release|Any CPU
+		{20DF1979-FD74-DD5D-60B3-CE5874101E31}.Release|ARM.Build.0 = Release|Any CPU
+		{20DF1979-FD74-DD5D-60B3-CE5874101E31}.Release|x64.ActiveCfg = Release|Any CPU
+		{20DF1979-FD74-DD5D-60B3-CE5874101E31}.Release|x64.Build.0 = Release|Any CPU
+		{20DF1979-FD74-DD5D-60B3-CE5874101E31}.Release|x86.ActiveCfg = Release|Any CPU
+		{20DF1979-FD74-DD5D-60B3-CE5874101E31}.Release|x86.Build.0 = Release|Any CPU
 	EndGlobalSection
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
 		HideSolutionNode = FALSE
@@ -648,6 +674,7 @@ Global
 		{C3FC6098-AC7F-4825-B292-4049BC6FC76E} = {1873A545-87AA-4C22-BA1A-8A6602F65749}
 		{C3FC6098-AC7F-4825-B292-4049BC6FC76E} = {1873A545-87AA-4C22-BA1A-8A6602F65749}
 		{EB27A089-56EC-4621-BF88-E3B0DA8E6557} = {1873A545-87AA-4C22-BA1A-8A6602F65749}
 		{EB27A089-56EC-4621-BF88-E3B0DA8E6557} = {1873A545-87AA-4C22-BA1A-8A6602F65749}
 		{BC5F1E6F-858E-4AF8-80CD-DBB5B6CE5FE1} = {A0F39260-B8F8-4FCB-9679-0ED917A22BDF}
 		{BC5F1E6F-858E-4AF8-80CD-DBB5B6CE5FE1} = {A0F39260-B8F8-4FCB-9679-0ED917A22BDF}
+		{20DF1979-FD74-DD5D-60B3-CE5874101E31} = {A0F39260-B8F8-4FCB-9679-0ED917A22BDF}
 	EndGlobalSection
 	EndGlobalSection
 	GlobalSection(ExtensibilityGlobals) = postSolution
 	GlobalSection(ExtensibilityGlobals) = postSolution
 		SolutionGuid = {2483F58F-A8D6-4FFE-A3C1-10F3A36DBE69}
 		SolutionGuid = {2483F58F-A8D6-4FFE-A3C1-10F3A36DBE69}

+ 102 - 0
Rx.NET/Source/facades/System.Reactive.MakeRefAssemblies/System.Reactive.MakeRefAssemblies.csproj

@@ -0,0 +1,102 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFrameworks>netstandard2.0;net472;uap10.0.18362;net8.0;net8.0-windows10.0.19041</TargetFrameworks>
+    <Nullable>enable</Nullable>
+
+    <!--
+    We seem to get spurious CA1812 warnings (internal class apparently never instantiated. The same code compiles
+    without warnings when built as a normal library, so this seems to be an issue with the refernce assembly build.
+    -->
+    <NoWarn>$(NoWarn);CA1812</NoWarn>
+
+    <DefineConstants>$(DefineConstants);LEGACY_SYSTEM_REACTIVE_FACADE;BUILDING_REFERENCE_ASSEMBLY</DefineConstants>
+
+    <ProduceOnlyReferenceAssembly>true</ProduceOnlyReferenceAssembly>
+
+    <TargetName>System.Reactive</TargetName>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <!--
+    See comments in System.Reactive for explanation of this and the
+    PropertyGroup that follows.
+    -->
+    <Compile Remove="..\GlobalAssemblyVersion.cs" Link="GlobalAssemblyVersion.cs" />
+  </ItemGroup>
+
+  <PropertyGroup>
+    <!-- Re-instate the normal versioning behaviour. -->
+    <GenerateAssemblyVersionAttribute>true</GenerateAssemblyVersionAttribute>
+    <GenerateAssemblyVersionInfo>true</GenerateAssemblyVersionInfo>
+  </PropertyGroup>
+
+
+  <ItemGroup>
+    <Compile Include="..\System.Reactive\**\*.cs" Exclude="$(DefaultItemExcludes);$(DefaultExcludesInProjectFolder);..\System.Reactive\obj\**\*;..\System.Reactive\bin\**\*" />
+    <Compile Remove="..\System.Reactive\Obsolete\**\*.*" />
+    <!-- Workaround so the files appear in VS -->
+    <None Include="..\System.Reactive\Obsolete\**\*.*" />
+  </ItemGroup>
+
+  <ItemGroup Condition="$(TargetFramework.StartsWith('uap10.0'))">
+    <Compile Include="..\System.Reactive\Obsolete\UWP\**\*.cs" />
+    <Compile Include="..\..\src\System.Reactive.For.Uwp\Stubs.cs" Link="Obsolete\UWP\Stubs.cs" />
+    <Compile Include="..\..\src\System.Reactive.For.Uwp\ThreadPoolTimerExtensions.cs" Link="Obsolete\UWP\Concurrency\ThreadPoolTimerExtensions.cs" />
+  </ItemGroup>
+
+  <!-- Windows includes for Desktop and UWP -->
+  <ItemGroup Condition=" '$(TargetFramework)' == 'net472' or $(TargetFramework.StartsWith('uap10.0')) or $(TargetFramework.StartsWith('net8.0-windows')) or $(TargetFramework.StartsWith('net9.0-windows'))">
+    <Compile Include="..\System.Reactive\Obsolete\Windows\**\*.cs" />
+    <EmbeddedResource Include="..\System.Reactive\Obsolete\Windows\**\*.resx" />
+  </ItemGroup>
+
+  <!-- .NET FX -->
+  <ItemGroup Condition=" '$(TargetFramework)' == 'net472'">
+    <Reference Include="System.Windows" />
+    <Reference Include="System.Windows.Forms" />
+    <Reference Include="WindowsBase" />
+    
+    <Compile Include="..\System.Reactive\Obsolete\Remoting\**\*.cs" />
+  </ItemGroup>
+
+  <ItemGroup Condition=" '$(TargetFramework)' == 'net472' or $(TargetFramework.StartsWith('net8.0-windows')) or $(TargetFramework.StartsWith('net9.0-windows'))">
+    <Compile Include="..\System.Reactive\Obsolete\Desktop\**\*.cs" />
+  </ItemGroup>
+
+
+    <!-- WindowsRuntime (netX.0-windows and UWP) -->
+  <ItemGroup Condition="$(TargetFramework.StartsWith('uap10.0')) or $(TargetFramework.StartsWith('net8.0-windows')) or $(TargetFramework.StartsWith('net9.0-windows'))">
+    <ProjectReference Include="..\..\src\System.Reactive.For.WindowsRuntime\System.Reactive.For.WindowsRuntime.csproj" />
+  </ItemGroup>
+
+  <!-- Windows Forms and WPF -->
+  <ItemGroup Condition="('$(TargetFramework)' == 'net472') or $(TargetFramework.StartsWith('net8.0-windows')) or $(TargetFramework.StartsWith('net9.0-windows'))">
+    <ProjectReference Include="..\..\src\System.Reactive.For.WindowsForms\System.Reactive.For.WindowsForms.csproj" />
+    <ProjectReference Include="..\..\src\System.Reactive.For.Wpf\System.Reactive.For.Wpf.csproj" />
+  </ItemGroup>
+
+  <ItemGroup Condition="'$(TargetFramework)'=='uap10.0.18362'">
+    <!--
+    The .NET SDK doesn't expect TargetFrameworks to include uap10.0.18362, so it doesn't understand
+    that this project is capable of using projects that target .NET Standard 2.0, with the result
+    that it reports an error when trying to resolve the reference to System.Reactive.Net. So
+    when building for UWP, we explicitly set the target framework here.
+    -->
+    <ProjectReference Include="..\..\src\System.Reactive.Net\System.Reactive.Net.csproj">
+      <Aliases>SystemReactiveNet</Aliases>
+      <SetTargetFramework>TargetFramework=netstandard2.0</SetTargetFramework>
+    </ProjectReference>
+  </ItemGroup>
+
+  <ItemGroup Condition="'$(TargetFramework)'!='uap10.0.18362'">
+    <ProjectReference Include="..\..\src\System.Reactive.Net\System.Reactive.Net.csproj">
+      <Aliases>SystemReactiveNet</Aliases>
+    </ProjectReference>
+  </ItemGroup>
+
+  <ItemGroup Condition="'$(TargetFramework)'=='uap10.0.18362'">
+    <ReferencePath Include="$(TargetPlatformSdkPath)UnionMetadata\10.0.19041.0\Windows.winmd" />
+  </ItemGroup>
+
+</Project>

+ 183 - 12
Rx.NET/Source/facades/System.Reactive/ApiCompatSuppressions.xml

@@ -2,22 +2,109 @@
 <!-- https://learn.microsoft.com/dotnet/fundamentals/package-validation/diagnostic-ids -->
 <!-- https://learn.microsoft.com/dotnet/fundamentals/package-validation/diagnostic-ids -->
 <Suppressions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
 <Suppressions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
 
 
+  <!--
+  We deliberately exclude certain types from the reference assemblies.
+
+  Specifically, in the netX.0-windows10.0.X target, we need the runtime libraries to include the same API
+  surface area as System.Reactive v6.0.1, but we have to remove types that define extension methods for
+  IObservable<T> where those extension methods use UI-framework-specific types. For example, we don't want
+  the ObserveOn(Control) to be available. That's because if it _is_ visible to the compiler, it becomes impossible
+  to use the non-UI-specific overloads of ObserveOn without having a reference to the Microsoft.WindowsDesktop.App
+  framework! (So even when you aren't using the Windows Forms or WPF overloads, the compiler needs access to
+  the Windows Forms and WPF assemblies to be able to determine that you aren't using ObserveOn(Control) or
+  ObserveOn(Dispatcher).
+
+  That would make it impossible to use the System.Reactive legacy package, and also to use Rx in your app, without
+  also have a desktop framework dependency. And since the whole reason we're relegating System.Reactive to being
+  a legacy facade is to fix that very problem, this would be pointless.
+
+  So we hide all the UI-specific types from the reference assemblies for the .NET Windows-specific targets.
+  (We don't have to do that for .NET FX or UAP targets because if you're building for those, you already have
+  the relevant UI frameworks installed.)
+  -->
+  <Suppression>
+    <DiagnosticId>CP0001</DiagnosticId>
+    <Target>T:System.Reactive.Concurrency.ControlScheduler</Target>
+    <Left>ref/net8.0-windows10.0.19041/System.Reactive.dll</Left>
+    <Right>lib/net8.0-windows10.0.19041/System.Reactive.dll</Right>
+  </Suppression>
+  <Suppression>
+    <DiagnosticId>CP0001</DiagnosticId>
+    <Target>T:System.Reactive.Concurrency.CoreDispatcherScheduler</Target>
+    <Left>ref/net8.0-windows10.0.19041/System.Reactive.dll</Left>
+    <Right>lib/net8.0-windows10.0.19041/System.Reactive.dll</Right>
+  </Suppression>
+  <Suppression>
+    <DiagnosticId>CP0001</DiagnosticId>
+    <Target>T:System.Reactive.Concurrency.DispatcherScheduler</Target>
+    <Left>ref/net8.0-windows10.0.19041/System.Reactive.dll</Left>
+    <Right>lib/net8.0-windows10.0.19041/System.Reactive.dll</Right>
+  </Suppression>
+  <Suppression>
+    <DiagnosticId>CP0001</DiagnosticId>
+    <Target>T:System.Reactive.Linq.AsyncInfoObservable</Target>
+    <Left>ref/net8.0-windows10.0.19041/System.Reactive.dll</Left>
+    <Right>lib/net8.0-windows10.0.19041/System.Reactive.dll</Right>
+  </Suppression>
+  <Suppression>
+    <DiagnosticId>CP0001</DiagnosticId>
+    <Target>T:System.Reactive.Linq.ControlObservable</Target>
+    <Left>ref/net8.0-windows10.0.19041/System.Reactive.dll</Left>
+    <Right>lib/net8.0-windows10.0.19041/System.Reactive.dll</Right>
+  </Suppression>
+  <Suppression>
+    <DiagnosticId>CP0001</DiagnosticId>
+    <Target>T:System.Reactive.Linq.CoreDispatcherObservable</Target>
+    <Left>ref/net8.0-windows10.0.19041/System.Reactive.dll</Left>
+    <Right>lib/net8.0-windows10.0.19041/System.Reactive.dll</Right>
+  </Suppression>
+  <Suppression>
+    <DiagnosticId>CP0001</DiagnosticId>
+    <Target>T:System.Reactive.Linq.DispatcherObservable</Target>
+    <Left>ref/net8.0-windows10.0.19041/System.Reactive.dll</Left>
+    <Right>lib/net8.0-windows10.0.19041/System.Reactive.dll</Right>
+  </Suppression>
+  <Suppression>
+    <DiagnosticId>CP0001</DiagnosticId>
+    <Target>T:System.Reactive.Linq.WindowsObservable</Target>
+    <Left>ref/net8.0-windows10.0.19041/System.Reactive.dll</Left>
+    <Right>lib/net8.0-windows10.0.19041/System.Reactive.dll</Right>
+  </Suppression>
+  <Suppression>
+    <DiagnosticId>CP0001</DiagnosticId>
+    <Target>T:System.Reactive.Windows.Foundation.AsyncInfoObservableExtensions</Target>
+    <Left>ref/net8.0-windows10.0.19041/System.Reactive.dll</Left>
+    <Right>lib/net8.0-windows10.0.19041/System.Reactive.dll</Right>
+  </Suppression>
+
   <!--
   <!--
   There are various internal (same package) inconsistencies that were already in Rx 6.0, because the API surface
   There are various internal (same package) inconsistencies that were already in Rx 6.0, because the API surface
   area was different across targets. There doesn't seem to be a 'baseline-only' mode, so we need to suppress
   area was different across targets. There doesn't seem to be a 'baseline-only' mode, so we need to suppress
   the various validation errors that describe differences that we must preserve for compatibility with Rx 6.0.
   the various validation errors that describe differences that we must preserve for compatibility with Rx 6.0.
 
 
   Essentially these all arise because netstandard2.0 is a viable target for frameworks in which other targets
   Essentially these all arise because netstandard2.0 is a viable target for frameworks in which other targets
-  are better matches. (E.g., if you target net6.0-windows10-0.19041, then you can actually tell the build system
-  to give you the .NET Standard 2.0 target of System.Reactive.dll, because you're on a runtime that supports
-  .NET Standard 2.0. By default you'd get net6.0-windows10-0.19041 because that's a better match (a precise match
-  in fact), but since you can override that and get the netstandard2.0 target instead, package validation sees
-  fit to tell us all the ways in which the netstandard2.0 target differs from the net6.0-windows10-0.19041 target.
-  Similarly, uap10.0.1836 is a framework that supports netstandard2.0, so again, the package validation tells
-  us about the differences between the netstandard2.0 and uap10.0.18362 targets.
+  are better matches. An application that targets net8.0-windows10-0.19041, is able to use any netstandard2.0
+  library, and any of those might have been built against Rx. Since the net8.0-windows10.0.19041 target is a
+  better match for the app, that's the version of Rx that will be chosen, but it needs to be consistent with
+  the netstandard2.0 one, because other libraries might have been built against that one.
+
+  The analyzer seems a little aggressive in that not only does it require that targets that might be substituted
+  for the netstandard2.0 target must provide the same surface area as the netstandard2.0 target, it also requires
+  that they don't provide any API surface area that is not present in the netstandard2.0 target. That seems more
+  odd because it's not obvious why something might have been built against the net8.0-windows10.0.19041 target
+  only to find itself using the netstandard2.0 target at runtime.
+
+  We mostly only have inconsistencies of the second kind. (I.e., there's almost nothing in the netstandard2.0 target
+  that is missing from more specific targets. The one exception is that the ThreadPoolScheduler implements
+  ISchedulerLongRunning on all targets except uap10.0.18362.) But we have plenty of examples where the more
+  specific targets provide additional API surface area that is not present in the netstandard2.0 target. It seems
+  like there really should be a way to turn off detection of that second kind, because it's normal. (The main reason
+  we offer targets in addition to netstandard2.0 is to add additional features.) But if there's a setting to do this,
+  I've not found it.
 
 
   We only care about differences between the baseline (6.0.1) and the current package, so we don't really want
   We only care about differences between the baseline (6.0.1) and the current package, so we don't really want
-  to hear about internal inconstencies, but apparently, suppressing them is the only option.
+  to hear about internal inconstencies, but apparently, suppressing them is the only option. None of the options
+  for turning off strict mode seem to help.
 
 
   The CP0001 errors all describes types that are present in one DLL but not another.
   The CP0001 errors all describes types that are present in one DLL but not another.
   -->
   -->
@@ -29,6 +116,13 @@
     <Right>lib/netstandard2.0/System.Reactive.dll</Right>
     <Right>lib/netstandard2.0/System.Reactive.dll</Right>
     <IsBaselineSuppression>true</IsBaselineSuppression>
     <IsBaselineSuppression>true</IsBaselineSuppression>
   </Suppression>
   </Suppression>
+  <Suppression>
+    <DiagnosticId>CP0001</DiagnosticId>
+    <Target>T:System.Reactive.Concurrency.ControlScheduler</Target>
+    <Left>lib/net6.0-windows10.0.19041/System.Reactive.dll</Left>
+    <Right>ref/netstandard2.0/System.Reactive.dll</Right>
+    <IsBaselineSuppression>true</IsBaselineSuppression>
+  </Suppression>
   <Suppression>
   <Suppression>
     <DiagnosticId>CP0001</DiagnosticId>
     <DiagnosticId>CP0001</DiagnosticId>
     <Target>T:System.Reactive.Concurrency.CoreDispatcherScheduler</Target>
     <Target>T:System.Reactive.Concurrency.CoreDispatcherScheduler</Target>
@@ -36,6 +130,13 @@
     <Right>lib/netstandard2.0/System.Reactive.dll</Right>
     <Right>lib/netstandard2.0/System.Reactive.dll</Right>
     <IsBaselineSuppression>true</IsBaselineSuppression>
     <IsBaselineSuppression>true</IsBaselineSuppression>
   </Suppression>
   </Suppression>
+  <Suppression>
+    <DiagnosticId>CP0001</DiagnosticId>
+    <Target>T:System.Reactive.Concurrency.CoreDispatcherScheduler</Target>
+    <Left>lib/net6.0-windows10.0.19041/System.Reactive.dll</Left>
+    <Right>ref/netstandard2.0/System.Reactive.dll</Right>
+    <IsBaselineSuppression>true</IsBaselineSuppression>
+  </Suppression>
   <Suppression>
   <Suppression>
     <DiagnosticId>CP0001</DiagnosticId>
     <DiagnosticId>CP0001</DiagnosticId>
     <Target>T:System.Reactive.Concurrency.DispatcherScheduler</Target>
     <Target>T:System.Reactive.Concurrency.DispatcherScheduler</Target>
@@ -43,6 +144,13 @@
     <Right>lib/netstandard2.0/System.Reactive.dll</Right>
     <Right>lib/netstandard2.0/System.Reactive.dll</Right>
     <IsBaselineSuppression>true</IsBaselineSuppression>
     <IsBaselineSuppression>true</IsBaselineSuppression>
   </Suppression>
   </Suppression>
+  <Suppression>
+    <DiagnosticId>CP0001</DiagnosticId>
+    <Target>T:System.Reactive.Concurrency.DispatcherScheduler</Target>
+    <Left>lib/net6.0-windows10.0.19041/System.Reactive.dll</Left>
+    <Right>ref/netstandard2.0/System.Reactive.dll</Right>
+    <IsBaselineSuppression>true</IsBaselineSuppression>
+  </Suppression>
   <Suppression>
   <Suppression>
     <DiagnosticId>CP0001</DiagnosticId>
     <DiagnosticId>CP0001</DiagnosticId>
     <Target>T:System.Reactive.IEventPatternSource`2</Target>
     <Target>T:System.Reactive.IEventPatternSource`2</Target>
@@ -50,6 +158,13 @@
     <Right>lib/netstandard2.0/System.Reactive.dll</Right>
     <Right>lib/netstandard2.0/System.Reactive.dll</Right>
     <IsBaselineSuppression>true</IsBaselineSuppression>
     <IsBaselineSuppression>true</IsBaselineSuppression>
   </Suppression>
   </Suppression>
+  <Suppression>
+    <DiagnosticId>CP0001</DiagnosticId>
+    <Target>T:System.Reactive.IEventPatternSource`2</Target>
+    <Left>lib/net6.0-windows10.0.19041/System.Reactive.dll</Left>
+    <Right>ref/netstandard2.0/System.Reactive.dll</Right>
+    <IsBaselineSuppression>true</IsBaselineSuppression>
+  </Suppression>
   <Suppression>
   <Suppression>
     <DiagnosticId>CP0001</DiagnosticId>
     <DiagnosticId>CP0001</DiagnosticId>
     <Target>T:System.Reactive.Linq.AsyncInfoObservable</Target>
     <Target>T:System.Reactive.Linq.AsyncInfoObservable</Target>
@@ -57,6 +172,13 @@
     <Right>lib/netstandard2.0/System.Reactive.dll</Right>
     <Right>lib/netstandard2.0/System.Reactive.dll</Right>
     <IsBaselineSuppression>true</IsBaselineSuppression>
     <IsBaselineSuppression>true</IsBaselineSuppression>
   </Suppression>
   </Suppression>
+  <Suppression>
+    <DiagnosticId>CP0001</DiagnosticId>
+    <Target>T:System.Reactive.Linq.AsyncInfoObservable</Target>
+    <Left>lib/net6.0-windows10.0.19041/System.Reactive.dll</Left>
+    <Right>ref/netstandard2.0/System.Reactive.dll</Right>
+    <IsBaselineSuppression>true</IsBaselineSuppression>
+  </Suppression>
   <Suppression>
   <Suppression>
     <DiagnosticId>CP0001</DiagnosticId>
     <DiagnosticId>CP0001</DiagnosticId>
     <Target>T:System.Reactive.Linq.ControlObservable</Target>
     <Target>T:System.Reactive.Linq.ControlObservable</Target>
@@ -64,6 +186,13 @@
     <Right>lib/netstandard2.0/System.Reactive.dll</Right>
     <Right>lib/netstandard2.0/System.Reactive.dll</Right>
     <IsBaselineSuppression>true</IsBaselineSuppression>
     <IsBaselineSuppression>true</IsBaselineSuppression>
   </Suppression>
   </Suppression>
+  <Suppression>
+    <DiagnosticId>CP0001</DiagnosticId>
+    <Target>T:System.Reactive.Linq.ControlObservable</Target>
+    <Left>lib/net6.0-windows10.0.19041/System.Reactive.dll</Left>
+    <Right>ref/netstandard2.0/System.Reactive.dll</Right>
+    <IsBaselineSuppression>true</IsBaselineSuppression>
+  </Suppression>
   <Suppression>
   <Suppression>
     <DiagnosticId>CP0001</DiagnosticId>
     <DiagnosticId>CP0001</DiagnosticId>
     <Target>T:System.Reactive.Linq.CoreDispatcherObservable</Target>
     <Target>T:System.Reactive.Linq.CoreDispatcherObservable</Target>
@@ -71,6 +200,13 @@
     <Right>lib/netstandard2.0/System.Reactive.dll</Right>
     <Right>lib/netstandard2.0/System.Reactive.dll</Right>
     <IsBaselineSuppression>true</IsBaselineSuppression>
     <IsBaselineSuppression>true</IsBaselineSuppression>
   </Suppression>
   </Suppression>
+  <Suppression>
+    <DiagnosticId>CP0001</DiagnosticId>
+    <Target>T:System.Reactive.Linq.CoreDispatcherObservable</Target>
+    <Left>lib/net6.0-windows10.0.19041/System.Reactive.dll</Left>
+    <Right>ref/netstandard2.0/System.Reactive.dll</Right>
+    <IsBaselineSuppression>true</IsBaselineSuppression>
+  </Suppression>
   <Suppression>
   <Suppression>
     <DiagnosticId>CP0001</DiagnosticId>
     <DiagnosticId>CP0001</DiagnosticId>
     <Target>T:System.Reactive.Linq.DispatcherObservable</Target>
     <Target>T:System.Reactive.Linq.DispatcherObservable</Target>
@@ -78,6 +214,13 @@
     <Right>lib/netstandard2.0/System.Reactive.dll</Right>
     <Right>lib/netstandard2.0/System.Reactive.dll</Right>
     <IsBaselineSuppression>true</IsBaselineSuppression>
     <IsBaselineSuppression>true</IsBaselineSuppression>
   </Suppression>
   </Suppression>
+  <Suppression>
+    <DiagnosticId>CP0001</DiagnosticId>
+    <Target>T:System.Reactive.Linq.DispatcherObservable</Target>
+    <Left>lib/net6.0-windows10.0.19041/System.Reactive.dll</Left>
+    <Right>ref/netstandard2.0/System.Reactive.dll</Right>
+    <IsBaselineSuppression>true</IsBaselineSuppression>
+  </Suppression>
   <Suppression>
   <Suppression>
     <DiagnosticId>CP0001</DiagnosticId>
     <DiagnosticId>CP0001</DiagnosticId>
     <Target>T:System.Reactive.Linq.WindowsObservable</Target>
     <Target>T:System.Reactive.Linq.WindowsObservable</Target>
@@ -85,6 +228,13 @@
     <Right>lib/netstandard2.0/System.Reactive.dll</Right>
     <Right>lib/netstandard2.0/System.Reactive.dll</Right>
     <IsBaselineSuppression>true</IsBaselineSuppression>
     <IsBaselineSuppression>true</IsBaselineSuppression>
   </Suppression>
   </Suppression>
+  <Suppression>
+    <DiagnosticId>CP0001</DiagnosticId>
+    <Target>T:System.Reactive.Linq.WindowsObservable</Target>
+    <Left>lib/net6.0-windows10.0.19041/System.Reactive.dll</Left>
+    <Right>ref/netstandard2.0/System.Reactive.dll</Right>
+    <IsBaselineSuppression>true</IsBaselineSuppression>
+  </Suppression>
   <Suppression>
   <Suppression>
     <DiagnosticId>CP0001</DiagnosticId>
     <DiagnosticId>CP0001</DiagnosticId>
     <Target>T:System.Reactive.Windows.Foundation.AsyncInfoObservableExtensions</Target>
     <Target>T:System.Reactive.Windows.Foundation.AsyncInfoObservableExtensions</Target>
@@ -92,6 +242,13 @@
     <Right>lib/netstandard2.0/System.Reactive.dll</Right>
     <Right>lib/netstandard2.0/System.Reactive.dll</Right>
     <IsBaselineSuppression>true</IsBaselineSuppression>
     <IsBaselineSuppression>true</IsBaselineSuppression>
   </Suppression>
   </Suppression>
+  <Suppression>
+    <DiagnosticId>CP0001</DiagnosticId>
+    <Target>T:System.Reactive.Windows.Foundation.AsyncInfoObservableExtensions</Target>
+    <Left>lib/net6.0-windows10.0.19041/System.Reactive.dll</Left>
+    <Right>ref/netstandard2.0/System.Reactive.dll</Right>
+    <IsBaselineSuppression>true</IsBaselineSuppression>
+  </Suppression>
 
 
 
 
   <!--
   <!--
@@ -110,8 +267,8 @@
   <Suppression>
   <Suppression>
     <DiagnosticId>CP0008</DiagnosticId>
     <DiagnosticId>CP0008</DiagnosticId>
     <Target>T:System.Reactive.Concurrency.ThreadPoolScheduler</Target>
     <Target>T:System.Reactive.Concurrency.ThreadPoolScheduler</Target>
-    <Left>lib/netstandard2.0/System.Reactive.dll</Left>
-    <Right>lib/uap10.0.18362/System.Reactive.dll</Right>
+    <Left>ref/netstandard2.0/System.Reactive.dll</Left>
+    <Right>ref/uap10.0.18362/System.Reactive.dll</Right>
   </Suppression>
   </Suppression>
 
 
   <!--
   <!--
@@ -125,8 +282,8 @@
   <Suppression>
   <Suppression>
     <DiagnosticId>CP0002</DiagnosticId>
     <DiagnosticId>CP0002</DiagnosticId>
     <Target>M:System.Reactive.Concurrency.ThreadPoolScheduler.ScheduleLongRunning``1(``0,System.Action{``0,System.Reactive.Disposables.ICancelable})</Target>
     <Target>M:System.Reactive.Concurrency.ThreadPoolScheduler.ScheduleLongRunning``1(``0,System.Action{``0,System.Reactive.Disposables.ICancelable})</Target>
-    <Left>lib/netstandard2.0/System.Reactive.dll</Left>
-    <Right>lib/uap10.0.18362/System.Reactive.dll</Right>
+    <Left>ref/netstandard2.0/System.Reactive.dll</Left>
+    <Right>ref/uap10.0.18362/System.Reactive.dll</Right>
   </Suppression>
   </Suppression>
 
 
 
 
@@ -148,6 +305,13 @@
     <Right>lib/netstandard2.0/System.Reactive.dll</Right>
     <Right>lib/netstandard2.0/System.Reactive.dll</Right>
     <IsBaselineSuppression>true</IsBaselineSuppression>
     <IsBaselineSuppression>true</IsBaselineSuppression>
   </Suppression>
   </Suppression>
+  <Suppression>
+    <DiagnosticId>CP0008</DiagnosticId>
+    <Target>T:System.Reactive.NotificationKind</Target>
+    <Left>lib/net6.0-windows10.0.19041/System.Reactive.dll</Left>
+    <Right>ref/netstandard2.0/System.Reactive.dll</Right>
+    <IsBaselineSuppression>true</IsBaselineSuppression>
+  </Suppression>
   <Suppression>
   <Suppression>
     <DiagnosticId>CP0008</DiagnosticId>
     <DiagnosticId>CP0008</DiagnosticId>
     <Target>T:System.Reactive.NotificationKind</Target>
     <Target>T:System.Reactive.NotificationKind</Target>
@@ -155,4 +319,11 @@
     <Right>lib/netstandard2.0/System.Reactive.dll</Right>
     <Right>lib/netstandard2.0/System.Reactive.dll</Right>
     <IsBaselineSuppression>true</IsBaselineSuppression>
     <IsBaselineSuppression>true</IsBaselineSuppression>
   </Suppression>
   </Suppression>
+  <Suppression>
+    <DiagnosticId>CP0008</DiagnosticId>
+    <Target>T:System.Reactive.NotificationKind</Target>
+    <Left>lib/net6.0/System.Reactive.dll</Left>
+    <Right>ref/netstandard2.0/System.Reactive.dll</Right>
+    <IsBaselineSuppression>true</IsBaselineSuppression>
+  </Suppression>
 </Suppressions>
 </Suppressions>

+ 15 - 0
Rx.NET/Source/facades/System.Reactive/Obsolete/Remoting/Linq/Observable.Remoting.cs

@@ -2,6 +2,21 @@
 // The .NET Foundation licenses this file to you under the MIT License.
 // The .NET Foundation licenses this file to you under the MIT License.
 // See the LICENSE file in the project root for more information. 
 // See the LICENSE file in the project root for more information. 
 
 
+// Remoting types now live only in the System.Reactive legacy facade package (meaning that this isn't
+// strictly a pure facade package).
+// Nobody should be using Remoting any more. And the new System.Reactive.Net package does not include
+// a net472 target. If this type remained in there, that would be the only reason it would need to offer
+// that target.
+// We could move this into a separate package entirely, but unless we discover that people really want it,
+// the addition of a whole new package just to provide .NET Remoting support would seem like we were
+// encouraging people to use a feature that they should not. it can remain in here. If nobody complains,
+// we can mark it as obsolete in a future release.
+// (We can't put it back into the old System.Reactive.Runtime.Remoting package and forward to there from
+// here, because existing versions of that package contain type forwarders back to this to System.Reactive,
+// package, and if people managed to get a slightly weird combination of versions of different Rx packages
+// - and that's certainly a thing that has happened in the past to disastrous effect - they would end up
+// with circular type forwarders.)
+
 #if HAS_REMOTING
 #if HAS_REMOTING
 extern alias SystemReactiveNet;
 extern alias SystemReactiveNet;
 
 

+ 2 - 5
Rx.NET/Source/facades/System.Reactive/Obsolete/Remoting/Linq/QueryLanguage.Remoting.cs

@@ -2,11 +2,8 @@
 // The .NET Foundation licenses this file to you under the MIT License.
 // The .NET Foundation licenses this file to you under the MIT License.
 // See the LICENSE file in the project root for more information. 
 // See the LICENSE file in the project root for more information. 
 
 
-// TODO: does this belong in here or System.Reactive.Net?
-// We might be able to completely remove the net472 target from System.Reactive.Net, in which case this would have
-// to come out, but that does raise the question of where the thing should live. Back in System.Reactive.Runtime.Remoting?
-// Or does that risk creating circular type forwarders if versions get out of alignment?
-// We don't really want it to remain in System.Reactive since we're trying to deprecate this component.
+// See comment in Observable.Remoting.cs for why we build this code into System.Reactive, which is mostly
+// just a type forwarding legacy facade.
 
 
 #if HAS_REMOTING
 #if HAS_REMOTING
 extern alias SystemReactiveNet;
 extern alias SystemReactiveNet;

+ 6 - 0
Rx.NET/Source/facades/System.Reactive/Obsolete/UWP/Concurrency/ThreadPoolScheduler.Windows.cs

@@ -30,6 +30,12 @@ namespace System.Reactive.Concurrency
         [Obsolete("If you require the UWP-specific features of ThreadPoolScheduler use the UwpThreadPoolScheduler in the System.Reactive.For.Uwp package. Otherwise, use the Instance property, because this constructor will be removed in a future version (because UWP applications will end up with the same ThreadPoolScheduler as all other application types).")]
         [Obsolete("If you require the UWP-specific features of ThreadPoolScheduler use the UwpThreadPoolScheduler in the System.Reactive.For.Uwp package. Otherwise, use the Instance property, because this constructor will be removed in a future version (because UWP applications will end up with the same ThreadPoolScheduler as all other application types).")]
         public ThreadPoolScheduler()
         public ThreadPoolScheduler()
         {
         {
+            // The next step for obsolescence is to omit this constructor and all the other
+            // Obsolete methods when BUILDING_REFERENCE_ASSEMBLY is defined.
+            // That way, they will remain available at runtime, providing binary backwards compatibility,
+            // but it will force anyone building against the latest Rx to use the replacement
+            // UwpThreadPoolScheduler type.
+            // But we're not doing that yet, because we want an obsolete-but-available period.
         }
         }
 
 
         /// <summary>
         /// <summary>

+ 31 - 0
Rx.NET/Source/facades/System.Reactive/System.Reactive.csproj

@@ -155,4 +155,35 @@
     <ReferencePath Include="$(TargetPlatformSdkPath)UnionMetadata\10.0.19041.0\Windows.winmd" />
     <ReferencePath Include="$(TargetPlatformSdkPath)UnionMetadata\10.0.19041.0\Windows.winmd" />
   </ItemGroup>
   </ItemGroup>
 
 
+  <!--
+  Put the reference assemblies built by System.Reactive.MakeRefAssemblies into the 'ref' folder of our
+  NuGet package.
+  -->
+  <ItemGroup>
+    <ProjectReference Include="..\System.Reactive.MakeRefAssemblies\System.Reactive.MakeRefAssemblies.csproj" PrivateAssets="all">
+      <!--
+      If we don't set an alias here, all the types exposed by the reference assembly become available in the global namespace,
+      which causes compiler errors when the UAP target tries to build a specialized ThreadPoolScheduler.
+      -->
+      <Aliases>SystemReactiveRefAssembly</Aliases>
+    </ProjectReference>
+  </ItemGroup>
+
+  <!--
+  We need to supply our own nuspec file, because the SDK doesn't appear to be able to populate the <references> section,
+  and without that we get NU5131 warnings. (I think this is only strictly necessary for package.config scenarios, but
+  Rx has a lot of users, so we'll probably break someone if we don't get this right.)
+  We use tokenization so that we can pass package metadata (which include the version number). But it turns out that
+  the various NuGet package metadata build properties we want to pass in don't get defined until quite late in the build,
+  so we need to set <NuspecProperties> in a custom target that runs just before the GenerateNuspec target.
+  -->
+  <PropertyGroup>
+    <NuspecFile>System.Reactive.nuspec</NuspecFile>
+  </PropertyGroup>
+  <Target Name="_SetNuspecProperties" BeforeTargets="GenerateNuspec">
+    <PropertyGroup>
+      <NuspecProperties>id=$(PackageId);version=$(PackageVersion);authors=$(Authors);licenseExpression=$(PackageLicenseExpression);icon=$(PackageIcon);projectUrl=$(PackageProjectUrl);description=$(PackageDescription);copyright=$(Copyright);tags=$(PackageTags);repository=$(RepositoryUrl);commit=$(RepositoryCommit);outputpath=$(OutputPath);refassemblypath=..\System.Reactive.MakeRefAssemblies\bin\$(Configuration)\</NuspecProperties>
+    </PropertyGroup>
+  </Target>
+
 </Project>
 </Project>

+ 79 - 0
Rx.NET/Source/facades/System.Reactive/System.Reactive.nuspec

@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="utf-8"?>
+<package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd">
+  <metadata>
+    <id>$id$</id>
+    <version>$version$</version>
+    <authors>$authors$</authors>
+    <license type="expression">$licenseExpression$</license>
+    <icon>$icon$</icon>
+    <readme>readme.md</readme>
+    <projectUrl>$projectUrl$</projectUrl>
+    <description>$description$</description>
+    <copyright>$copyright$</copyright>
+    <tags>$tags$</tags>
+    <repository type="git" url="$repository$" commit="$commit$" />
+    <references>
+      <group targetFramework="net8.0">
+        <reference file="System.Reactive.dll" />
+      </group>
+      <group targetFramework="net8.0-windows10.0.19041">
+        <reference file="System.Reactive.dll" />
+      </group>
+      <group targetFramework="netstandard2.0">
+        <reference file="System.Reactive.dll" />
+      </group>
+      <group targetFramework="net472">
+        <reference file="System.Reactive.dll" />
+      </group>
+      <group targetFramework="uap10.0.18362">
+        <reference file="System.Reactive.dll" />
+      </group>
+    </references>
+    <dependencies>
+      <group targetFramework=".NETFramework4.7.2">
+        <dependency id="System.Threading.Tasks.Extensions" version="4.5.4" exclude="Build,Analyzers" />
+      </group>
+      <group targetFramework="net8.0" />
+      <group targetFramework="net8.0-windows10.0.19041" />
+      <group targetFramework=".NETStandard2.0">
+        <dependency id="System.Threading.Tasks.Extensions" version="4.5.4" exclude="Build,Analyzers" />
+      </group>
+      <group targetFramework="UAP10.0.18362">
+        <dependency id="System.Threading.Tasks.Extensions" version="4.5.4" exclude="Build,Analyzers" />
+      </group>
+    </dependencies>
+    <frameworkReferences>
+      <group targetFramework="net8.0" />
+      <group targetFramework="net8.0-windows10.0.19041">
+        <frameworkReference name="Microsoft.WindowsDesktop.App" />
+      </group>
+      <group targetFramework=".NETFramework4.7.2" />
+      <group targetFramework=".NETStandard2.0" />
+      <group targetFramework="UAP10.0.18362" />
+    </frameworkReferences>
+    <frameworkAssemblies>
+      <frameworkAssembly assemblyName="System.Windows" targetFramework=".NETFramework4.7.2" />
+      <frameworkAssembly assemblyName="System.Windows.Forms" targetFramework=".NETFramework4.7.2" />
+      <frameworkAssembly assemblyName="WindowsBase" targetFramework=".NETFramework4.7.2" />
+    </frameworkAssemblies>
+  </metadata>
+  <files>
+    <file src="$outputpath$net472\System.Reactive.dll" target="lib\net472\System.Reactive.dll" />
+    <file src="$outputpath$net8.0\System.Reactive.dll" target="lib\net8.0\System.Reactive.dll" />
+    <file src="$outputpath$net8.0-windows10.0.19041\System.Reactive.dll" target="lib\net8.0-windows10.0.19041\System.Reactive.dll" />
+    <file src="$outputpath$netstandard2.0\System.Reactive.dll" target="lib\netstandard2.0\System.Reactive.dll" />
+    <file src="$outputpath$uap10.0.18362\System.Reactive.dll" target="lib\uap10.0.18362\System.Reactive.dll" />
+    <file src="$refassemblypath$net472\System.Reactive.dll" target="ref\net472\System.Reactive.dll" />
+    <file src="$refassemblypath$net8.0\System.Reactive.dll" target="ref\net8.0\System.Reactive.dll" />
+    <file src="$refassemblypath$net8.0-windows10.0.19041\System.Reactive.dll" target="ref\net8.0-windows10.0.19041\System.Reactive.dll" />
+    <file src="$refassemblypath$netstandard2.0\System.Reactive.dll" target="ref\netstandard2.0\System.Reactive.dll" />
+    <file src="$refassemblypath$uap10.0.18362\System.Reactive.dll" target="ref\uap10.0.18362\System.Reactive.dll" />
+    <file src="..\..\..\Resources\Artwork\Logo.png" target="icon.png" />
+    <file src="..\NuGet.Facades.Readme.md" target="readme.md" />
+    <file src="$outputpath$net472\System.Reactive.pdb" target="lib\net472\System.Reactive.pdb" />
+    <file src="$outputpath$net8.0\System.Reactive.pdb" target="lib\net8.0\System.Reactive.pdb" />
+    <file src="$outputpath$net8.0-windows10.0.19041\System.Reactive.pdb" target="lib\net8.0-windows10.0.19041\System.Reactive.pdb" />
+    <file src="$outputpath$netstandard2.0\System.Reactive.pdb" target="lib\netstandard2.0\System.Reactive.pdb" />
+    <file src="$outputpath$uap10.0.18362\System.Reactive.pdb" target="lib\uap10.0.18362\System.Reactive.pdb" />
+  </files>
+</package>

+ 4 - 6
Rx.NET/Source/facades/System.Reactive/System/Reactive/Concurrency.cs

@@ -54,12 +54,9 @@ using System.Runtime.CompilerServices;
 [assembly:TypeForwardedToAttribute(typeof(VirtualTimeScheduler<,>))]
 [assembly:TypeForwardedToAttribute(typeof(VirtualTimeScheduler<,>))]
 [assembly:TypeForwardedToAttribute(typeof(VirtualTimeSchedulerExtensions))]
 [assembly:TypeForwardedToAttribute(typeof(VirtualTimeSchedulerExtensions))]
 
 
-// TODO: currently we've moved these three types into this assembly, with the intention of deprecating them all,
-// and preferring the newer types in the platform-specific packages.
-// An alternative would be to have the types retain their original names and live in those new packages without
-// deprecating them. This would enable us to avoid making working types obsolete which might reduce confusion.
-// It does remove the opportunity to fix up some naming issues, but maybe it would be better to live with that
-// to minimize disruption.
+// Seem comments in Reactive\Linq.cs for why we exclude forwarders for these types in some reference assemblies.
+#if !(BUILDING_REFERENCE_ASSEMBLY && NET8_0_OR_GREATER)
+
 #if WINDOWS
 #if WINDOWS
 [assembly:TypeForwardedToAttribute(typeof(System.Reactive.Concurrency.CoreDispatcherScheduler))]
 [assembly:TypeForwardedToAttribute(typeof(System.Reactive.Concurrency.CoreDispatcherScheduler))]
 #endif
 #endif
@@ -69,3 +66,4 @@ using System.Runtime.CompilerServices;
 #if HAS_DISPATCHER
 #if HAS_DISPATCHER
 [assembly:TypeForwardedToAttribute(typeof(System.Reactive.Concurrency.DispatcherScheduler))]
 [assembly:TypeForwardedToAttribute(typeof(System.Reactive.Concurrency.DispatcherScheduler))]
 #endif
 #endif
+#endif

+ 15 - 3
Rx.NET/Source/facades/System.Reactive/System/Reactive/Linq.cs

@@ -19,6 +19,20 @@ using System.Runtime.CompilerServices;
 [assembly:TypeForwardedToAttribute(typeof(QbservableEx))]
 [assembly:TypeForwardedToAttribute(typeof(QbservableEx))]
 [assembly:TypeForwardedToAttribute(typeof(QueryDebugger))]
 [assembly:TypeForwardedToAttribute(typeof(QueryDebugger))]
 
 
+// These UI-framework-specific types have been moved to the platform-specific packages. To maintain binary
+// compatibility we forward the types to the new packages. However, when building reference assemblies for
+// the netX.0-windows10.0.X target, we do not include these types in the reference assembly. We do this to
+// enable applications that target a Windows-specific .NET TFM to use Rx without needing to reference the
+// Microsoft.WindowsDesktop.App framework. If we don't hide the UI-framework-specific types, they become
+// visible to the compiler, which can then complain that it can't find the Windows Forms or WPF types
+// that these types use. (In particular, this becomes a problem for the types that add UI-framework-specific
+// extension methods such as ObserveOn(Control). Code that is trying to use the non-UI-framework-specific
+// overloads fails to compile because the compiler can't find the Control type, and so it doesn't have
+// the information it requires to be determine that the Control overloads is not applicable.) So we
+// exclude UI-framework-specific types from the .NET '-windows' reference assembly, but we keep the
+// forwarders in the runtime assembly.
+
+#if !(BUILDING_REFERENCE_ASSEMBLY && NET8_0_OR_GREATER)
 #if WINDOWS
 #if WINDOWS
 [assembly:TypeForwardedToAttribute(typeof(System.Reactive.Linq.AsyncInfoObservable))]
 [assembly:TypeForwardedToAttribute(typeof(System.Reactive.Linq.AsyncInfoObservable))]
 [assembly:TypeForwardedToAttribute(typeof(System.Reactive.Linq.CoreDispatcherObservable))]
 [assembly:TypeForwardedToAttribute(typeof(System.Reactive.Linq.CoreDispatcherObservable))]
@@ -30,6 +44,4 @@ using System.Runtime.CompilerServices;
 #if HAS_DISPATCHER
 #if HAS_DISPATCHER
 [assembly: TypeForwardedToAttribute(typeof(System.Reactive.Linq.DispatcherObservable))]
 [assembly: TypeForwardedToAttribute(typeof(System.Reactive.Linq.DispatcherObservable))]
 #endif
 #endif
-//#if HAS_REMOTING
-//[assembly: TypeForwardedTo(typeof(RemotingObservable))]
-//#endif
+#endif

+ 5 - 1
Rx.NET/Source/facades/System.Reactive/System/Reactive/Windows/Foundation.cs

@@ -2,11 +2,15 @@
 // The .NET Foundation licenses this file to you under the MIT License.
 // The .NET Foundation licenses this file to you under the MIT License.
 // See the LICENSE file in the project root for more information.
 // See the LICENSE file in the project root for more information.
 
 
-#if WINDOWS
+// Seem comments in Reactive\Linq.cs for why we exclude forwarders for these types in some reference assemblies.
+#if !(BUILDING_REFERENCE_ASSEMBLY && NET8_0_OR_GREATER)
 
 
+#if WINDOWS
 
 
 using System.Runtime.CompilerServices;
 using System.Runtime.CompilerServices;
 
 
 [assembly:TypeForwardedToAttribute(typeof(System.Reactive.Windows.Foundation.AsyncInfoObservableExtensions))]
 [assembly:TypeForwardedToAttribute(typeof(System.Reactive.Windows.Foundation.AsyncInfoObservableExtensions))]
 
 
 #endif
 #endif
+
+#endif

+ 5 - 2
Rx.NET/Source/src/System.Reactive.For.Uwp/System.Reactive.For.Uwp.csproj

@@ -48,8 +48,11 @@
   <ItemGroup>
   <ItemGroup>
     <Compile Include="..\AssemblyInfo.cs" Link="Properties\AssemblyInfo.cs" />
     <Compile Include="..\AssemblyInfo.cs" Link="Properties\AssemblyInfo.cs" />
     <Compile Include="..\System.Reactive.For.WindowsRuntime\AsyncInfoExtensions.cs" Link="AsyncInfoExtensions.cs" />
     <Compile Include="..\System.Reactive.For.WindowsRuntime\AsyncInfoExtensions.cs" Link="AsyncInfoExtensions.cs" />
-    <Compile Include="..\System.Reactive.Net\Concurrency\UserWorkItem.cs" Link="UserWorkItem.cs" />
-    <Compile Include="..\System.Reactive.Net\Diagnostics\CodeAnalysis\NullableAttributes.cs" Link="NullableAttributes.cs" />
+
+    <!--
+    Although System.Reactive.Net makes its internals available to us, we get the netstandard2.0 target when running
+    on UWP, which doesn't include this particular file, so we need to build our own copy.
+    -->
     <Compile Include="..\System.Reactive.Net\Internal\HostLifecycleNotifications.Windows.cs" Link="HostLifecycleNotifications.Windows.cs" />
     <Compile Include="..\System.Reactive.Net\Internal\HostLifecycleNotifications.Windows.cs" Link="HostLifecycleNotifications.Windows.cs" />
   </ItemGroup>
   </ItemGroup>
 
 

+ 1 - 1
Rx.NET/Source/version.json

@@ -1,5 +1,5 @@
 {
 {
-  "version": "7.0.0-preview-legacyfacade.{height}",
+  "version": "7.0.0-preview-legacyfacade-refnoui.{height}",
   "publicReleaseRefSpec": [
   "publicReleaseRefSpec": [
     "^refs/heads/main$", // we release out of main
     "^refs/heads/main$", // we release out of main
     "^refs/heads/rel/v\\d+\\.\\d+", // we also release branches starting with rel/vN.N
     "^refs/heads/rel/v\\d+\\.\\d+", // we also release branches starting with rel/vN.N