提问人:Viktor Pagels 提问时间:9/20/2023 更新时间:9/21/2023 访问量:23
将 2 个泛型类型合并为一个泛型函数调用
Consolidating 2 generic types into one for a generic function call
问:
很抱歉,如果标题不是很具有描述性,我很难想出一个。
我有一个抽象基类,其中泛型类型是其属性之一。
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 的衍生物?
答:
您可以通过使用反射来检查 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 属性,并且事先不知道其类型。
评论