I have the following method
public bool HasTypeAttribute<TAttribute, TType>(TType obj)
{
return typeof(TType).GetCustomAttribute<TAttribute>() != null;
}
and I want to be able to use it like this:
MyClass instance = new MyClass();
TypeHelper.HasTypeAttribute<SerializableAttribute>(instance);
but I can't get it working because of the
incorrect number of type parameters
so that I need to call
TypeHelper.HasTypeAttribute<SerializableAttribute, MyClass>(instance);
which certainly makes sense, but why can the compiler not infer the type of the passed object? Because if the method looked like this:
public void Demo<T>(T obj)
{
}
the compiler would certainly be able to infer the type, so that I can write
Foo.Demo(new Bar());
instead of
Foo.Demo<Bar>(new Bar());
So, is there a way to make type inference work in this case? Is it a design flaw by me or can I achieve what I want? Reordering the parameters doesn't help too...
You could break the call into multiple steps, which lets type inference kick in wherever it can.
public class TypeHelperFor<TType>
{
public bool HasTypeAttribute<TAttribute>() where TAttribute : Attribute
{
return typeof(TType).GetCustomAttribute<TAttribute>() != null;
}
}
public static class TypeHelper
{
public static TypeHelperFor<T> For<T>(this T obj)
{
return new TypeHelperFor<T>();
}
}
// The ideal, but unsupported
TypeHelper.HasTypeAttribute<SerializableAttribute>(instance);
// Chained
TypeHelper.For(instance).HasTypeAttribute<SerializableAttribute>();
// Straight-forward/non-chained
TypeHelper.HasTypeAttribute<SerializableAttribute, MyClass>(instance);
That should work alright for this case, but I'd warn against using it in cases where the final method returns void, because it's too easy to leave the chain half-formed if you're not doing anything with the return value.
e.g.
// If I forget to complete the chain here...
if (TypeHelper.For(instance)) // Compiler error
// But if I forget the last call on a chain focused on side-effects, like this one:
// DbHelper.For(table).Execute<MyDbOperationType>();
DbHelper.For(table); // Blissfully compiles but does nothing
// Whereas the non-chained version would protect me
DbHelper.Execute<MyTableType, MyDbOperationType>(table);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With