AddGo
This commit is contained in:
258
C#/source/.gitignore
vendored
258
C#/source/.gitignore
vendored
@@ -1,258 +0,0 @@
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
|
||||
# User-specific files
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
*.editorconfig
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
|
||||
# Visual Studio 2015 cache/options directory
|
||||
**/.vs/
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
# NUNIT
|
||||
*.VisualState.xml
|
||||
TestResult.xml
|
||||
|
||||
# Build Results of an ATL Project
|
||||
[Dd]ebugPS/
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
# DNX
|
||||
project.lock.json
|
||||
artifacts/
|
||||
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_i.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*.log
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Chutzpah Test files
|
||||
_Chutzpah*
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opendb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
*.VC.db
|
||||
*.VC.VC.opendb
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
*.sap
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# JustCode is a .NET coding add-in
|
||||
.JustCode
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# NCrunch
|
||||
_NCrunch_*
|
||||
.*crunch*.local.xml
|
||||
nCrunchTemp_*
|
||||
|
||||
# MightyMoose
|
||||
*.mm.*
|
||||
AutoTest.Net/
|
||||
|
||||
# Web workbench (sass)
|
||||
.sass-cache/
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
# TODO: Comment the next line if you want to checkin your web deploy settings
|
||||
# but database connection strings (with potential passwords) will be unencrypted
|
||||
*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||
# in these scripts will be unencrypted
|
||||
PublishScripts/
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
*.snupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/packages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/packages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/packages/repositories.config
|
||||
# NuGet v3's project.json files produces more ignoreable files
|
||||
*.nuget.props
|
||||
*.nuget.targets
|
||||
|
||||
# Microsoft Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Microsoft Azure Emulator
|
||||
ecf/
|
||||
rcf/
|
||||
|
||||
# Windows Store app package directories and files
|
||||
AppPackages/
|
||||
BundleArtifacts/
|
||||
Package.StoreAssociation.xml
|
||||
_pkginfo.txt
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!*.[Cc]ache/
|
||||
|
||||
# Others
|
||||
ClientBin/
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
node_modules/
|
||||
orleans.codegen.cs
|
||||
|
||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||
#bower_components/
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file
|
||||
# to a newer Visual Studio version. Backup files are not needed,
|
||||
# because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# GhostDoc plugin setting file
|
||||
*.GhostDoc.xml
|
||||
|
||||
# Node.js Tools for Visual Studio
|
||||
.ntvs_analysis.dat
|
||||
|
||||
# Visual Studio 6 build log
|
||||
*.plg
|
||||
|
||||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
|
||||
# Visual Studio LightSwitch build output
|
||||
**/*.HTMLClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/ModelManifest.xml
|
||||
**/*.Server/GeneratedArtifacts
|
||||
**/*.Server/ModelManifest.xml
|
||||
_Pvt_Extensions
|
||||
|
||||
# Paket dependency manager
|
||||
.paket/paket.exe
|
||||
paket-files/
|
||||
|
||||
# FAKE - F# Make
|
||||
.fake/
|
||||
|
||||
# JetBrains Rider
|
||||
.idea/
|
||||
*.sln.iml
|
||||
|
||||
|
||||
# macOS
|
||||
.DS_Store
|
||||
@@ -1,31 +0,0 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.31005.135
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yitter.IdGenerator", "Yitter.IdGenerator\Yitter.IdGenerator.csproj", "{FF8DAF11-34E7-4842-ADF2-3722A1A5FBB2}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yitter.IdGenTest", "Yitter.IdGenTest\Yitter.IdGenTest.csproj", "{67426F7D-0A3B-4645-B4D7-5487215D3E2B}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{FF8DAF11-34E7-4842-ADF2-3722A1A5FBB2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{FF8DAF11-34E7-4842-ADF2-3722A1A5FBB2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{FF8DAF11-34E7-4842-ADF2-3722A1A5FBB2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{FF8DAF11-34E7-4842-ADF2-3722A1A5FBB2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{67426F7D-0A3B-4645-B4D7-5487215D3E2B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{67426F7D-0A3B-4645-B4D7-5487215D3E2B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{67426F7D-0A3B-4645-B4D7-5487215D3E2B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{67426F7D-0A3B-4645-B4D7-5487215D3E2B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {5C87B69B-CE8D-411F-AFAF-298C7BC7C2EA}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -1,49 +0,0 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Yitter.IdGenerator;
|
||||
|
||||
namespace Yitter.OrgSystem.TestA
|
||||
{
|
||||
public class GenTest
|
||||
{
|
||||
private IIdGenerator IdGen;
|
||||
private Hashtable ids = new Hashtable();
|
||||
public IList<long> idList = new List<long>();
|
||||
private int GenIdCount;
|
||||
private int WorkerId;
|
||||
|
||||
|
||||
public GenTest(IIdGenerator idGen, int genIdCount, int workerId)
|
||||
{
|
||||
GenIdCount = genIdCount;
|
||||
IdGen = idGen;
|
||||
WorkerId = workerId;
|
||||
}
|
||||
|
||||
//public void GenId()
|
||||
//{
|
||||
// Thread t = new Thread(new ThreadStart(Gen1Start));
|
||||
// t.Start();
|
||||
//}
|
||||
|
||||
public void GenStart()
|
||||
{
|
||||
DateTime start = DateTime.Now;
|
||||
|
||||
for (int i = 0; i < GenIdCount; i++)
|
||||
{
|
||||
var id = IdGen.NewLong();
|
||||
//ids.Add(id, i);
|
||||
//idList.Add(id);
|
||||
}
|
||||
|
||||
DateTime end = DateTime.Now;
|
||||
Console.WriteLine($"++++++++++++++++++++++++++++++++++++++++WorkerId: {WorkerId}, total: {(end - start).TotalSeconds} s");
|
||||
Interlocked.Increment(ref Program.Count);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,172 +0,0 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using Yitter.IdGenerator;
|
||||
|
||||
namespace Yitter.OrgSystem.TestA
|
||||
{
|
||||
class Program
|
||||
{
|
||||
|
||||
// 测试参数(默认配置下,最佳性能是10W/s)
|
||||
static int genIdCount = 50000; // 计算ID数量(如果要验证50W效率,请将TopOverCostCount设置为20000或适当增加SeqBitLength)
|
||||
static short method = 1; // 1-漂移算法,2-传统算法
|
||||
|
||||
|
||||
static bool single = true;
|
||||
static bool outputLog = true;
|
||||
static IIdGenerator IdGen = null;
|
||||
static IList<GenTest> testList = new List<GenTest>();
|
||||
static bool checkResult = false;
|
||||
public static int Count = 0;
|
||||
static int workerCount = 1;
|
||||
|
||||
|
||||
static void Main(string[] args)
|
||||
{
|
||||
var options = new IdGeneratorOptions()
|
||||
{
|
||||
Method = method,
|
||||
WorkerId = 1,
|
||||
|
||||
//TopOverCostCount = 2000,
|
||||
//WorkerIdBitLength = 1,
|
||||
//SeqBitLength = 2,
|
||||
|
||||
//MinSeqNumber = 1,
|
||||
|
||||
// MaxSeqNumber = 200,
|
||||
|
||||
BaseTime = DateTime.Now.AddYears(-10),
|
||||
};
|
||||
|
||||
IIdGenerator IdGen = new DefaultIdGenerator(options);
|
||||
GenTest genTest = new GenTest(IdGen, genIdCount, options.WorkerId);
|
||||
|
||||
// 首先测试一下 IdHelper 方法,获取单个Id
|
||||
YitIdHelper.SetIdGenerator(options);
|
||||
long newId = YitIdHelper.NextId();
|
||||
Console.WriteLine("=====================================");
|
||||
Console.WriteLine("这是用方法 " + method + " 生成的 Id:" + newId);
|
||||
|
||||
while (true)
|
||||
{
|
||||
Go(options);
|
||||
Thread.Sleep(1000); // 每隔3秒执行一次Go
|
||||
Console.WriteLine("Hello World!");
|
||||
}
|
||||
}
|
||||
|
||||
private static void Go(IdGeneratorOptions options)
|
||||
{
|
||||
Count = 0;
|
||||
testList = new List<GenTest>();
|
||||
|
||||
// ++++++++++++++++++++++++++++++++
|
||||
if (single)
|
||||
{
|
||||
if (IdGen == null)
|
||||
{
|
||||
IdGen = new DefaultIdGenerator(options);
|
||||
}
|
||||
|
||||
if (outputLog)
|
||||
{
|
||||
IdGen.GenIdActionAsync = (arg =>
|
||||
{
|
||||
if (arg.ActionType == 1)
|
||||
{
|
||||
Console.WriteLine($">>>> {arg.WorkerId}:开始:{DateTime.Now.ToString("mm:ss:fff")}, 周期次序:{arg.TermIndex}");
|
||||
}
|
||||
else if (arg.ActionType == 2)
|
||||
{
|
||||
Console.WriteLine($"<<<< {arg.WorkerId}:结束:{DateTime.Now.ToString("mm:ss:fff")},漂移 {arg.OverCostCountInOneTerm} 次,产生 {arg.GenCountInOneTerm} 个, 周期次序:{arg.TermIndex}");
|
||||
}
|
||||
if (arg.ActionType == 8)
|
||||
{
|
||||
Console.WriteLine($"---- {arg.WorkerId}:AA结束:{DateTime.Now.ToString("mm:ss:fff")},时间回拨");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for (int i = 1; i < workerCount + 1; i++)
|
||||
{
|
||||
Console.WriteLine("Gen:" + i);
|
||||
var test = new GenTest(IdGen, genIdCount, i);
|
||||
testList.Add(test);
|
||||
// test.GenId();
|
||||
test.GenStart();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 1; i < workerCount + 1; i++)
|
||||
{
|
||||
IdGeneratorOptions newOptions = new IdGeneratorOptions()
|
||||
{
|
||||
WorkerId = (ushort)i, // workerId 不能设置为0
|
||||
WorkerIdBitLength = options.WorkerIdBitLength,
|
||||
SeqBitLength = options.SeqBitLength,
|
||||
MinSeqNumber = options.MinSeqNumber,
|
||||
MaxSeqNumber = options.MaxSeqNumber,
|
||||
Method = options.Method,
|
||||
};
|
||||
|
||||
Console.WriteLine("Gen:" + i);
|
||||
var idGen2 = new DefaultIdGenerator(newOptions);
|
||||
var test = new GenTest(idGen2, genIdCount, i);
|
||||
|
||||
if (outputLog)
|
||||
{
|
||||
idGen2.GenIdActionAsync = (arg =>
|
||||
{
|
||||
Console.WriteLine($"{DateTime.Now.ToString("mm:ss:fff")} {arg.WorkerId} 漂移了 {arg.OverCostCountInOneTerm}, 顺序:{arg.TermIndex}");
|
||||
});
|
||||
}
|
||||
|
||||
testList.Add(test);
|
||||
// test.GenId();
|
||||
test.GenStart();
|
||||
}
|
||||
}
|
||||
|
||||
while (Count < workerCount)
|
||||
{
|
||||
//Console.WriteLine("Count:" + Count);
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
//Console.WriteLine("Count:" + Count);
|
||||
|
||||
if (!checkResult)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var dupCount = 0;
|
||||
foreach (var id in testList[0].idList)
|
||||
{
|
||||
if (id == 0)
|
||||
{
|
||||
Console.WriteLine("############### 错误的ID:" + id + "###########");
|
||||
}
|
||||
|
||||
for (int j = 1; j < testList.Count; j++)
|
||||
{
|
||||
if (testList[j].idList.Contains(id))
|
||||
{
|
||||
dupCount++;
|
||||
Console.WriteLine("xxxxxxxxxx 重复的ID:" + id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dupCount > 0)
|
||||
{
|
||||
Console.WriteLine($"重复数量:{dupCount}");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Version>1.0.2</Version>
|
||||
<PackageProjectUrl>https://gitee.com/yitter/idgenerator</PackageProjectUrl>
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Yitter.IdGenerator\Yitter.IdGenerator.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,29 +0,0 @@
|
||||
/*
|
||||
* 版权属于:yitter(yitter@126.com)
|
||||
* 开源地址:https://gitee.com/yitter/idgenerator
|
||||
* 版权协议:MIT
|
||||
* 版权说明:只要保留本版权,你可以免费使用、修改、分发本代码。
|
||||
* 免责条款:任何因为本代码产生的系统、法律、政治、宗教问题,均与版权所有者无关。
|
||||
*
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace Yitter.IdGenerator
|
||||
{
|
||||
public interface IIdGenerator
|
||||
{
|
||||
/// <summary>
|
||||
/// 生成过程中产生的事件
|
||||
/// </summary>
|
||||
Action<OverCostActionArg> GenIdActionAsync { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 生成新的long型Id
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
long NewLong();
|
||||
|
||||
// Guid NewGuid();
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
/*
|
||||
* 版权属于:yitter(yitter@126.com)
|
||||
* 开源地址:https://gitee.com/yitter/idgenerator
|
||||
* 版权协议:MIT
|
||||
* 版权说明:只要保留本版权,你可以免费使用、修改、分发本代码。
|
||||
* 免责条款:任何因为本代码产生的系统、法律、政治、宗教问题,均与版权所有者无关。
|
||||
*
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Yitter.IdGenerator
|
||||
{
|
||||
internal interface ISnowWorker
|
||||
{
|
||||
Action<OverCostActionArg> GenAction { get; set; }
|
||||
|
||||
long NextId();
|
||||
}
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
/*
|
||||
* 版权属于:yitter(yitter@126.com)
|
||||
* 开源地址:https://gitee.com/yitter/idgenerator
|
||||
* 版权协议:MIT
|
||||
* 版权说明:只要保留本版权,你可以免费使用、修改、分发本代码。
|
||||
* 免责条款:任何因为本代码产生的系统、法律、政治、宗教问题,均与版权所有者无关。
|
||||
*
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Yitter.IdGenerator
|
||||
{
|
||||
public class IdGeneratorOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// 雪花计算方法
|
||||
/// (1-漂移算法|2-传统算法),默认1
|
||||
/// </summary>
|
||||
public virtual short Method { get; set; } = 1;
|
||||
|
||||
/// <summary>
|
||||
/// 开始时间(UTC格式)
|
||||
/// 不能超过当前系统时间
|
||||
/// </summary>
|
||||
public virtual DateTime BaseTime { get; set; } = new DateTime(2020, 2, 20, 2, 20, 2, 20, DateTimeKind.Utc);
|
||||
|
||||
/// <summary>
|
||||
/// 机器码
|
||||
/// 与 WorkerIdBitLength 有关系
|
||||
/// (ushort类型,最大值65535,如果有更高要求,请修改数据类型,或联系作者)
|
||||
/// </summary>
|
||||
public virtual ushort WorkerId { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 机器码位长
|
||||
/// 范围:1-21(要求:序列数位长+机器码位长不超过22)。
|
||||
/// 建议范围:6-12。
|
||||
/// </summary>
|
||||
public virtual byte WorkerIdBitLength { get; set; } = 6;//10;
|
||||
|
||||
/// <summary>
|
||||
/// 序列数位长
|
||||
/// 范围:2-21(要求:序列数位长+机器码位长不超过22)。
|
||||
/// 建议范围:6-14。
|
||||
/// </summary>
|
||||
public virtual byte SeqBitLength { get; set; } = 6;//10;
|
||||
|
||||
/// <summary>
|
||||
/// 最大序列数(含)
|
||||
/// (由SeqBitLength计算的最大值)
|
||||
/// </summary>
|
||||
public virtual int MaxSeqNumber { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 最小序列数(含)
|
||||
/// 默认5,不小于1,不大于MaxSeqNumber
|
||||
/// </summary>
|
||||
public virtual ushort MinSeqNumber { get; set; } = 5;
|
||||
|
||||
/// <summary>
|
||||
/// 最大漂移次数(含),
|
||||
/// 默认2000,推荐范围500-10000(与计算能力有关)
|
||||
/// </summary>
|
||||
public virtual int TopOverCostCount { get; set; } = 2000;
|
||||
|
||||
|
||||
public IdGeneratorOptions()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public IdGeneratorOptions(ushort workerId)
|
||||
{
|
||||
WorkerId = workerId;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
/*
|
||||
* 版权属于:yitter(yitter@126.com)
|
||||
* 开源地址:https://gitee.com/yitter/idgenerator
|
||||
* 版权协议:MIT
|
||||
* 版权说明:只要保留本版权,你可以免费使用、修改、分发本代码。
|
||||
* 免责条款:任何因为本代码产生的系统、法律、政治、宗教问题,均与版权所有者无关。
|
||||
*
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Yitter.IdGenerator
|
||||
{
|
||||
/// <summary>
|
||||
/// Id生成时回调参数
|
||||
/// </summary>
|
||||
public class OverCostActionArg
|
||||
{
|
||||
/// <summary>
|
||||
/// 事件类型
|
||||
/// 1-开始,2-结束,8-漂移
|
||||
/// </summary>
|
||||
public virtual int ActionType { get; set; }
|
||||
/// <summary>
|
||||
/// 时间戳
|
||||
/// </summary>
|
||||
public virtual long TimeTick { get; set; }
|
||||
/// <summary>
|
||||
/// 机器码
|
||||
/// </summary>
|
||||
public virtual ushort WorkerId { get; set; }
|
||||
/// <summary>
|
||||
/// 漂移计算次数
|
||||
/// </summary>
|
||||
public virtual int OverCostCountInOneTerm { get; set; }
|
||||
/// <summary>
|
||||
/// 漂移期间生产ID个数
|
||||
/// </summary>
|
||||
public virtual int GenCountInOneTerm { get; set; }
|
||||
/// <summary>
|
||||
/// 漂移周期
|
||||
/// </summary>
|
||||
public virtual int TermIndex { get; set; }
|
||||
|
||||
public OverCostActionArg(ushort workerId, long timeTick, int actionType = 0, int overCostCountInOneTerm = 0, int genCountWhenOverCost = 0, int index = 0)
|
||||
{
|
||||
ActionType = actionType;
|
||||
TimeTick = timeTick;
|
||||
WorkerId = workerId;
|
||||
OverCostCountInOneTerm = overCostCountInOneTerm;
|
||||
GenCountInOneTerm = genCountWhenOverCost;
|
||||
TermIndex = index;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,334 +0,0 @@
|
||||
/*
|
||||
* 版权属于:yitter(yitter@126.com)
|
||||
* 开源地址:https://gitee.com/yitter/idgenerator
|
||||
* 版权协议:MIT
|
||||
* 版权说明:只要保留本版权,你可以免费使用、修改、分发本代码。
|
||||
* 免责条款:任何因为本代码产生的系统、法律、政治、宗教问题,均与版权所有者无关。
|
||||
*
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Yitter.IdGenerator
|
||||
{
|
||||
/// <summary>
|
||||
/// 雪花漂移算法
|
||||
/// </summary>
|
||||
internal class SnowWorkerM1 : ISnowWorker
|
||||
{
|
||||
/// <summary>
|
||||
/// 基础时间
|
||||
/// </summary>
|
||||
protected readonly DateTime BaseTime;
|
||||
|
||||
/// <summary>
|
||||
/// 机器码
|
||||
/// </summary>
|
||||
protected readonly ushort WorkerId = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 机器码位长
|
||||
/// </summary>
|
||||
protected readonly byte WorkerIdBitLength = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 自增序列数位长
|
||||
/// </summary>
|
||||
protected readonly byte SeqBitLength = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 最大序列数(含)
|
||||
/// </summary>
|
||||
protected readonly int MaxSeqNumber = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 最小序列数(含)
|
||||
/// </summary>
|
||||
protected readonly ushort MinSeqNumber = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 最大漂移次数
|
||||
/// </summary>
|
||||
protected readonly int TopOverCostCount = 0;
|
||||
|
||||
protected readonly byte _TimestampShift = 0;
|
||||
protected static object _SyncLock = new object();
|
||||
|
||||
protected ushort _CurrentSeqNumber;
|
||||
protected long _LastTimeTick = -1L;
|
||||
protected long _TurnBackTimeTick = -1L;
|
||||
protected byte _TurnBackIndex = 0;
|
||||
|
||||
protected bool _IsOverCost = false;
|
||||
protected int _OverCostCountInOneTerm = 0;
|
||||
protected int _GenCountInOneTerm = 0;
|
||||
protected int _TermIndex = 0;
|
||||
|
||||
public Action<OverCostActionArg> GenAction { get; set; }
|
||||
|
||||
public SnowWorkerM1(IdGeneratorOptions options)
|
||||
{
|
||||
WorkerId = options.WorkerId;
|
||||
WorkerIdBitLength = options.WorkerIdBitLength;
|
||||
SeqBitLength = options.SeqBitLength;
|
||||
MaxSeqNumber = options.MaxSeqNumber;
|
||||
MinSeqNumber = options.MinSeqNumber;
|
||||
TopOverCostCount = options.TopOverCostCount;
|
||||
|
||||
if (options.BaseTime != DateTime.MinValue)
|
||||
{
|
||||
BaseTime = options.BaseTime;
|
||||
}
|
||||
|
||||
if (WorkerId < 1)
|
||||
{
|
||||
WorkerId = (ushort)DateTime.Now.Millisecond;
|
||||
}
|
||||
|
||||
if (SeqBitLength == 0)
|
||||
{
|
||||
SeqBitLength = 6;
|
||||
}
|
||||
|
||||
if (WorkerIdBitLength == 0)
|
||||
{
|
||||
WorkerIdBitLength = 6;
|
||||
}
|
||||
|
||||
if (MaxSeqNumber == 0)
|
||||
{
|
||||
MaxSeqNumber = (int)Math.Pow(2, SeqBitLength) - 1;
|
||||
}
|
||||
|
||||
_TimestampShift = (byte)(WorkerIdBitLength + SeqBitLength);
|
||||
_CurrentSeqNumber = options.MinSeqNumber;
|
||||
}
|
||||
|
||||
|
||||
private void DoGenIdAction(OverCostActionArg arg)
|
||||
{
|
||||
Task.Run(() =>
|
||||
{
|
||||
GenAction(arg);
|
||||
});
|
||||
}
|
||||
|
||||
private void BeginOverCostAction(in long useTimeTick)
|
||||
{
|
||||
if (GenAction == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
DoGenIdAction(new OverCostActionArg(
|
||||
WorkerId,
|
||||
useTimeTick,
|
||||
1,
|
||||
_OverCostCountInOneTerm,
|
||||
_GenCountInOneTerm,
|
||||
_TermIndex));
|
||||
}
|
||||
|
||||
private void EndOverCostAction(in long useTimeTick)
|
||||
{
|
||||
if (_TermIndex > 10000)
|
||||
{
|
||||
_TermIndex = 0;
|
||||
}
|
||||
|
||||
if (GenAction == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
DoGenIdAction(new OverCostActionArg(
|
||||
WorkerId,
|
||||
useTimeTick,
|
||||
2,
|
||||
_OverCostCountInOneTerm,
|
||||
_GenCountInOneTerm,
|
||||
_TermIndex));
|
||||
}
|
||||
|
||||
private void BeginTurnBackAction(in long useTimeTick)
|
||||
{
|
||||
if (GenAction == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
DoGenIdAction(new OverCostActionArg(
|
||||
WorkerId,
|
||||
useTimeTick,
|
||||
8,
|
||||
0,
|
||||
0,
|
||||
_TurnBackIndex));
|
||||
}
|
||||
|
||||
private void EndTurnBackAction(in long useTimeTick)
|
||||
{
|
||||
if (GenAction == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
DoGenIdAction(new OverCostActionArg(
|
||||
WorkerId,
|
||||
useTimeTick,
|
||||
9,
|
||||
0,
|
||||
0,
|
||||
_TurnBackIndex));
|
||||
}
|
||||
|
||||
private long NextOverCostId()
|
||||
{
|
||||
long currentTimeTick = GetCurrentTimeTick();
|
||||
|
||||
if (currentTimeTick > _LastTimeTick)
|
||||
{
|
||||
EndOverCostAction(currentTimeTick);
|
||||
|
||||
_LastTimeTick = currentTimeTick;
|
||||
_CurrentSeqNumber = MinSeqNumber;
|
||||
_IsOverCost = false;
|
||||
_OverCostCountInOneTerm = 0;
|
||||
_GenCountInOneTerm = 0;
|
||||
|
||||
return CalcId(_LastTimeTick);
|
||||
}
|
||||
|
||||
if (_OverCostCountInOneTerm >= TopOverCostCount)
|
||||
{
|
||||
EndOverCostAction(currentTimeTick);
|
||||
|
||||
_LastTimeTick = GetNextTimeTick();
|
||||
_CurrentSeqNumber = MinSeqNumber;
|
||||
_IsOverCost = false;
|
||||
_OverCostCountInOneTerm = 0;
|
||||
_GenCountInOneTerm = 0;
|
||||
|
||||
return CalcId(_LastTimeTick);
|
||||
}
|
||||
|
||||
if (_CurrentSeqNumber > MaxSeqNumber)
|
||||
{
|
||||
_LastTimeTick++;
|
||||
_CurrentSeqNumber = MinSeqNumber;
|
||||
_IsOverCost = true;
|
||||
_OverCostCountInOneTerm++;
|
||||
_GenCountInOneTerm++;
|
||||
|
||||
return CalcId(_LastTimeTick);
|
||||
}
|
||||
|
||||
_GenCountInOneTerm++;
|
||||
return CalcId(_LastTimeTick);
|
||||
}
|
||||
|
||||
private long NextNormalId()
|
||||
{
|
||||
long currentTimeTick = GetCurrentTimeTick();
|
||||
|
||||
if (currentTimeTick < _LastTimeTick)
|
||||
{
|
||||
if (_TurnBackTimeTick < 1)
|
||||
{
|
||||
_TurnBackTimeTick = _LastTimeTick - 1;
|
||||
_TurnBackIndex++;
|
||||
|
||||
// 每毫秒序列数的前5位是预留位,0用于手工新值,1-4是时间回拨次序
|
||||
// 最多4次回拨(防止回拨重叠)
|
||||
if (_TurnBackIndex > 4)
|
||||
{
|
||||
_TurnBackIndex = 1;
|
||||
}
|
||||
|
||||
BeginTurnBackAction(_TurnBackTimeTick);
|
||||
}
|
||||
|
||||
Thread.Sleep(10);
|
||||
return CalcTurnBackId(_TurnBackTimeTick);
|
||||
}
|
||||
|
||||
// 时间追平时,_TurnBackTimeTick清零
|
||||
if (_TurnBackTimeTick > 0)
|
||||
{
|
||||
EndTurnBackAction(_TurnBackTimeTick);
|
||||
_TurnBackTimeTick = 0;
|
||||
}
|
||||
|
||||
if (currentTimeTick > _LastTimeTick)
|
||||
{
|
||||
_LastTimeTick = currentTimeTick;
|
||||
_CurrentSeqNumber = MinSeqNumber;
|
||||
|
||||
return CalcId(_LastTimeTick);
|
||||
}
|
||||
|
||||
if (_CurrentSeqNumber > MaxSeqNumber)
|
||||
{
|
||||
BeginOverCostAction(currentTimeTick);
|
||||
|
||||
_TermIndex++;
|
||||
_LastTimeTick++;
|
||||
_CurrentSeqNumber = MinSeqNumber;
|
||||
_IsOverCost = true;
|
||||
_OverCostCountInOneTerm = 1;
|
||||
_GenCountInOneTerm = 1;
|
||||
|
||||
return CalcId(_LastTimeTick);
|
||||
}
|
||||
|
||||
return CalcId(_LastTimeTick);
|
||||
}
|
||||
|
||||
private long CalcId(in long useTimeTick)
|
||||
{
|
||||
var result = ((useTimeTick << _TimestampShift) +
|
||||
((long)WorkerId << SeqBitLength) +
|
||||
(uint)_CurrentSeqNumber);
|
||||
|
||||
_CurrentSeqNumber++;
|
||||
return result;
|
||||
}
|
||||
|
||||
private long CalcTurnBackId(in long useTimeTick)
|
||||
{
|
||||
var result = ((useTimeTick << _TimestampShift) +
|
||||
((long)WorkerId << SeqBitLength) + _TurnBackIndex);
|
||||
|
||||
_TurnBackTimeTick--;
|
||||
return result;
|
||||
}
|
||||
|
||||
protected virtual long GetCurrentTimeTick()
|
||||
{
|
||||
return (long)(DateTime.UtcNow - BaseTime).TotalMilliseconds;
|
||||
}
|
||||
|
||||
protected virtual long GetNextTimeTick()
|
||||
{
|
||||
long tempTimeTicker = GetCurrentTimeTick();
|
||||
|
||||
while (tempTimeTicker <= _LastTimeTick)
|
||||
{
|
||||
tempTimeTicker = GetCurrentTimeTick();
|
||||
}
|
||||
|
||||
return tempTimeTicker;
|
||||
}
|
||||
|
||||
|
||||
public virtual long NextId()
|
||||
{
|
||||
lock (_SyncLock)
|
||||
{
|
||||
return _IsOverCost ? NextOverCostId() : NextNormalId();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
* 版权属于:yitter(yitter@126.com)
|
||||
* 开源地址:https://gitee.com/yitter/idgenerator
|
||||
* 版权协议:MIT
|
||||
* 版权说明:只要保留本版权,你可以免费使用、修改、分发本代码。
|
||||
* 免责条款:任何因为本代码产生的系统、法律、政治、宗教问题,均与版权所有者无关。
|
||||
*
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Yitter.IdGenerator
|
||||
{
|
||||
/// <summary>
|
||||
/// 常规雪花算法
|
||||
/// </summary>
|
||||
internal class SnowWorkerM2 : SnowWorkerM1
|
||||
{
|
||||
public SnowWorkerM2(IdGeneratorOptions options) : base(options)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override long NextId()
|
||||
{
|
||||
lock (_SyncLock)
|
||||
{
|
||||
long currentTimeTick = GetCurrentTimeTick();
|
||||
|
||||
if (_LastTimeTick == currentTimeTick)
|
||||
{
|
||||
if (_CurrentSeqNumber++ > MaxSeqNumber)
|
||||
{
|
||||
_CurrentSeqNumber = MinSeqNumber;
|
||||
currentTimeTick = GetNextTimeTick();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_CurrentSeqNumber = MinSeqNumber;
|
||||
}
|
||||
|
||||
if (currentTimeTick < _LastTimeTick)
|
||||
{
|
||||
throw new Exception(string.Format("Time error for {0} milliseconds", _LastTimeTick - currentTimeTick));
|
||||
}
|
||||
|
||||
_LastTimeTick = currentTimeTick;
|
||||
var result = ((currentTimeTick << _TimestampShift) + ((long)WorkerId << SeqBitLength) + (uint)_CurrentSeqNumber);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
/*
|
||||
* 版权属于:yitter(yitter@126.com)
|
||||
* 开源地址:https://gitee.com/yitter/idgenerator
|
||||
* 版权协议:MIT
|
||||
* 版权说明:只要保留本版权,你可以免费使用、修改、分发本代码。
|
||||
* 免责条款:任何因为本代码产生的系统、法律、政治、宗教问题,均与版权所有者无关。
|
||||
*
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace Yitter.IdGenerator
|
||||
{
|
||||
/// <summary>
|
||||
/// 默认实现
|
||||
/// </summary>
|
||||
public class DefaultIdGenerator : IIdGenerator
|
||||
{
|
||||
private ISnowWorker _SnowWorker { get; set; }
|
||||
|
||||
public Action<OverCostActionArg> GenIdActionAsync
|
||||
{
|
||||
get => _SnowWorker.GenAction;
|
||||
set => _SnowWorker.GenAction = value;
|
||||
}
|
||||
|
||||
|
||||
public DefaultIdGenerator(IdGeneratorOptions options)
|
||||
{
|
||||
if (options == null)
|
||||
{
|
||||
throw new ApplicationException("options error.");
|
||||
}
|
||||
|
||||
if (options.BaseTime < DateTime.Now.AddYears(-50) || options.BaseTime > DateTime.Now)
|
||||
{
|
||||
throw new ApplicationException("BaseTime error.");
|
||||
}
|
||||
|
||||
if (options.SeqBitLength + options.WorkerIdBitLength > 22)
|
||||
{
|
||||
throw new ApplicationException("error:WorkerIdBitLength + SeqBitLength <= 22");
|
||||
}
|
||||
|
||||
var maxWorkerIdNumber = Math.Pow(2, options.WorkerIdBitLength) - 1;
|
||||
if (options.WorkerId < 0 || options.WorkerId > maxWorkerIdNumber)
|
||||
{
|
||||
throw new ApplicationException("WorkerId error. (range:[1, " + maxWorkerIdNumber + "]");
|
||||
}
|
||||
|
||||
if (options.SeqBitLength < 2 || options.SeqBitLength > 21)
|
||||
{
|
||||
throw new ApplicationException("SeqBitLength error. (range:[2, 21])");
|
||||
}
|
||||
|
||||
var maxSeqNumber = Math.Pow(2, options.SeqBitLength) - 1;
|
||||
if (options.MaxSeqNumber < 0 || options.MaxSeqNumber > maxSeqNumber)
|
||||
{
|
||||
throw new ApplicationException("MaxSeqNumber error. (range:[1, " + maxSeqNumber + "]");
|
||||
}
|
||||
|
||||
var maxValue = maxSeqNumber; // maxSeqNumber - 1;
|
||||
if (options.MinSeqNumber < 1 || options.MinSeqNumber > maxValue)
|
||||
{
|
||||
throw new ApplicationException("MinSeqNumber error. (range:[1, " + maxValue + "]");
|
||||
}
|
||||
|
||||
switch (options.Method)
|
||||
{
|
||||
case 1:
|
||||
_SnowWorker = new SnowWorkerM1(options);
|
||||
break;
|
||||
case 2:
|
||||
_SnowWorker = new SnowWorkerM2(options);
|
||||
break;
|
||||
default:
|
||||
_SnowWorker = new SnowWorkerM1(options);
|
||||
break;
|
||||
}
|
||||
|
||||
if (options.Method == 1)
|
||||
{
|
||||
Thread.Sleep(500);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public long NewLong()
|
||||
{
|
||||
return _SnowWorker.NextId();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
/*
|
||||
* 版权属于:yitter(yitter@126.com)
|
||||
* 开源地址:https://gitee.com/yitter/idgenerator
|
||||
* 版权协议:MIT
|
||||
* 版权说明:只要保留本版权,你可以免费使用、修改、分发本代码。
|
||||
* 免责条款:任何因为本代码产生的系统、法律、政治、宗教问题,均与版权所有者无关。
|
||||
*
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Yitter.IdGenerator
|
||||
{
|
||||
/// <summary>
|
||||
/// 这是一个调用的例子,默认情况下,单机集成者可以直接使用 NextId()。
|
||||
/// </summary>
|
||||
public class YitIdHelper
|
||||
{
|
||||
private static IIdGenerator _IdGenInstance = null;
|
||||
|
||||
public static IIdGenerator IdGenInstance => _IdGenInstance;
|
||||
|
||||
/// <summary>
|
||||
/// 设置参数,建议程序初始化时执行一次
|
||||
/// </summary>
|
||||
/// <param name="options"></param>
|
||||
public static void SetIdGenerator(IdGeneratorOptions options)
|
||||
{
|
||||
_IdGenInstance = new DefaultIdGenerator(options);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 生成新的Id
|
||||
/// 调用本方法前,请确保调用了 SetIdGenerator 方法做初始化。
|
||||
/// 否则将会初始化一个WorkerId为1的对象。
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static long NextId()
|
||||
{
|
||||
if (_IdGenInstance == null)
|
||||
{
|
||||
_IdGenInstance = new DefaultIdGenerator(
|
||||
new IdGeneratorOptions() { WorkerId = 1 }
|
||||
);
|
||||
}
|
||||
|
||||
return _IdGenInstance.NewLong();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||
<Description>Shorter ID and faster generation with a new snowflake drift algorithm. The core is to shorten the ID length, but also can have a very high instantaneous concurrent processing capacity (50W/0.1s), and powerful configuration capacity.
|
||||
|
||||
一种全新的雪花漂移算法,让ID更短、生成速度更快。 核心在于缩短ID长度的同时,还能拥有极高瞬时并发处理量(50W/0.1s),及强大的配置能力。</Description>
|
||||
<AssemblyName>Yitter.IdGenerator</AssemblyName>
|
||||
<RootNamespace>Yitter.IdGenerator</RootNamespace>
|
||||
<Product>IdGenerator</Product>
|
||||
<Company>Yitter</Company>
|
||||
<Authors>Yitter</Authors>
|
||||
<Copyright>Yitter</Copyright>
|
||||
<PackageProjectUrl>https://gitee.com/yitter/idgenerator</PackageProjectUrl>
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
<Version>1.0.8</Version>
|
||||
<PackageReleaseNotes></PackageReleaseNotes>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<WarningLevel>5</WarningLevel>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
Reference in New Issue
Block a user