Skip to content

Commit 7deffed

Browse files
committed
Conversion operators of a keyed value objects can be configured
1 parent 6d6703f commit 7deffed

File tree

91 files changed

+4961
-53
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

91 files changed

+4961
-53
lines changed

Directory.Build.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
<PropertyGroup>
44
<Copyright>(c) $([System.DateTime]::Now.Year), Pawel Gerr. All rights reserved.</Copyright>
5-
<VersionPrefix>8.1.0</VersionPrefix>
5+
<VersionPrefix>8.2.0</VersionPrefix>
66
<Authors>Pawel Gerr</Authors>
77
<GenerateDocumentationFile>true</GenerateDocumentationFile>
88
<PackageProjectUrl>https://github.com/PawelGerr/Thinktecture.Runtime.Extensions</PackageProjectUrl>

samples/Thinktecture.Runtime.Extensions.Benchmarking/Benchmarks/TypedIdBenchmarks.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public CustomerId CustomerId_NewId()
3131
}
3232
}
3333

34-
[ValueObject<Guid>]
34+
[ValueObject<Guid>(ConversionToKeyMemberType = ConversionOperatorsGeneration.Explicit)]
3535
public partial struct CustomerId
3636
{
3737
public static CustomerId NewId() => new(Guid.NewGuid());

src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ValueObjects/AllValueObjectSettings.cs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ public sealed class AllValueObjectSettings : IEquatable<AllValueObjectSettings>,
2424
public OperatorsGeneration EqualityComparisonOperators { get; }
2525
public string DefaultInstancePropertyName { get; }
2626
public bool AllowDefaultStructs { get; }
27+
public ConversionOperatorsGeneration ConversionFromKeyMemberType { get; }
28+
public ConversionOperatorsGeneration UnsafeConversionToKeyMemberType { get; }
29+
public ConversionOperatorsGeneration ConversionToKeyMemberType { get; }
2730

2831
public AllValueObjectSettings(AttributeData valueObjectAttribute)
2932
{
@@ -49,6 +52,9 @@ public AllValueObjectSettings(AttributeData valueObjectAttribute)
4952
ComparisonOperators = valueObjectAttribute.FindComparisonOperators();
5053
DefaultInstancePropertyName = valueObjectAttribute.FindDefaultInstancePropertyName() ?? "Empty";
5154
AllowDefaultStructs = valueObjectAttribute.FindAllowDefaultStructs();
55+
ConversionToKeyMemberType = valueObjectAttribute.FindConversionToKeyMemberType() ?? ConversionOperatorsGeneration.Implicit;
56+
UnsafeConversionToKeyMemberType = valueObjectAttribute.FindUnsafeConversionToKeyMemberType() ?? ConversionOperatorsGeneration.Explicit;
57+
ConversionFromKeyMemberType = valueObjectAttribute.FindConversionFromKeyMemberType() ?? ConversionOperatorsGeneration.Explicit;
5258

5359
// Comparison operators depend on the equality comparison operators
5460
if (ComparisonOperators > EqualityComparisonOperators)
@@ -88,7 +94,10 @@ public bool Equals(AllValueObjectSettings? other)
8894
&& ComparisonOperators == other.ComparisonOperators
8995
&& EqualityComparisonOperators == other.EqualityComparisonOperators
9096
&& DefaultInstancePropertyName == other.DefaultInstancePropertyName
91-
&& AllowDefaultStructs == other.AllowDefaultStructs;
97+
&& AllowDefaultStructs == other.AllowDefaultStructs
98+
&& ConversionToKeyMemberType == other.ConversionToKeyMemberType
99+
&& UnsafeConversionToKeyMemberType == other.UnsafeConversionToKeyMemberType
100+
&& ConversionFromKeyMemberType == other.ConversionFromKeyMemberType;
92101
}
93102

94103
public override int GetHashCode()
@@ -117,6 +126,9 @@ public override int GetHashCode()
117126
hashCode = (hashCode * 397) ^ (int)EqualityComparisonOperators;
118127
hashCode = (hashCode * 397) ^ DefaultInstancePropertyName.GetHashCode();
119128
hashCode = (hashCode * 397) ^ AllowDefaultStructs.GetHashCode();
129+
hashCode = (hashCode * 397) ^ (int)ConversionToKeyMemberType;
130+
hashCode = (hashCode * 397) ^ (int)UnsafeConversionToKeyMemberType;
131+
hashCode = (hashCode * 397) ^ (int)ConversionFromKeyMemberType;
120132

121133
return hashCode;
122134
}

