将 2 个泛型类型合并为一个泛型函数调用

Consolidating 2 generic types into one for a generic function call

提问人:Viktor Pagels 提问时间:9/20/2023 更新时间:9/21/2023 访问量:23

问:

很抱歉,如果标题不是很具有描述性,我很难想出一个。

我有一个抽象基类,其中泛型类型是其属性之一。

public abstract class AdapterBase<T>
{
        public string AdapterName { get; set; }
        public T? Configuration { get; set; }
}

我想从抽象类派生并传递配置属性的类型信息。

public class FooAdapter : AdapterBase<FooConfiguration>{}
public class BarAdapter : AdapterBase<BarConfiguration>{}

两个配置对象具有不同的属性,一个可能具有名称,另一个只有一个 Guid。但是,附加到每个配置类我都有一个属性。

[MyCustomAttribute("Foo")]
public class FooConfiguration{}

[MyCustomAttribute("bar")]
public class BarConfiguration{}

现在,我想调用一个泛型函数,该函数仅检查配置字段中是否存在属性

public bool AdapterConfigurationHasMyCustomAttribute<T>()
{
  ....
}
...
main()
{
   bool isThere = AdapterConfigurationHasMyCustomAttribute<FooAdapter>(); => returns true
}

我的问题是,如果我不指定 T 是 AdapterBase 的,那么我无法访问函数中 T 的任何属性。 因此,我必须使用where子句来约束类型

public bool AdapterConfigurationHasMyCustomAttribute<T>() where T : AdapterBase<U>
{
....
}

这对我来说很好。但是,此解决方案还要求我为 U 提供类型信息,这将使签名看起来像这样。

public bool AdapterConfigurationHasMyCustomAttribute<T,U>() where T : AdapterBase<U> where U: class, new()
{
....
}

但是,最好是将签名保留为单一类型,因为 U 的类型已经通过定义 T 来定义。添加另一种类型也意味着像这样的调用: main() { bool isThere = AdapterConfigurationHasMyCustomAttribute<FooAdapter, BarConfiguration>(); }

将导致 True,即使 FooAdapter 和 BarConfiguration 不属于一起。

我可以通过像这样传递一个对象作为参数来规避它。

public bool AdapterConfigurationHasMyCustomAttribute<T>(AdapterBase<T> myAdapter) where T : class, new()
{
....
}

但是,当我只需要附加到类型的信息时,实例化一个对象对我来说似乎有点矫枉过正。

同样,我想避免像这样的调用,其中我传递了 Configuration-Type:

main()
{
   bool isThere = AdapterConfigurationHasMyCustomAttribute<FooConfiguration>();
}

这是因为如果其他人要使用代码,他们需要事先了解哪个 Configuration-Type 属于哪个 AdapterBase 派生,否则他们以后可能会犯错误。

main()
{
   BarAdapter = new BarAdapter();
   bool isThere = AdapterConfigurationHasMyCustomAttribute<FooConfiguration>();
   if(isThere)
   {
     //doing something with BarAdapter after checking FooConfiguration
   }
}

我希望方法签名看起来像这样。

 public bool AdapterConfigurationHasMyCustomAttribute<T>() where T : AdapterBase<U> where U: class, new()
    {
    ....
    }

有没有办法让我避免必须传递第二种类型,同时确保 T 始终是 AdapterBase 的衍生物?

泛型 C#-7.0 类型约束

评论


答:

1赞 Damoon Salatian 9/21/2023 #1

您可以通过使用反射来检查 T 上的属性来实现此目的。 修改您的方法,如下所示:

public bool AdapterConfigurationHasMyCustomAttribute<T>() where T : AdapterBase<object>
{
    Type configType = typeof(T).GetProperty("Configuration")?.PropertyType;

    if (configType != null)
    {
        var attribute = configType.GetCustomAttribute<MyCustomAttribute>();
        if (attribute != null && attribute.SomeProperty == "desiredValue")
        {
            return true;
        }
    }
    
    return false;
}

它将 T 限制为 AdapterBase 的派生,因为您要访问 Configuration 属性,并且事先不知道其类型。

评论

1赞 Viktor Pagels 9/21/2023
谢谢。我可以发誓我尝试了 AdapterBase<object> 方法只是为了得到编译器错误 CS1503“无法从 TypeA 转换为 TypeB”,说这不起作用,因为 FooAdapter 与 AdapterBase<object> 不同。昨天,我设法找到了一个不同的解决方案,在我的项目背景下更适合我的需求。但是,我会接受你的回答,因为这正是我想要实现的目标。