From e4d5412eb66de003cfc88376b615fe73fd2f6f2f Mon Sep 17 00:00:00 2001 From: walterlv Date: Thu, 1 Jun 2023 19:59:26 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8A=A0=E4=B8=8A=20dotnetCampus.LatestCsharpF?= =?UTF-8?q?eatures.Source?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Directory.Build.props | 2 +- build/Version.props | 2 +- .../IsExternalInit.cs | 2 +- .../dotnetCampus.IsExternalInit.Source.csproj | 4 +- .../Class1.cs | 5 - .../IsExternalInit.cs | 19 ++ .../Nullable.cs | 193 ++++++++++++++++++ .../RequiredMemberAttribute.cs | 48 +++++ .../SetsRequiredMembersAttribute.cs | 16 ++ ...tCampus.LatestCsharpFeatures.Source.csproj | 9 +- .../dotnetCampus.Nullable.Source.csproj | 2 +- .../dotnetCampus.Required.Source.csproj | 2 +- 12 files changed, 291 insertions(+), 13 deletions(-) delete mode 100644 src/dotnetCampus.LatestCsharpFeatures.Source/Class1.cs create mode 100644 src/dotnetCampus.LatestCsharpFeatures.Source/IsExternalInit.cs create mode 100644 src/dotnetCampus.LatestCsharpFeatures.Source/Nullable.cs create mode 100644 src/dotnetCampus.LatestCsharpFeatures.Source/RequiredMemberAttribute.cs create mode 100644 src/dotnetCampus.LatestCsharpFeatures.Source/SetsRequiredMembersAttribute.cs diff --git a/Directory.Build.props b/Directory.Build.props index d5b246d..8342cc2 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -20,7 +20,7 @@ - + \ No newline at end of file diff --git a/build/Version.props b/build/Version.props index 3af3bad..a8ad5ed 100644 --- a/build/Version.props +++ b/build/Version.props @@ -1,5 +1,5 @@ - 0.0.0-alpha01 + 0.0.1-alpha01 \ No newline at end of file diff --git a/src/dotnetCampus.IsExternalInit.Source/IsExternalInit.cs b/src/dotnetCampus.IsExternalInit.Source/IsExternalInit.cs index 59b4b37..b861dfd 100644 --- a/src/dotnetCampus.IsExternalInit.Source/IsExternalInit.cs +++ b/src/dotnetCampus.IsExternalInit.Source/IsExternalInit.cs @@ -12,7 +12,7 @@ namespace System.Runtime.CompilerServices /// This dummy class is required to compile records when targeting .NET Standard /// [EditorBrowsable(EditorBrowsableState.Never)] - public static class IsExternalInit + internal static class IsExternalInit { } } diff --git a/src/dotnetCampus.IsExternalInit.Source/dotnetCampus.IsExternalInit.Source.csproj b/src/dotnetCampus.IsExternalInit.Source/dotnetCampus.IsExternalInit.Source.csproj index 6c6ca87..f2c03bf 100644 --- a/src/dotnetCampus.IsExternalInit.Source/dotnetCampus.IsExternalInit.Source.csproj +++ b/src/dotnetCampus.IsExternalInit.Source/dotnetCampus.IsExternalInit.Source.csproj @@ -1,4 +1,4 @@ - + net5.0;netcoreapp3.0;netstandard1.0;net40 @@ -9,7 +9,7 @@ - + \ No newline at end of file diff --git a/src/dotnetCampus.LatestCsharpFeatures.Source/Class1.cs b/src/dotnetCampus.LatestCsharpFeatures.Source/Class1.cs deleted file mode 100644 index cbeefb4..0000000 --- a/src/dotnetCampus.LatestCsharpFeatures.Source/Class1.cs +++ /dev/null @@ -1,5 +0,0 @@ -namespace dotnetCampus.LatestCsharpFeatures.Source; -public class Class1 -{ - -} diff --git a/src/dotnetCampus.LatestCsharpFeatures.Source/IsExternalInit.cs b/src/dotnetCampus.LatestCsharpFeatures.Source/IsExternalInit.cs new file mode 100644 index 0000000..b861dfd --- /dev/null +++ b/src/dotnetCampus.LatestCsharpFeatures.Source/IsExternalInit.cs @@ -0,0 +1,19 @@ +#if NET5_0_OR_GREATER +// .NET 5.0 开始已包含 IsExternalInit。 +#else +// 旧框架需要包含 IsExternalInit。 +using System.ComponentModel; + +namespace System.Runtime.CompilerServices +{ + /// + /// Reserved to be used by the compiler for tracking metadata. + /// This class should not be used by developers in source code. + /// This dummy class is required to compile records when targeting .NET Standard + /// + [EditorBrowsable(EditorBrowsableState.Never)] + internal static class IsExternalInit + { + } +} +#endif \ No newline at end of file diff --git a/src/dotnetCampus.LatestCsharpFeatures.Source/Nullable.cs b/src/dotnetCampus.LatestCsharpFeatures.Source/Nullable.cs new file mode 100644 index 0000000..d5e0c72 --- /dev/null +++ b/src/dotnetCampus.LatestCsharpFeatures.Source/Nullable.cs @@ -0,0 +1,193 @@ +namespace System.Diagnostics.CodeAnalysis +{ +#if NETCOREAPP3_0 || NETCOREAPP3_1 || NET5_0_OR_GREATER + // 新框架都包含基本的 Nullable Attributes。 +#else + /// + /// 标记一个不可空的输入实际上是可以传入 null 的。 + /// + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)] + internal sealed class AllowNullAttribute : Attribute { } + + /// + /// 标记一个可空的输入实际上不应该传入 null。 + /// + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)] + internal sealed class DisallowNullAttribute : Attribute { } + + /// + /// 标记一个非空的返回值实际上可能会返回 null,返回值包括输出参数。 + /// + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)] + internal sealed class MaybeNullAttribute : Attribute { } + + /// + /// 标记一个可空的返回值实际上是不可能返回 null 的,返回值包括输出参数。 + /// + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)] + internal sealed class NotNullAttribute : Attribute { } + + /// + /// 当返回指定的 true/false 时某个输出参数才可能为 null,而返回相反的值时那个输出参数则不可为 null。 + /// + [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] + internal sealed class MaybeNullWhenAttribute : Attribute + { + /// + /// 使用 true 或者 false 决定输出参数是否可能为 null。 + /// + /// 如果方法返回值等于这个值,那么输出参数则可能为 null,否则输出参数是不可为 null 的。 + public MaybeNullWhenAttribute(bool returnValue) => ReturnValue = returnValue; + + /// + /// 获取返回值决定是否可为空的那个判断值。 + /// + public bool ReturnValue { get; } + } + + /// + /// 当返回指定的 true/false 时,某个输出参数不可为 null,而返回相反的值时那个输出参数则可能为 null。 + /// + [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] + internal sealed class NotNullWhenAttribute : Attribute + { + /// + /// 使用 true 或者 false 决定输出参数是否不可为 null。 + /// + /// + /// 如果方法或属性的返回值等于这个值,那么输出参数则不可为 null,否则输出参数是可能为 null 的。 + /// + public NotNullWhenAttribute(bool returnValue) => ReturnValue = returnValue; + + /// + /// 获取返回值决定是否不可为空的那个判断值。 + /// + public bool ReturnValue { get; } + } + + /// + /// 指定的参数传入 null 时才可能返回 null,指定的参数传入非 null 时就不可能返回 null。 + /// + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, AllowMultiple = true, Inherited = false)] + internal sealed class NotNullIfNotNullAttribute : Attribute + { + /// + /// 使用一个参数名称决定返回值是否可能为 null。 + /// + /// + /// 指定一个方法传入参数的名称,当这个参数传入非 null 时,输出参数或者返回值就是非 null;而这个参数传入可为 null 时,输出参数或者返回值就可为 null。 + /// + public NotNullIfNotNullAttribute(string parameterName) => ParameterName = parameterName; + + /// + /// 获取决定输出参数或者返回值是否可能为空的那个参数名称。 + /// + public string ParameterName { get; } + } + + /// + /// 指定一个方法是不可能返回的。 + /// + [AttributeUsage(AttributeTargets.Method, Inherited = false)] + internal sealed class DoesNotReturnAttribute : Attribute { } + + /// + /// 在方法的输入参数上指定一个条件,当这个参数传入了指定的 true/false 时方法不可能返回。 + /// + [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] + internal sealed class DoesNotReturnIfAttribute : Attribute + { + /// + /// 使用 true/false 决定方法是否可能返回。 + /// + /// + /// 在方法的输入参数上指定一个条件,当这个参数传入的值等于这里设定的值时,方法不可能返回。 + /// + public DoesNotReturnIfAttribute(bool parameterValue) => ParameterValue = parameterValue; + + /// + /// 获取决定方法是否可返回的那个参数的值。 + /// + public bool ParameterValue { get; } + } +#endif + +#if NET5_0_OR_GREATER + // .NET 5.0 开始已包含更多 Nullable Attributes。 +#else + /// + /// 调用了此方法后,即可保证列表中所列出的字段和属性成员将不会为 null。 + /// + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] + internal sealed class MemberNotNullAttribute : Attribute + { + /// + /// 指定调用了此方法后,所列出的字段和属性成员将不会为 null。 + /// + /// + /// 将保证不会为 null 的字段或属性名称。 + /// + public MemberNotNullAttribute(string member) => Members = new[] { member }; + + /// + /// 指定调用了此方法后,所列出的字段和属性成员将不会为 null。 + /// + /// + /// 将保证不会为 null 的字段或属性名称列表。 + /// + public MemberNotNullAttribute(params string[] members) => Members = members; + + /// + /// 调用了此方法后保证不会为 null 的字段或属性名称列表。 + /// + public string[] Members { get; } + } + + /// + /// 当返回指定的 true/false 时,即可保证列表中所列出的字段和属性成员将不会为 null。 + /// + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] + internal sealed class MemberNotNullWhenAttribute : Attribute + { + /// + /// 使用 true 或者 false 决定是否所列出的字段和属性成员将不会为 null。 + /// + /// + /// 如果方法或属性的返回值等于这个值,那么所列出的字段和属性成员将不会为 null。 + /// + /// + /// 将保证不会为 null 的字段或属性名称列表。 + /// + public MemberNotNullWhenAttribute(bool returnValue, string member) + { + ReturnValue = returnValue; + Members = new[] { member }; + } + + /// + /// 使用 true 或者 false 决定是否所列出的字段和属性成员将不会为 null。 + /// + /// + /// 如果方法或属性的返回值等于这个值,那么所列出的字段和属性成员将不会为 null。 + /// + /// + /// 将保证不会为 null 的字段或属性名称列表。 + /// + public MemberNotNullWhenAttribute(bool returnValue, params string[] members) + { + ReturnValue = returnValue; + Members = members; + } + + /// + /// 获取返回值决定是否不可为空的那个判断值。 + /// + public bool ReturnValue { get; } + + /// + /// 调用了此方法后保证不会为 null 的字段或属性名称列表。 + /// + public string[] Members { get; } + } +#endif +} diff --git a/src/dotnetCampus.LatestCsharpFeatures.Source/RequiredMemberAttribute.cs b/src/dotnetCampus.LatestCsharpFeatures.Source/RequiredMemberAttribute.cs new file mode 100644 index 0000000..1c2e576 --- /dev/null +++ b/src/dotnetCampus.LatestCsharpFeatures.Source/RequiredMemberAttribute.cs @@ -0,0 +1,48 @@ +#if NET7_0_OR_GREATER +// .NET 7.0 开始已包含 required。 +#else +// 旧框架需要包含 required。 +namespace System.Runtime.CompilerServices +{ + /// + /// Specifies that a type has required members or that a member is required. + /// + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = false)] + + internal sealed class RequiredMemberAttribute : Attribute + { + } + + /// + /// Indicates that compiler support for a particular feature is required for the location where this attribute is applied. + /// + [AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = false)] + internal sealed class CompilerFeatureRequiredAttribute : Attribute + { + public CompilerFeatureRequiredAttribute(string featureName) + { + FeatureName = featureName; + } + + /// + /// The name of the compiler feature. + /// + public string FeatureName { get; } + + /// + /// If true, the compiler can choose to allow access to the location where this attribute is applied if it does not understand . + /// + public bool IsOptional { get; init; } + + /// + /// The used for the ref structs C# feature. + /// + public const string RefStructs = nameof(RefStructs); + + /// + /// The used for the required members C# feature. + /// + public const string RequiredMembers = nameof(RequiredMembers); + } +} +#endif \ No newline at end of file diff --git a/src/dotnetCampus.LatestCsharpFeatures.Source/SetsRequiredMembersAttribute.cs b/src/dotnetCampus.LatestCsharpFeatures.Source/SetsRequiredMembersAttribute.cs new file mode 100644 index 0000000..973263f --- /dev/null +++ b/src/dotnetCampus.LatestCsharpFeatures.Source/SetsRequiredMembersAttribute.cs @@ -0,0 +1,16 @@ +#if NET7_0_OR_GREATER +// .NET 7.0 开始已包含 required。 +#else +// 旧框架需要包含 required。 +namespace System.Diagnostics.CodeAnalysis +{ + /// + /// Specifies that this constructor sets all required members for the current type, and callers + /// do not need to set any required members themselves. + /// + [AttributeUsage(AttributeTargets.Constructor, AllowMultiple = false, Inherited = false)] + internal sealed class SetsRequiredMembersAttribute : Attribute + { + } +} +#endif \ No newline at end of file diff --git a/src/dotnetCampus.LatestCsharpFeatures.Source/dotnetCampus.LatestCsharpFeatures.Source.csproj b/src/dotnetCampus.LatestCsharpFeatures.Source/dotnetCampus.LatestCsharpFeatures.Source.csproj index 9cbb86f..ff90808 100644 --- a/src/dotnetCampus.LatestCsharpFeatures.Source/dotnetCampus.LatestCsharpFeatures.Source.csproj +++ b/src/dotnetCampus.LatestCsharpFeatures.Source/dotnetCampus.LatestCsharpFeatures.Source.csproj @@ -9,7 +9,14 @@ - + + + + diff --git a/src/dotnetCampus.Nullable.Source/dotnetCampus.Nullable.Source.csproj b/src/dotnetCampus.Nullable.Source/dotnetCampus.Nullable.Source.csproj index d8ebf32..d2358d7 100644 --- a/src/dotnetCampus.Nullable.Source/dotnetCampus.Nullable.Source.csproj +++ b/src/dotnetCampus.Nullable.Source/dotnetCampus.Nullable.Source.csproj @@ -9,7 +9,7 @@ - + diff --git a/src/dotnetCampus.Required.Source/dotnetCampus.Required.Source.csproj b/src/dotnetCampus.Required.Source/dotnetCampus.Required.Source.csproj index 6bcab0e..4185032 100644 --- a/src/dotnetCampus.Required.Source/dotnetCampus.Required.Source.csproj +++ b/src/dotnetCampus.Required.Source/dotnetCampus.Required.Source.csproj @@ -9,7 +9,7 @@ - +