Reputation: 1079
I'm pretty stumped with this so if anyone has any ideas. I have the generic method
public void Foo<TClass>(TClass item) where TClass : class
{ }
And I want to call this method from another generic method, but this generic method doesn't have the type constraint "where TClass : class"
public void Bar<T>(T item)
{
this.Foo<T>(item);
}
This doesn't work, I get the error
"The type 'T' must be a reference type in order to use it as parameter 'TClass'"
Which I understand. But my question is this - is there anything I can do with C# syntax in order to "filter" the generic type "T" to pass it to "this.Bar" if it is a class. Something like....
public void Bar<T>(T item)
{
if (typeof(T).IsClass)
this.Foo<T **as class**>();
}
I realise I could use reflection to call Foo, but this just seems like cheating. Is there something I can do with C# to pass "T" on with the constraint at runtime?
Also - I can't change the constraint on the method "Bar" as it comes from an interface so the constraint has to match the constraint on the interface
Upvotes: 13
Views: 1512
Reputation: 68640
The only way to call Foo
without reflection, is to cast item
to one of the types/classes in its hierarchy (after the proper IsClass
check).
Obviously, there's only one type in its hierarchy that you know of a priori: Object
.
public void Bar<T>(T item)
{
if (typeof(T).IsClass)
this.Foo((object) item);
}
Edit :
Also, in one of the comments you said you added the class
constraint to be to instantiate T
. You don't need that, what you need is the new
constraint.
Upvotes: 4
Reputation: 10287
if (typeof(T).IsClass)
{
this.GetType()
.GetMethod("Foo", System.Reflection.BindingFlags.Instance |
System.Reflection.BindingFlags.Public)
.Invoke(this, new object[] { item });
}
Upvotes: 0
Reputation: 754525
Unfortunately there is no way to do this without changing Bar
to have the generic constraint class
or using reflection. In order to compile C# must know at compile time that T
is indeed a class
value. There is no way to use a dynamic test such as typeof(T).IsClass
in order to satisfy this compile time constraint.
You mentioned in the question that you can't change Bar
but it seems like you are willing to accept the possibility of dynamic failure. Perhaps instead change Foo
to not have the constraint but instead throw an exception when T
is not a class type
Upvotes: 4
Reputation: 12849
I believe there is no way to make it compile. You will have to use reflection to make the call.
Actually. You could cheat if you contain it within a class:
public class Container<T>
{
public Container(T value)
{
Value = value;
}
public T Value { get; private set; }
}
public void Bar<T>(T item)
{
this.Foo<Container<T>>(new Container<T>(item));
}
but this adds one layer you need to call-through and makes the types less clear.
Upvotes: -1