This commit is contained in:
neuecc 2024-02-15 17:13:16 +09:00
parent 4023a28e4f
commit 17ae2c400a
14 changed files with 114 additions and 140 deletions

View File

@ -15,5 +15,5 @@ jobs:
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- uses: Cysharp/Actions/.github/actions/setup-dotnet@main - uses: Cysharp/Actions/.github/actions/setup-dotnet@main
- run: dotnet build ObservableCollection.WithoutSandbox.slnf -c Debug - run: dotnet build -c Debug
- run: dotnet test ObservableCollection.WithoutSandbox.slnf -c Debug --no-build - run: dotnet test -c Debug --no-build

View File

@ -20,11 +20,11 @@ jobs:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- uses: Cysharp/Actions/.github/actions/setup-dotnet@main - uses: Cysharp/Actions/.github/actions/setup-dotnet@main
# build and pack # build and pack
- run: dotnet build ObservableCollection.WithoutSandbox.slnf -c Release -p:Version=${{ inputs.tag }} - run: dotnet build -c Release -p:Version=${{ inputs.tag }}
- run: dotnet test ObservableCollection.WithoutSandbox.slnf -c Release --no-build - run: dotnet test -c Release --no-build
- run: dotnet pack ObservableCollection.WithoutSandbox.slnf -c Release --no-build -p:Version=${{ inputs.tag }} -o ./publish - run: dotnet pack -c Release --no-build -p:Version=${{ inputs.tag }} -o ./publish
# Store artifacts. # Store artifacts.
- uses: actions/upload-artifact@v1 - uses: actions/upload-artifact@v2
with: with:
name: nuget name: nuget
path: ./publish/ path: ./publish/

View File

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@ -1,10 +0,0 @@
{
"solution": {
"path": "ObservableCollections.sln",
"projects": [
"src\\ObservableCollections\\ObservableCollections.csproj",
"tests\\ObservableCollections.Tests\\ObservableCollections.Tests.csproj",
"tools\\PostBuildUtility\\PostBuildUtility.csproj"
]
}
}

View File