src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ValueObjects/KeyedValueObjectCodeGenerator.cs

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -119,11 +119,11 @@ private void GenerateValueObject(CancellationToken cancellationToken)
119119
}
120120

121121
GenerateToValue();
122-
GenerateImplicitConversionToKey();
123-
GenerateExplicitConversionToKey();
122+
GenerateSafeConversionToKey();
123+
GenerateUnsafeConversionToKey();
124124

125125
if (!_state.Settings.SkipFactoryMethods)
126-
GenerateExplicitConversion(emptyStringYieldsNull);
126+
GenerateConversionFromKey(emptyStringYieldsNull);
127127

128128
cancellationToken.ThrowIfCancellationRequested();
129129

@@ -197,22 +197,22 @@ internal static void ModuleInit()
197197
");
198198
}
199199

200-
private void GenerateImplicitConversionToKey()
200+
private void GenerateSafeConversionToKey()
201201
{
202202
var keyMember = _state.KeyMember;
203203

204-
if (keyMember.IsInterface)
204+
if (_state.Settings.ConversionToKeyMemberType == ConversionOperatorsGeneration.None || keyMember.IsInterface)
205205
return;
206206

207207
_sb.Append(@"
208208
209209
/// <summary>
210-
/// Implicit conversion to the type ").AppendTypeForXmlComment(keyMember).Append(@".
210+
/// ").Append(_state.Settings.ConversionToKeyMemberType == ConversionOperatorsGeneration.Implicit ? "Implicit" : "Explicit").Append(" conversion to the type ").AppendTypeForXmlComment(keyMember).Append(@".
211211
/// </summary>
212212
/// <param name=""obj"">Object to covert.</param>
213213
/// <returns>The <see cref=""").Append(keyMember.Name).Append(@"""/> of provided <paramref name=""obj""/> or <c>default</c> if <paramref name=""obj""/> is <c>null</c>.</returns>
214214
[return: global::System.Diagnostics.CodeAnalysis.NotNullIfNotNull(""obj"")]
215-
public static implicit operator ").AppendTypeFullyQualifiedNullable(keyMember).Append("(").AppendTypeFullyQualifiedNullable(_state).Append(@" obj)
215+
public static ").AppendConversionOperator(_state.Settings.ConversionToKeyMemberType).Append(" operator ").AppendTypeFullyQualifiedNullable(keyMember).Append("(").AppendTypeFullyQualifiedNullable(_state).Append(@" obj)
216216
{
217217
return obj?.").Append(keyMember.Name).Append(@";
218218
}");
@@ -225,33 +225,33 @@ private void GenerateImplicitConversionToKey()
225225
_sb.Append(@"
226226
227227
/// <summary>
228-
/// Implicit conversion to the type ").AppendTypeForXmlComment(keyMember).Append(@".
228+
/// ").Append(_state.Settings.ConversionToKeyMemberType == ConversionOperatorsGeneration.Implicit ? "Implicit" : "Explicit").Append(" conversion to the type ").AppendTypeForXmlComment(keyMember).Append(@".
229229
/// </summary>
230230
/// <param name=""obj"">Object to covert.</param>
231231
/// <returns>The <see cref=""").Append(keyMember.Name).Append(@"""/> of provided <paramref name=""obj""/>.</returns>
232-
public static implicit operator ").AppendTypeFullyQualified(keyMember).Append("(").AppendTypeFullyQualified(_state).Append(@" obj)
232+
public static ").AppendConversionOperator(_state.Settings.ConversionToKeyMemberType).Append(" operator ").AppendTypeFullyQualified(keyMember).Append("(").AppendTypeFullyQualified(_state).Append(@" obj)
233233
{
234234
return obj.").Append(keyMember.Name).Append(@";
235235
}");
236236
}
237237

238-
private void GenerateExplicitConversionToKey()
238+
private void GenerateUnsafeConversionToKey()
239239
{
240240
var keyMember = _state.KeyMember;
241241

242-
if (keyMember.IsInterface || keyMember.IsReferenceType || !_state.IsReferenceType)
242+
if (_state.Settings.UnsafeConversionToKeyMemberType == ConversionOperatorsGeneration.None || keyMember.IsInterface || keyMember.IsReferenceType || !_state.IsReferenceType)
243243
return;
244244

245245
_sb.Append(@"
246246
247247
/// <summary>
248-
/// Explicit conversion to the type ").AppendTypeForXmlComment(keyMember).Append(@".
248+
/// ").Append(_state.Settings.UnsafeConversionToKeyMemberType == ConversionOperatorsGeneration.Implicit ? "Implicit" : "Explicit").Append(" conversion to the type ").AppendTypeForXmlComment(keyMember).Append(@".
249249
/// </summary>
250250
/// <param name=""obj"">Object to covert.</param>
251251
/// <returns>The <see cref=""").Append(keyMember.Name).Append(@"""/> of provided <paramref name=""obj""/>.</returns>
252252
/// <exception cref=""System.NullReferenceException"">If <paramref name=""obj""/> is <c>null</c>.</exception>
253253
[return: global::System.Diagnostics.CodeAnalysis.NotNullIfNotNull(""obj"")]
254-
public static explicit operator ").AppendTypeFullyQualified(keyMember).Append("(").AppendTypeFullyQualified(_state).Append(@" obj)
254+
public static ").AppendConversionOperator(_state.Settings.UnsafeConversionToKeyMemberType).Append(" operator ").AppendTypeFullyQualified(keyMember).Append("(").AppendTypeFullyQualified(_state).Append(@" obj)
255255
{
256256
if(obj is null)
257257
throw new global::System.NullReferenceException();
@@ -260,11 +260,11 @@ private void GenerateExplicitConversionToKey()
260260
}");
261261
}
262262

263-
private void GenerateExplicitConversion(bool emptyStringYieldsNull)
263+
private void GenerateConversionFromKey(bool emptyStringYieldsNull)
264264
{
265265
var keyMember = _state.KeyMember;
266266

267-
if (keyMember.IsInterface)
267+
if (_state.Settings.ConversionFromKeyMemberType == ConversionOperatorsGeneration.None || keyMember.IsInterface)
268268
return;
269269

270270
var bothAreReferenceTypes = _state.IsReferenceType && keyMember.IsReferenceType;
@@ -273,10 +273,10 @@ private void GenerateExplicitConversion(bool emptyStringYieldsNull)
273273
_sb.Append(@"
274274
275275
/// <summary>
276-
/// Explicit conversion from the type ").AppendTypeForXmlComment(keyMember).Append(@".
276+
/// ").Append(_state.Settings.ConversionFromKeyMemberType == ConversionOperatorsGeneration.Implicit ? "Implicit" : "Explicit").Append(" conversion from the type ").AppendTypeForXmlComment(keyMember).Append(@".
277277
/// </summary>
278278
/// <param name=""").Append(keyMember.ArgumentName).Append(@""">Value to covert.</param>
279-
/// <returns>An instance of ").AppendTypeForXmlComment(_state).Append(@".</returns>");
279+
/// <returns>An instance of ").AppendTypeForXmlComment(_state).Append(".</returns>");
280280

281281
if (bothAreReferenceTypes && !emptyStringYieldsNull)
282282
{
@@ -285,7 +285,7 @@ private void GenerateExplicitConversion(bool emptyStringYieldsNull)
285285
}
286286

287287
_sb.Append(@"
288-
public static explicit operator ").AppendTypeFullyQualified(_state).Append(nullableQuestionMark).Append("(").AppendTypeFullyQualified(keyMember).Append(nullableQuestionMark).Append(" ").AppendEscaped(keyMember.ArgumentName).Append(@")
288+
public static ").AppendConversionOperator(_state.Settings.ConversionFromKeyMemberType).Append(" operator ").AppendTypeFullyQualified(_state).Append(nullableQuestionMark).Append("(").AppendTypeFullyQualified(keyMember).Append(nullableQuestionMark).Append(" ").AppendEscaped(keyMember.ArgumentName).Append(@")
289289
{");
290290

291291
if (bothAreReferenceTypes)

src/Thinktecture.Runtime.Extensions.SourceGenerator/CodeAnalysis/ValueObjects/ValueObjectSettings.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ namespace Thinktecture.CodeAnalysis.ValueObjects;
1515
public bool NullInFactoryMethodsYieldsNull => _allSettings.NullInFactoryMethodsYieldsNull;
1616
public string DefaultInstancePropertyName => _allSettings.DefaultInstancePropertyName;
1717
public bool AllowDefaultStructs => _allSettings.AllowDefaultStructs;
18+
public ConversionOperatorsGeneration ConversionToKeyMemberType => _allSettings.ConversionToKeyMemberType;
19+
public ConversionOperatorsGeneration UnsafeConversionToKeyMemberType => _allSettings.UnsafeConversionToKeyMemberType;
20+
public ConversionOperatorsGeneration ConversionFromKeyMemberType => _allSettings.ConversionFromKeyMemberType;
1821
public bool HasStructLayoutAttribute => _attributeInfo.HasStructLayoutAttribute;
1922
public string? KeyMemberEqualityComparerAccessor => _attributeInfo.KeyMemberEqualityComparerAccessor;
2023
public ImmutableArray<DesiredFactory> DesiredFactories => _attributeInfo.DesiredFactories;
@@ -39,6 +42,9 @@ public bool Equals(ValueObjectSettings other)
3942
&& NullInFactoryMethodsYieldsNull == other.NullInFactoryMethodsYieldsNull
4043
&& DefaultInstancePropertyName == other.DefaultInstancePropertyName
4144
&& AllowDefaultStructs == other.AllowDefaultStructs
45+
&& ConversionToKeyMemberType == other.ConversionToKeyMemberType
46+
&& UnsafeConversionToKeyMemberType == other.UnsafeConversionToKeyMemberType
47+
&& ConversionFromKeyMemberType == other.ConversionFromKeyMemberType
4248
&& HasStructLayoutAttribute == other.HasStructLayoutAttribute
4349
&& KeyMemberEqualityComparerAccessor == other.KeyMemberEqualityComparerAccessor
4450
&& DesiredFactories.SequenceEqual(other.DesiredFactories);
@@ -63,6 +69,9 @@ public override int GetHashCode()
6369
hashCode = (hashCode * 397) ^ NullInFactoryMethodsYieldsNull.GetHashCode();
6470
hashCode = (hashCode * 397) ^ DefaultInstancePropertyName.GetHashCode();
6571
hashCode = (hashCode * 397) ^ AllowDefaultStructs.GetHashCode();
72+
hashCode = (hashCode * 397) ^ (int)ConversionToKeyMemberType;
73+
hashCode = (hashCode * 397) ^ (int)UnsafeConversionToKeyMemberType;
74+
hashCode = (hashCode * 397) ^ (int)ConversionFromKeyMemberType;
6675
hashCode = (hashCode * 397) ^ HasStructLayoutAttribute.GetHashCode();
6776
hashCode = (hashCode * 397) ^ (KeyMemberEqualityComparerAccessor?.GetHashCode() ?? 0);
6877
hashCode = (hashCode * 397) ^ DesiredFactories.ComputeHashCode();

src/Thinktecture.Runtime.Extensions.SourceGenerator/Extensions/AttributeDataExtensions.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,11 @@ public static SwitchMapMethodsGeneration FindMapMethods(this AttributeData attri
144144
return GetConversionOperatorsGeneration(attributeData, "ConversionToKeyMemberType");
145145
}
146146

147+
public static ConversionOperatorsGeneration? FindUnsafeConversionToKeyMemberType(this AttributeData attributeData)
148+
{
149+
return GetConversionOperatorsGeneration(attributeData, "UnsafeConversionToKeyMemberType");
150+
}
151+
147152
public static ConversionOperatorsGeneration? FindConversionFromKeyMemberType(this AttributeData attributeData)
148153
{
149154
return GetConversionOperatorsGeneration(attributeData, "ConversionFromKeyMemberType");

src/Thinktecture.Runtime.Extensions/ValueObjectAttribute.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,12 +161,34 @@ public override OperatorsGeneration EqualityComparisonOperators
161161
/// </summary>
162162
public bool SkipIFormattable { get; set; }
163163

164+
/// <summary>
165+
/// Indication whether and how the generator should generate the conversion operators from value object to <see cref="KeyMemberType"/>.
166+
/// Default is <see cref="ConversionOperatorsGeneration.Implicit"/>.
167+
/// </summary>
168+
public ConversionOperatorsGeneration ConversionToKeyMemberType { get; set; }
169+
170+
/// <summary>
171+
/// Indication whether and how the generator should generate "unsafe" conversion operators from value object to <see cref="KeyMemberType"/>.
172+
/// Conversion is considered unsafe if it can throw an <see cref="Exception"/>.
173+
/// Default is <see cref="ConversionOperatorsGeneration.Explicit"/>.
174+
/// </summary>
175+
public ConversionOperatorsGeneration UnsafeConversionToKeyMemberType { get; set; }
176+
177+
/// <summary>
178+
/// Indication whether and how the generator should generate the conversion operators from <see cref="KeyMemberType"/> to enum type.
179+
/// Default is <see cref="ConversionOperatorsGeneration.Explicit"/>.
180+
/// </summary>
181+
public ConversionOperatorsGeneration ConversionFromKeyMemberType { get; set; }
182+
164183
/// <summary>
165184
/// Initializes new instance of <see cref="ValueObjectAttribute{TKey}"/>.
166185
/// </summary>
167186
public ValueObjectAttribute()
168187
{
169188
KeyMemberType = typeof(TKey);
170189
KeyMemberAccessModifier = ValueObjectAccessModifier.Private;
190+
ConversionToKeyMemberType = ConversionOperatorsGeneration.Implicit;
191+
UnsafeConversionToKeyMemberType = ConversionOperatorsGeneration.Explicit;
192+
ConversionFromKeyMemberType = ConversionOperatorsGeneration.Explicit;
171193
}
172194
}

test/Thinktecture.Runtime.Extensions.SourceGenerator.Tests/SourceGeneratorTests/EnumSourceGeneratorTests.cs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -676,6 +676,36 @@ public async Task Should_change_conversion_from_key(
676676
var source = $$"""
677677
using System;
678678
679+
namespace Thinktecture.Tests
680+
{
681+
[SmartEnum<string>(ConversionFromKeyMemberType = ConversionOperatorsGeneration.{{operatorsGeneration}})]
682+
public abstract partial class TestEnum
683+
{
684+
public static readonly TestEnum Item1 = null!;
685+
}
686+
}
687+
""";
688+
var outputs = GetGeneratedOutputs<SmartEnumSourceGenerator>(source, typeof(IEnum<>).Assembly);
689+
690+
await VerifyAsync(operatorsGeneration.ToString(),
691+
outputs,
692+
"Thinktecture.Tests.TestEnum.g.cs",
693+
"Thinktecture.Tests.TestEnum.Comparable.g.cs",
694+
"Thinktecture.Tests.TestEnum.Parsable.g.cs",
695+
"Thinktecture.Tests.TestEnum.ComparisonOperators.g.cs",
696+
"Thinktecture.Tests.TestEnum.EqualityComparisonOperators.g.cs");
697+
}
698+
699+
[Theory]
700+
[InlineData(ConversionOperatorsGeneration.None)]
701+
[InlineData(ConversionOperatorsGeneration.Implicit)]
702+
[InlineData(ConversionOperatorsGeneration.Explicit)]
703+
public async Task Should_change_conversion_to_key(
704+
ConversionOperatorsGeneration operatorsGeneration)
705+
{
706+
var source = $$"""
707+
using System;
708+
679709
namespace Thinktecture.Tests
680710
{
681711
[SmartEnum<string>(ConversionToKeyMemberType = ConversionOperatorsGeneration.{{operatorsGeneration}})]

test/Thinktecture.Runtime.Extensions.SourceGenerator.Tests/SourceGeneratorTests/Snapshots/EnumSourceGeneratorTests.Should_change_conversion_from_key_Explicit0.verified.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -184,12 +184,12 @@ public static bool TryGet(global::System.ReadOnlySpan<char> @key, [global::Syste
184184
#endif
185185

186186
/// <summary>
187-
/// Explicit conversion to the type <see cref="string"/>.
187+
/// Implicit conversion to the type <see cref="string"/>.
188188
/// </summary>
189189
/// <param name="item">Item to covert.</param>
190190
/// <returns>The <see cref="TestEnum.Key"/> of provided <paramref name="item"/> or <c>default</c> if <paramref name="item"/> is <c>null</c>.</returns>
191191
[return: global::System.Diagnostics.CodeAnalysis.NotNullIfNotNull("item")]
192-
public static explicit operator string?(global::Thinktecture.Tests.TestEnum? item)
192+
public static implicit operator string?(global::Thinktecture.Tests.TestEnum? item)
193193
{
194194
return item is null ? default : item.Key;
195195
}

test/Thinktecture.Runtime.Extensions.SourceGenerator.Tests/SourceGeneratorTests/Snapshots/EnumSourceGeneratorTests.Should_change_conversion_from_key_Implicit0.verified.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -195,12 +195,12 @@ public static bool TryGet(global::System.ReadOnlySpan<char> @key, [global::Syste
195195
}
196196

197197
/// <summary>
198-
/// Explicit conversion from the type <see cref="string"/>.
198+
/// Implicit conversion from the type <see cref="string"/>.
199199
/// </summary>
200200
/// <param name="key">Value to covert.</param>
201201
/// <returns>An instance of <see cref="TestEnum"/> if the <paramref name="key"/> is a known item or implements <see cref="Thinktecture.IValidatableEnum"/>.</returns>
202202
[return: global::System.Diagnostics.CodeAnalysis.NotNullIfNotNull("key")]
203-
public static explicit operator global::Thinktecture.Tests.TestEnum?(string? @key)
203+
public static implicit operator global::Thinktecture.Tests.TestEnum?(string? @key)
204204
{
205205
return global::Thinktecture.Tests.TestEnum.Get(@key);
206206
}

test/Thinktecture.Runtime.Extensions.SourceGenerator.Tests/SourceGeneratorTests/Snapshots/EnumSourceGeneratorTests.Should_change_conversion_from_key_None0.verified.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -184,14 +184,14 @@ public static bool TryGet(global::System.ReadOnlySpan<char> @key, [global::Syste
184184
#endif
185185

186186
/// <summary>
187-
/// Explicit conversion from the type <see cref="string"/>.
187+
/// Implicit conversion to the type <see cref="string"/>.
188188
/// </summary>
189-
/// <param name="key">Value to covert.</param>
190-
/// <returns>An instance of <see cref="TestEnum"/> if the <paramref name="key"/> is a known item or implements <see cref="Thinktecture.IValidatableEnum"/>.</returns>
191-
[return: global::System.Diagnostics.CodeAnalysis.NotNullIfNotNull("key")]
192-
public static explicit operator global::Thinktecture.Tests.TestEnum?(string? @key)
189+
/// <param name="item">Item to covert.</param>
190+
/// <returns>The <see cref="TestEnum.Key"/> of provided <paramref name="item"/> or <c>default</c> if <paramref name="item"/> is <c>null</c>.</returns>
191+
[return: global::System.Diagnostics.CodeAnalysis.NotNullIfNotNull("item")]
192+
public static implicit operator string?(global::Thinktecture.Tests.TestEnum? item)
193193
{
194-
return global::Thinktecture.Tests.TestEnum.Get(@key);
194+
return item is null ? default : item.Key;
195195
}
196196

197197
/// <inheritdoc />

0 commit comments

Comments
 (0)