Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 22 additions & 2 deletions TUnit.Engine/Discovery/ConstructorHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -126,9 +126,29 @@ public static bool HasRequiredProperties([DynamicallyAccessedMembers(Dynamically

// Also check individual properties for RequiredAttribute (older approach)
var properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
return properties.Any(p => p.GetCustomAttributes().Any(a => a.GetType().Name == "RequiredAttribute"));
foreach (var property in properties)
{
if (HasRequiredAttribute(property))
{
return true;
}
}

return false;
}

// System.ComponentModel.DataAnnotations.RequiredAttribute, resolved once. It lives in a separate
// assembly that isn't referenced on netstandard2.0, so we look it up by name instead of a compile-time
// type reference. Null when the type can't be loaded (e.g. the assembly isn't present).
private static readonly Type? RequiredAttributeType =
Type.GetType("System.ComponentModel.DataAnnotations.RequiredAttribute, System.ComponentModel.Annotations")
?? Type.GetType("System.ComponentModel.DataAnnotations.RequiredAttribute, System.ComponentModel.DataAnnotations");

private static bool HasRequiredAttribute(PropertyInfo property) =>
// IsDefined checks metadata tokens only — no attribute instances are materialised.
// It matches subclasses of RequiredAttributeType, same as the previous IsInstanceOfType.
RequiredAttributeType is not null && property.IsDefined(RequiredAttributeType, inherit: true);

/// <summary>
/// Tries to initialize required properties on an instance
/// </summary>
Expand All @@ -145,7 +165,7 @@ public static void InitializeRequiredProperties(
{
// In C# 11+, required properties are marked with RequiredMemberAttribute at the member level
var isRequired = property.GetCustomAttribute<System.Runtime.CompilerServices.RequiredMemberAttribute>() != null ||
property.GetCustomAttributes().Any(a => a.GetType().Name == "RequiredAttribute");
HasRequiredAttribute(property);

// Also check if property is marked with 'required' modifier by checking if it's init-only and the type has RequiredMemberAttribute
if (!isRequired && property is { CanWrite: true, SetMethod.IsSpecialName: true } &&
Expand Down
Loading