@ -11,7 +11,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "sandbox", "sandbox", "{FD83
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WpfApp", "sandbox\WpfApp\WpfApp.csproj", "{4D937626-2CAE-4987-BFFA-BD53597F3338}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WpfApp", "sandbox\WpfApp\WpfApp.csproj", "{4D937626-2CAE-4987-BFFA-BD53597F3338}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConsoleApp", "sandbox\ConsoleApp\ConsoleApp.csproj", "{3F3A73AC-DA6E-4987-8AA9-9B1E226D3DD5}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConsoleApp", "sandbox\ConsoleApp\ConsoleApp.csproj", "{3F3A73AC-DA6E-4987-8AA9-9B1E226D3DD5}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlazorApp", "sandbox\BlazorApp\BlazorApp.csproj", "{7E10EF01-24DC-4346-8A18-F791BB5252A7}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlazorApp", "sandbox\BlazorApp\BlazorApp.csproj", "{7E10EF01-24DC-4346-8A18-F791BB5252A7}"
EndProject EndProject
@ -19,13 +19,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{B6D0425C
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ObservableCollections.Tests", "tests\ObservableCollections.Tests\ObservableCollections.Tests.csproj", "{B84027E4-9B39-4FB6-B888-C55CE4C79152}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ObservableCollections.Tests", "tests\ObservableCollections.Tests\ObservableCollections.Tests.csproj", "{B84027E4-9B39-4FB6-B888-C55CE4C79152}"
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tools", "tools", "{7133A3F7-B398-4DE0-8295-0F1ECFCC4CE4}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ObservableCollections.R3", "src\ObservableCollections.R3\ObservableCollections.R3.csproj", "{D5950521-C5B3-4B92-834E-3B12CDDD8DD6}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PostBuildUtility", "tools\PostBuildUtility\PostBuildUtility.csproj", "{29E3967D-89E9-494F-B1E6-9706B8F1CD57}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ObservableCollections.R3.Tests", "tests\ObservableCollections.R3.Tests\ObservableCollections.R3.Tests.csproj", "{1205F414-EE6D-49C6-9500-3E62E2120EAF}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ObservableCollections.R3", "src\ObservableCollections.R3\ObservableCollections.R3.csproj", "{D5950521-C5B3-4B92-834E-3B12CDDD8DD6}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ObservableCollections.R3.Tests", "tests\ObservableCollections.R3.Tests\ObservableCollections.R3.Tests.csproj", "{1205F414-EE6D-49C6-9500-3E62E2120EAF}"
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -53,10 +49,6 @@ Global
{B84027E4-9B39-4FB6-B888-C55CE4C79152}.Debug|Any CPU.Build.0 = Debug|Any CPU {B84027E4-9B39-4FB6-B888-C55CE4C79152}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B84027E4-9B39-4FB6-B888-C55CE4C79152}.Release|Any CPU.ActiveCfg = Release|Any CPU {B84027E4-9B39-4FB6-B888-C55CE4C79152}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B84027E4-9B39-4FB6-B888-C55CE4C79152}.Release|Any CPU.Build.0 = Release|Any CPU {B84027E4-9B39-4FB6-B888-C55CE4C79152}.Release|Any CPU.Build.0 = Release|Any CPU
{29E3967D-89E9-494F-B1E6-9706B8F1CD57}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{29E3967D-89E9-494F-B1E6-9706B8F1CD57}.Debug|Any CPU.Build.0 = Debug|Any CPU
{29E3967D-89E9-494F-B1E6-9706B8F1CD57}.Release|Any CPU.ActiveCfg = Release|Any CPU
{29E3967D-89E9-494F-B1E6-9706B8F1CD57}.Release|Any CPU.Build.0 = Release|Any CPU
{D5950521-C5B3-4B92-834E-3B12CDDD8DD6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D5950521-C5B3-4B92-834E-3B12CDDD8DD6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D5950521-C5B3-4B92-834E-3B12CDDD8DD6}.Debug|Any CPU.Build.0 = Debug|Any CPU {D5950521-C5B3-4B92-834E-3B12CDDD8DD6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D5950521-C5B3-4B92-834E-3B12CDDD8DD6}.Release|Any CPU.ActiveCfg = Release|Any CPU {D5950521-C5B3-4B92-834E-3B12CDDD8DD6}.Release|Any CPU.ActiveCfg = Release|Any CPU
@ -75,7 +67,6 @@ Global
{3F3A73AC-DA6E-4987-8AA9-9B1E226D3DD5} = {FD836539-75F1-4707-BCFF-751B95DAE19C} {3F3A73AC-DA6E-4987-8AA9-9B1E226D3DD5} = {FD836539-75F1-4707-BCFF-751B95DAE19C}
{7E10EF01-24DC-4346-8A18-F791BB5252A7} = {FD836539-75F1-4707-BCFF-751B95DAE19C} {7E10EF01-24DC-4346-8A18-F791BB5252A7} = {FD836539-75F1-4707-BCFF-751B95DAE19C}
{B84027E4-9B39-4FB6-B888-C55CE4C79152} = {B6D0425C-7902-4EFB-B0EA-99F164C20835} {B84027E4-9B39-4FB6-B888-C55CE4C79152} = {B6D0425C-7902-4EFB-B0EA-99F164C20835}
{29E3967D-89E9-494F-B1E6-9706B8F1CD57} = {7133A3F7-B398-4DE0-8295-0F1ECFCC4CE4}
{D5950521-C5B3-4B92-834E-3B12CDDD8DD6} = {8F60DC54-F617-4841-8C79-6B0137500D1C} {D5950521-C5B3-4B92-834E-3B12CDDD8DD6} = {8F60DC54-F617-4841-8C79-6B0137500D1C}
{1205F414-EE6D-49C6-9500-3E62E2120EAF} = {B6D0425C-7902-4EFB-B0EA-99F164C20835} {1205F414-EE6D-49C6-9500-3E62E2120EAF} = {B6D0425C-7902-4EFB-B0EA-99F164C20835}
EndGlobalSection EndGlobalSection

View File

