Vogen
Vogen copied to clipboard
[Documentation Enhancement] [Code Snippet] -- How to Identity a type that is generated by 'Vogen'
Describe the feature
Goal The goal of this is to identify types that are generated by Vogen.
Use Case I use Vogen along side EfCore, I like to programmatically add ValueConverters by convention, I need to identity which properties on my entities are Vogen Generated value objects.
This is one of many use-cases
Shoutout:
- Big thanks to @SteveDunn for using
GeneratedCodeAttribute
, this was very helpful, and I have not seen it used before in the numerous other Source Generator libraries I have reviewed.- Basically
GeneratedCodeAttribute
provides metadata about the tool which generated the code, this is what we'll use as an identifier.
- Basically
Note: My code snippets use:
-
CSharpFunctionalExtensions - to use
Maybe<T>
- btw - if your reading this, and have not checked out this library, I highly recommend.
- You don't need to adopt the pattern 100%, just treat it as a buffet and take / use what you want
- FluentAssertions - in the unit tests, just because
-
XUnit
, because its better thanNUnit
andMSTest
🙃
Code Snippet
// Helper class
internal static class AttributeHelper
{
public static bool IsVogenValueObject(this Type targetType)
{
Maybe<GeneratedCodeAttribute> generatedCodeAttribute = targetType.GetClassAttribute<GeneratedCodeAttribute>();
return generatedCodeAttribute.HasValue && generatedCodeAttribute.Value.Tool == "Vogen";
}
private static Maybe<TAttribute> GetClassAttribute<TAttribute>(this Type targetType)
where TAttribute : Attribute
{
return targetType.GetAttribute<TAttribute>();
}
}
Usage Example (From EfCore)
foreach (IMutableEntityType entityType in builder.Model.GetEntityTypes())
{
PropertyInfo[] properties = entityType.ClrType.GetProperties();
foreach (PropertyInfo propertyInfo in properties)
{
if (propertyInfo.PropertyType.IsVogenValueObject())
{
// Huzzah!
// Do something with the property that is a value object generated by Vogen....
}
}
}
Testing Data for unit test
[ValueObject<Guid>]
// ReSharper disable once PartialTypeWithSinglePart
public readonly partial struct VogenStronglyTypedId {}
Unit Test
public class VogenStronglyTypedIdTests
{
[Fact]
public void ShouldIdentityVogenAttributeByHelperMethod()
{
Type vogenType = typeof(VogenStronglyTypedId);
Maybe<GeneratedCodeAttribute> generatedCodeAttribute = vogenType.GetClassAttribute<GeneratedCodeAttribute>();
Assert.True(generatedCodeAttribute.HasValue);
GeneratedCodeAttribute? valueOfAttribute = generatedCodeAttribute.Value;
valueOfAttribute.Tool.Should()
.Be("Vogen");
}
[Fact]
public void ShouldIdentityVogenAttribute()
{
Type vogenType = typeof(VogenStronglyTypedId);
vogenType.IsVogenValueObject()
.Should()
.Be(true);
}
}
Note
I think this is outside the scope of the library, but I imagine a large majority of Vogen
users have some usecase where this will be helpful.
Add it to the docs, or dont 😄 -- I just wanted to share.
Btw:
- I think a snippet area where users can share code like this, sorta like
Samples
but smaller and less overhead would be cool. - At the same time, this snippet and
snippet samples area
might become messy, or is not relevant (out if scope), so perhaps its a reason to not add it.- I know that CSharpFunctionalExtensions keeps all of their snippets in the Issues, then you can use GitHub search to find the snippets, it works... but I find myself having to really 'dig' for code and examples
Thanks all