[英]Checking Whether Class Implements Generic Interface
I'm using the following generic function to determine whether a class implements a specified interface:我正在使用以下通用函数来确定一个类是否实现了指定的接口:
private static bool HasFieldType<TEntity, TInterface>()
{
return typeof(TInterface).IsAssignableFrom(typeof(TEntity));
}
This works fine for the majority of the time.这在大多数情况下都可以正常工作。
However, I now have an interface which has a generic parameter:但是,我现在有一个具有通用参数的接口:
public interface IStatusField<TEnum> where TEnum : System.Enum
{
TEnum Status { get; set; }
}
And this causes the HasFieldType
function to break with an unexpected use of unbound generic name
error.这会导致
HasFieldType
函数因unexpected use of unbound generic name
错误而中断。
Ideally, I want to call the function like:理想情况下,我想调用如下函数:
if (HasFieldType<TEntity, IStatusField<>>())
{
// builder is an EntityTypeBuilder instance
builder.Property("Status")
.HasMaxLength(255)
.HasConversion(new EnumToStringConverter<>());
}
But this won't work as I'm not specifying the generic type for both the IStatusField<>
or the EnumToStringConverter<>
.但这不起作用,因为我没有为
IStatusField<>
或EnumToStringConverter<>
指定泛型类型。
Is there any way around this?有没有办法解决?
This code forms part of a generic base IEntityTypeConfiguration
class as follows:此代码构成通用基础
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<>());
}
}
At the point of checking for IStatusField
implementation, I know nothing about the generic type specified.在检查
IStatusField
实现时,我对指定的泛型类型一无所知。 I think this may be the bigger problem...我认为这可能是更大的问题......
Ok, so I've managed to punch my way around the problem.好的,所以我设法解决了这个问题。
It needs a bit of tidying and some error checking but in the crudest form:它需要一些整理和一些错误检查,但以最粗略的形式:
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;
}
Which now enables this to work:现在使它能够工作:
// IStatusField implementation
if (HasFieldType<TEntity>(typeof(IStatusField<>)))
{
builder.Property("Status")
.HasMaxLength(255)
.HasConversion<string>();
}
I can just use the built-in automatic string-to-enum conversions from EF to do the grunt work.我可以使用 EF 的内置自动字符串到枚举转换来完成繁重的工作。
Instead of trying to wrestle with resolving generic type arguments from nothing, you might consider approaching it from the opposite direction, by getting a list of interfaces implemented by TEntity
, filtering it to search for an IStatusField
.与其尝试从无到有解析泛型类型参数,您可以考虑从相反的方向接近它,通过获取由
TEntity
实现的接口列表,过滤它以搜索IStatusField
。 Once you've located the field, you can get its' generic type arguments and pass those to your EnumToStringConverter
:找到该字段后,您可以获取其通用类型参数并将它们传递给您的
EnumToStringConverter
:
var statusField = typeof(TEntity)
.GetInterfaces()
.FirstOrDefault(x => x.Name.StartsWith("IStatusField"));
Value given TEntity : IStatusField<ConsoleColor>
:给定值
TEntity : IStatusField<ConsoleColor>
:
statusField.GenericTypeArguments = [ typeof(System.Color) ]
From there though you're not done;从那里虽然你还没有完成; you must still construct an instance of the generic type
EnumToStringConverter<System.Color>
.您仍然必须构造泛型类型
EnumToStringConverter<System.Color>
的实例。 This is rather simple and outlined here .这相当简单,并在此处进行了概述。
Edit: I realized that because you'd be invoking a constructor, it's not quite the same.编辑:我意识到,因为你会调用构造函数,这是不太一样的。 Here's how you'd accomplish this:
以下是您如何完成此操作:
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);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.