@ -1,7 +1,7 @@
# ObservableCollections # ObservableCollections
[![GitHub Actions](https://github.com/Cysharp/ObservableCollections/workflows/Build-Debug/badge.svg)](https://github.com/Cysharp/ObservableCollections/actions) [![Releases](https://img.shields.io/github/release/Cysharp/ObservableCollections.svg)](https://github.com/Cysharp/ObservableCollections/releases) [![GitHub Actions](https://github.com/Cysharp/ObservableCollections/workflows/Build-Debug/badge.svg)](https://github.com/Cysharp/ObservableCollections/actions) [![Releases](https://img.shields.io/github/release/Cysharp/ObservableCollections.svg)](https://github.com/Cysharp/ObservableCollections/releases)
ObservableCollections is a high performance observable collections(`ObservableList<T>`, `ObservableDictionary<TKey, TValue>`, `ObservableHashSet<T>`, `ObservableQueue<T>`, `ObservableStack<T>`, `ObservableRingBuffer<T>`, `ObservableFixedSizeRingBuffer<T>`) with synchronized views. ObservableCollections is a high performance observable collections(`ObservableList<T>`, `ObservableDictionary<TKey, TValue>`, `ObservableHashSet<T>`, `ObservableQueue<T>`, `ObservableStack<T>`, `ObservableRingBuffer<T>`, `ObservableFixedSizeRingBuffer<T>`) with synchronized views and Observe Extension for [R3](https://github.com/Cysharp/R3).
.NET has [`ObservableCollection<T>`](https://docs.microsoft.com/en-us/dotnet/api/system.collections.objectmodel.observablecollection-1), however it has many lacks of features. .NET has [`ObservableCollection<T>`](https://docs.microsoft.com/en-us/dotnet/api/system.collections.objectmodel.observablecollection-1), however it has many lacks of features.
@ -46,6 +46,16 @@ SynchronizedView helps to separate between Model and View (ViewModel). We will u
ObservableCollections has not just a simple list, there are many more data structures. `ObservableList<T>`, `ObservableDictionary<TKey, TValue>`, `ObservableHashSet<T>`, `ObservableQueue<T>`, `ObservableStack<T>`, `ObservableRingBuffer<T>`, `ObservableFixedSizeRingBuffer<T>`. `RingBuffer`, especially `FixedSizeRingBuffer`, can be achieved with efficient performance when there is rotation (e.g., displaying up to 1000 logs, where old ones are deleted when new ones are added). Of course, the AddRange allows for efficient batch processing of large numbers of additions. ObservableCollections has not just a simple list, there are many more data structures. `ObservableList<T>`, `ObservableDictionary<TKey, TValue>`, `ObservableHashSet<T>`, `ObservableQueue<T>`, `ObservableStack<T>`, `ObservableRingBuffer<T>`, `ObservableFixedSizeRingBuffer<T>`. `RingBuffer`, especially `FixedSizeRingBuffer`, can be achieved with efficient performance when there is rotation (e.g., displaying up to 1000 logs, where old ones are deleted when new ones are added). Of course, the AddRange allows for efficient batch processing of large numbers of additions.
If you want to handle each change event with Rx, you can monitor it with the following method by combining it with [R3](https://github.com/Cysharp/R3):
```csharp
Observable<CollectionAddEvent<T>> IObservableCollection<T>.ObserveAdd()
Observable<CollectionRemoveEvent<T>> IObservableCollection<T>.ObserveRemove()
Observable<CollectionReplaceEvent<T>> IObservableCollection<T>.ObserveReplace()
Observable<CollectionMoveEvent<T>> IObservableCollection<T>.ObserveMove()
Observable<CollectionResetEvent<T>> IObservableCollection<T>.ObserveReset()
```
Getting Started Getting Started
--- ---
For .NET, use NuGet. For Unity, please read [Unity](#unity) section. For .NET, use NuGet. For Unity, please read [Unity](#unity) section.
@ -112,6 +122,30 @@ view.Dispose();
The basic idea behind using ObservableCollections is to create a View. In order to automate this pipeline, the view can be sortable, filtered, and have side effects on the values when they are changed. The basic idea behind using ObservableCollections is to create a View. In order to automate this pipeline, the view can be sortable, filtered, and have side effects on the values when they are changed.
Reactive Extensions with R3
---
Once the R3 extension package is installed, you can subscribe to `ObserveAdd`, `ObserveRemove`, `ObserveReplace`, `ObserveMove`, and `ObserveReset` events as Rx, allowing you to compose events individually.
PM> Install-Package [ObservableCollections.R3](https://www.nuget.org/packages/ObservableCollections.R3)
```csharp
using R3;
using ObservableCollections;
var list = new ObservableList<int>();
list.ObserveAdd()
.Subscribe(x =>
{
Console.WriteLine(x);
});
list.Add(10);
list.Add(20);
list.AddRange(new[] { 10, 20, 30 });
```
Since it is not supported by dotnet/reactive, please use the Rx library [R3](https://github.com/Cysharp/R3).
Blazor Blazor
--- ---
Since Blazor re-renders the whole thing by StateHasChanged, you may think that Observable collections are unnecessary. However, when you split it into Components, it is beneficial for Component confidence to detect the change and change its own State. Since Blazor re-renders the whole thing by StateHasChanged, you may think that Observable collections are unnecessary. However, when you split it into Components, it is beneficial for Component confidence to detect the change and change its own State.
@ -174,7 +208,7 @@ public partial class DataTable<T> : ComponentBase, IDisposable
WPF WPF
--- ---
Because of data binding in WPF, it is important that the collection is Observable. ObservableCollections high-performance `IObservableCollection<T>` cannot be bind to WPF. Call `WithINotifyCollectionChanged` to convert it to `INotifyCollectionChanged`. Also, although ObservableCollections and Views are thread-safe, the WPF UI does not support change notifications from different threads. `BindingOperations.EnableCollectionSynchronization` to work safely with change notifications from different threads. Because of data binding in WPF, it is important that the collection is Observable. ObservableCollections high-performance `IObservableCollection<T>` cannot be bind to WPF. Call `ToNotifyCollectionChanged()` to convert it to `INotifyCollectionChanged`. Also, although ObservableCollections and Views are thread-safe, the WPF UI does not support change notifications from different threads. `BindingOperations.EnableCollectionSynchronization` to work safely with change notifications from different threads.
```csharp ```csharp
// WPF simple sample. // WPF simple sample.
@ -188,7 +222,7 @@ public MainWindow()
this.DataContext = this; this.DataContext = this;
list = new ObservableList<int>(); list = new ObservableList<int>();
ItemsView = list.CreateView(x => x).WithINotifyCollectionChanged(); ItemsView = list.CreateView(x => x).ToNotifyCollectionChanged();
BindingOperations.EnableCollectionSynchronization(ItemsView, new object()); // for ui synchronization safety of viewmodel BindingOperations.EnableCollectionSynchronization(ItemsView, new object()); // for ui synchronization safety of viewmodel
} }
@ -203,9 +237,7 @@ protected override void OnClosed(EventArgs e)
Unity Unity
--- ---
In Unity projects, you can installing `ObservableCollections` with [NugetForUnity](https://github.com/GlitchEnzo/NuGetForUnity). If R3 integration is required, similarly install `ObservableCollections.R3` via NuGetForUnity.
In Unity projects, you can installing `ObservableCollections` with [NugetForUnity](https://github.com/GlitchEnzo/NuGetForUnity).
In Unity, ObservableCollections and Views are useful as CollectionManagers, since they need to convert T to Prefab for display. In Unity, ObservableCollections and Views are useful as CollectionManagers, since they need to convert T to Prefab for display.

View File

@ -9,7 +9,9 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\src\ObservableCollections.R3\ObservableCollections.R3.csproj" />
<ProjectReference Include="..\..\src\ObservableCollections\ObservableCollections.csproj" /> <ProjectReference Include="..\..\src\ObservableCollections\ObservableCollections.csproj" />
<PackageReference Include="R3" Version="0.1.23" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -1,7 +1,31 @@
using System; using System;
using R3;
using System.Linq; using System.Linq;
using ObservableCollections; using ObservableCollections;
var list = new ObservableList<int>();
list.ObserveAdd()
.Subscribe(x =>
{
Console.WriteLine(x);
});
list.Add(10);
list.Add(20);
list.AddRange(new[] { 10, 20, 30 });
return;
var models = new ObservableList<int>(Enumerable.Range(0, 10)); var models = new ObservableList<int>(Enumerable.Range(0, 10));
var viewModels = models.CreateView(x => new ViewModel var viewModels = models.CreateView(x => new ViewModel

View File

@ -1,15 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<OutputType>WinExe</OutputType> <OutputType>WinExe</OutputType>
<TargetFramework>net6.0-windows</TargetFramework> <TargetFramework>net6.0-windows</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<UseWPF>true</UseWPF> <UseWPF>true</UseWPF>
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>
</PropertyGroup> <EnableWindowsTargeting>true</EnableWindowsTargeting>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\src\ObservableCollections\ObservableCollections.csproj" /> <ProjectReference Include="..\..\src\ObservableCollections\ObservableCollections.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -1,22 +1,32 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>netstandard2.0;netstandard2.1;net6.0;net8.0</TargetFrameworks> <TargetFrameworks>netstandard2.0;netstandard2.1;net6.0;net8.0</TargetFrameworks>
<ImplicitUsings>disable</ImplicitUsings> <ImplicitUsings>disable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<LangVersion>12</LangVersion> <LangVersion>12</LangVersion>
</PropertyGroup>
<ItemGroup> <!-- NuGet Packaging -->
<PackageReference Include="PolySharp" Version="1.14.1"> <PackageTags>collection</PackageTags>
<PrivateAssets>all</PrivateAssets> <Description>R3 Extensions of ObservableCollections.</Description>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <SignAssembly>true</SignAssembly>
</PackageReference> <IsPackable>true</IsPackable>
<PackageReference Include="R3" Version="0.1.18" /> </PropertyGroup>
</ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\ObservableCollections\ObservableCollections.csproj" /> <PackageReference Include="PolySharp" Version="1.14.1">
</ItemGroup> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="R3" Version="0.1.23" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ObservableCollections\ObservableCollections.csproj" />
</ItemGroup>
<ItemGroup>
<None Include="../../Icon.png" Pack="true" PackagePath="/" />
<EmbeddedResource Include="..\..\LICENSE" />
</ItemGroup>
</Project> </Project>

View File

@ -18,6 +18,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="Icon.png" Pack="true" PackagePath="/" /> <None Include="../../Icon.png" Pack="true" PackagePath="/" />
<EmbeddedResource Include="..\..\LICENSE" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -10,7 +10,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="FluentAssertions" Version="6.12.0" /> <PackageReference Include="FluentAssertions" Version="6.12.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.0"/> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.0"/>
<PackageReference Include="R3" Version="0.1.18" /> <PackageReference Include="R3" Version="0.1.23" />
<PackageReference Include="xunit" Version="2.4.2"/> <PackageReference Include="xunit" Version="2.4.2"/>
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5"> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>

View File

@ -1,13 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="ConsoleAppFramework" Version="3.3.0" />
</ItemGroup>
</Project>

View File

@ -1,64 +0,0 @@
using ConsoleAppFramework;
using Microsoft.Extensions.Hosting;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace PostBuildUtility
{
class Program : ConsoleAppBase
{
static async Task Main(string[] args)
{
await Host.CreateDefaultBuilder().RunConsoleAppFrameworkAsync<Program>(args);
}
[Command("replace-to-unity")]
public void ReplaceToUnity([Option(0)] string directory)
{
var replaceSet = new Dictionary<string, string>
{
// Remove nullable
{"#nullable disable", "" },
{"where T : notnull", "" },
{"where TKey : notnull, IComparable<TKey>", "where TKey : IComparable<TKey>" }, // override project specified
{"where TKey : notnull", "" },
{">?", ">" }, // generics <T>?
{"T?", "T" },
{"T[]?", "T[]" },
{"default!", "default" },
{"null!", "null" },
// project specified
{"array!", "array" },
{"Current!", "Current" },
{"NotifyCollectionChangedEventHandler?", "NotifyCollectionChangedEventHandler" },
{"PropertyChangedEventHandler?", "PropertyChangedEventHandler" },
};
System.Console.WriteLine("Start to replace code, remove nullability.");
var noBomUtf8 = new UTF8Encoding(false);
foreach (var path in Directory.EnumerateFiles(directory, "*.cs", SearchOption.AllDirectories))
{
var text = File.ReadAllText(path, Encoding.UTF8);
var original = text;
foreach (var item in replaceSet)
{
text = text.Replace(item.Key, item.Value);
}
if (text != original)
{
Console.WriteLine("Replace Output:" + path);
File.WriteAllText(path, text, noBomUtf8);
}
}
System.Console.WriteLine("Replace complete.");
}
}
}