检查类是否实现泛型接口



我使用以下通用函数来确定类是否实现了指定的接口:

private static bool HasFieldType<TEntity, TInterface>()
{
return typeof(TInterface).IsAssignableFrom(typeof(TEntity));
}

这在大多数情况下都很好。

然而,我现在有一个接口,它有一个通用参数:

public interface IStatusField<TEnum> where TEnum : System.Enum
{
TEnum Status { get; set; }
}

这会导致HasFieldType函数因unexpected use of unbound generic name错误而中断。

理想情况下,我想调用这样的函数:

if (HasFieldType<TEntity, IStatusField<>>()) 
{
// builder is an EntityTypeBuilder instance
builder.Property("Status")
.HasMaxLength(255)
.HasConversion(new EnumToStringConverter<>());
}

但这不起作用,因为我没有为IStatusField<>EnumToStringConverter<>指定泛型类型。

有办法解决这个问题吗?

更新

此代码构成通用基本IEntityTypeConfiguration类的一部分,如下所示:

public abstract class EntityTypeConfiguration<TPrimaryKey, TEntity> : IEntityTypeConfiguration<TEntity> where TEntity : Entity<TPrimaryKey>
{
public void Configure(EntityTypeBuilder<TEntity> builder)
{
builder.HasKey(e => e.Id);
builder.Property(e => e.Id)
.IsRequired()
.HasMaxLength(13)
.HasValueGenerator<PrimaryKeyValueGenerator>();
// Apply the generic interface properties
builder.ApplyInterfaceFields<TPrimaryKey, TEntity>();
// Apply any additional configuration
this.OnConfigure(builder);
}
protected abstract void OnConfigure(EntityTypeBuilder<TEntity> builder);
}
// In an extension class, I have
public static void ApplyInterfaceFields<TPrimaryKey, TEntity>(this EntityTypeBuilder<TEntity> builder) where TEntity : Entity<TPrimaryKey>
{
// Check other implementations (removed for brevity)
// IStatusField implementation
if (HasFieldType<TEntity, IStatusField<>())
{
builder.Property("Status")
.HasMaxLength(255)
.HasConversion(new EnumToStringConverter<>());
}
}

在检查IStatusField实现时,我对指定的泛型类型一无所知。我认为这可能是更大的问题。。。

好的,所以我已经设法解决了这个问题。

它需要一些整理和错误检查,但形式最粗糙:

private static bool HasFieldType<TEntity>(Type interfaceType)
{
var interfaces = typeof(TEntity).GetTypeInfo().ImplementedInterfaces;
// Iterate through the interfaces
foreach (var intf in interfaces)
{
// Compare interface names
if (intf.FullName.Contains(interfaceType.FullName))
{
return intf.IsAssignableFrom(typeof(TEntity));
}
}
return false;
}

现在使其能够工作:

// IStatusField implementation
if (HasFieldType<TEntity>(typeof(IStatusField<>)))
{
builder.Property("Status")
.HasMaxLength(255)
.HasConversion<string>();
}

我可以使用内置的从EF到枚举的自动字符串转换来完成繁重的工作。

您可以考虑从相反的方向来解决它,方法是获取TEntity实现的接口列表,对其进行过滤以搜索IStatusField,而不是试图从无到有地解决泛型类型参数。一旦找到字段,就可以获得它的"泛型类型参数",并将其传递给EnumToStringConverter:

var statusField = typeof(TEntity)
.GetInterfaces()
.FirstOrDefault(x => x.Name.StartsWith("IStatusField"));

给定值TEntity : IStatusField<ConsoleColor>:

statusField.GenericTypeArguments = [ typeof(System.Color) ]

从那里开始,尽管你还没有完成;您仍然必须构造泛型类型EnumToStringConverter<System.Color>的实例。这是相当简单和概述在这里。

编辑:我意识到,因为你将调用一个构造函数,所以它与不太一样。以下是你如何做到这一点:

var statusField = typeof(TEntity)
.GetInterfaces()
.FirstOrDefault(x => x.Name.StartsWith("IStatusField"));
if (statusField != null)
{
var enumType = statusField.GenericTypeArguments[0]; // get the IStatusField<T> value
// get the default constructor after supplying generic type arg
var converterType = typeof(EnumToStringConverter<>)
.MakeGenericType(enumType)
.GetConstructors()[0];
// invoke the constructor. Note the null (optional) param
dynamic converter = converterType.Invoke(new Object[1]);
builder.Property("Status")
.HasMaxLength(255)
.HasConversion(converter);
}

最新更新