diff --git a/CHANGELOG.md b/CHANGELOG.md index 997dc96..1758045 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Class `Louis.ComponentModel.SimpleStringConverter` provides a base class for type converters that can convert a specific type to and/or from a string. This abstract class takes care of boilerplate code and dealing with `object`s; subclasses only have to implement conversions between `string`s and strongly-typed instances. - Static method `Louis.ComponentModel.SimpleStringConverter.AddToTypeDescriptor` creates an instance of [`TyepConverterAttribute`](https://learn.microsoft.com/en-us/dotnet/api/system.componentmodel.typeconverterattribute) referencing a subclass of `SimpleStringConverter` and registers it for use by [`TypeDescriptor.GetAttributes`](https://learn.microsoft.com/en-us/dotnet/api/system.componentmodel.typedescriptor.getattributes). This enables a converter to be recognized by e.g. [`ConfigurationBinder`](https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.configuration.configurationbinder) with just one line of clean, easy-to-understand code. +- Classes `Louis.ComponentModel.MailAddressConverter` and `Louis.ComponentModel.MailAddressCollectionConverter` perform conversion of [`MailAddress`](https://learn.microsoft.com/en-us/dotnet/api/system.net.mail.mailaddress) and [`MailAddressCollection`](https://learn.microsoft.com/en-us/dotnet/api/system.net.mail.mailaddresscollection), respectively, to and from `string`. They are also good examples of how to subclass `SimpleStringConverter`. ### Changes to existing features diff --git a/src/Louis/ComponentModel/MailAddressCollectionConverter.cs b/src/Louis/ComponentModel/MailAddressCollectionConverter.cs new file mode 100644 index 0000000..6ec72ee --- /dev/null +++ b/src/Louis/ComponentModel/MailAddressCollectionConverter.cs @@ -0,0 +1,42 @@ +// Copyright (c) Tenacom and contributors. Licensed under the MIT license. +// See the LICENSE file in the project root for full license information. + +using System; +using System.ComponentModel; +using System.Globalization; +using System.Net.Mail; +using CommunityToolkit.Diagnostics; + +namespace Louis.ComponentModel; + +/// +/// Provides a type converter to convert instances to and from strings. +/// +public sealed class MailAddressCollectionConverter : SimpleStringConverter +{ + /// + /// Initializes a new instance of the class. + /// + public MailAddressCollectionConverter() + : base(DoConvertFromString, DoConvertToString) + { + } + + private static MailAddressCollection DoConvertFromString(ITypeDescriptorContext? context, CultureInfo? culture, string value) + { + Guard.IsNotEmpty(value, nameof(value)); + var result = new MailAddressCollection(); + try + { + result.Add(value); + } + catch (FormatException e) + { + ThrowHelper.ThrowArgumentException(nameof(value), "Value should be a valid e-mail address, or valid e-mail addresses separated by commas.", e); + } + + return result; + } + + private static string DoConvertToString(ITypeDescriptorContext? context, CultureInfo? culture, MailAddressCollection value) => value.ToString(); +} diff --git a/src/Louis/ComponentModel/MailAddressConverter.cs b/src/Louis/ComponentModel/MailAddressConverter.cs new file mode 100644 index 0000000..d7e343b --- /dev/null +++ b/src/Louis/ComponentModel/MailAddressConverter.cs @@ -0,0 +1,47 @@ +// Copyright (c) Tenacom and contributors. Licensed under the MIT license. +// See the LICENSE file in the project root for full license information. + +using System; +using System.ComponentModel; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Net.Mail; +using CommunityToolkit.Diagnostics; + +namespace Louis.ComponentModel; + +/// +/// Provides a type converter to convert instances to and from strings. +/// +public sealed class MailAddressConverter : SimpleStringConverter +{ + /// + /// Initializes a new instance of the class. + /// + public MailAddressConverter() + : base(DoConvertFromString, DoConvertToString) + { + } + + private static MailAddress DoConvertFromString(ITypeDescriptorContext? context, CultureInfo? culture, string value) + { +#if NET5_0_OR_GREATER + return MailAddress.TryCreate(value, out var result) ? result : ThrowOnInvalidString(nameof(value)); +#else + try + { + return new MailAddress(value); + } + catch (FormatException ex) + { + return ThrowOnInvalidString(nameof(value), ex); + } +#endif + + [DoesNotReturn] + static MailAddress ThrowOnInvalidString(string parameterName, Exception? innerException = null) + => ThrowHelper.ThrowArgumentException(parameterName, "Value should be a valid e-mail address.", innerException); + } + + private static string DoConvertToString(ITypeDescriptorContext? context, CultureInfo? culture, MailAddress value) => value.ToString(); +} diff --git a/src/Louis/PublicAPI.Unshipped.txt b/src/Louis/PublicAPI.Unshipped.txt index 3c0c7b9..51d112a 100644 --- a/src/Louis/PublicAPI.Unshipped.txt +++ b/src/Louis/PublicAPI.Unshipped.txt @@ -1,4 +1,8 @@ #nullable enable +Louis.ComponentModel.MailAddressCollectionConverter +Louis.ComponentModel.MailAddressCollectionConverter.MailAddressCollectionConverter() -> void +Louis.ComponentModel.MailAddressConverter +Louis.ComponentModel.MailAddressConverter.MailAddressConverter() -> void Louis.ComponentModel.SimpleStringConverter Louis.ComponentModel.SimpleStringConverter Louis.ComponentModel.SimpleStringConverter.SimpleStringConverter(System.Func? convertFromString, System.Func? convertToString) -> void