簡體   English   中英

檢查類是否實現了泛型接口

[英]Checking Whether Class Implements Generic Interface

我正在使用以下通用函數來確定一個類是否實現了指定的接口:

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);
        }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM