I'm sorry if the title is not very descriptive I have a hard time coming up with one.
I have an abstract baseclass with a generic type as one of its properties.
public abstract class AdapterBase<T>
{
public string AdapterName { get; set; }
public T? Configuration { get; set; }
}
I want to derive from the abstract class and pass along the type-information of the Configuration Property.
public class FooAdapter : AdapterBase<FooConfiguration>{}
public class BarAdapter : AdapterBase<BarConfiguration>{}
Both Configuration Objects have different properties, one might have a name, the other only a Guid. However Attached to each Configuration-class I have an attribute.
[MyCustomAttribute("Foo")]
public class FooConfiguration{}
[MyCustomAttribute("bar")]
public class BarConfiguration{}
Now I want to call a generic function that only checks for the existence of the attribute in the configuration field
public bool AdapterConfigurationHasMyCustomAttribute<T>()
{
....
}
...
main()
{
bool isThere = AdapterConfigurationHasMyCustomAttribute<FooAdapter>(); => returns true
}
My problem is, if I don't specify that T is of AdapterBase then I have no access to any of the properties for T inside the function. So I have to constrain the type with a where clause
public bool AdapterConfigurationHasMyCustomAttribute<T>() where T : AdapterBase<U>
{
....
}
which would be fine for me. This solution, however, requires that I also supply the Type-Information for U which would make the signature look like this.
public bool AdapterConfigurationHasMyCustomAttribute<T,U>() where T : AdapterBase<U> where U: class, new()
{
....
}
preferably, however, I'd like to keep the signature with a single type since the type for U is already defined through by defining T. And adding another type would also mean that a call like this: main() { bool isThere = AdapterConfigurationHasMyCustomAttribute<FooAdapter, BarConfiguration>(); }
would result in True, even though FooAdapter and BarConfiguration don't belong together.
I could circumvent it by passing along an object as a parameter like this.
public bool AdapterConfigurationHasMyCustomAttribute<T>(AdapterBase<T> myAdapter) where T : class, new()
{
....
}
but instantiating an object when I only need information attached to a type seems overkill to me.
Likewise I would like to avoid a call like this where I pass the Configuration-Type along:
main()
{
bool isThere = AdapterConfigurationHasMyCustomAttribute<FooConfiguration>();
}
This is because if someone else were to use the code they would need to have prior knowledge about which Configuration-Type belongs to which AdapterBase-derivative or else they might make mistakes later.
main()
{
BarAdapter = new BarAdapter();
bool isThere = AdapterConfigurationHasMyCustomAttribute<FooConfiguration>();
if(isThere)
{
//doing something with BarAdapter after checking FooConfiguration
}
}
I'd like for the method-signature to look like this.
public bool AdapterConfigurationHasMyCustomAttribute<T>() where T : AdapterBase<U> where U: class, new()
{
....
}
Is there a way that allows me to avoid having to pass a second type while making sure T is always a derivative of AdapterBase?
you can achieve this by using reflection to inspect the attribute on T. modify your method like follow:
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;
}
It constrains T to be a derivative of AdapterBase since you want to access the Configuration property, and its type is not known in advance.