Reputation: 1324
I have the following generic class
public class Home<T> where T : Class
{
public string GetClassType
{
get{ return T.ToString() }
}
}
Now, I'm getting an Object X which I know for sure is Home:
public void DoSomething(object x)
{
if(x is // Check if Home<>)
{
// I want to invoke GetClassType method of x
// but I don't know his generic type
x as Home<?> // What should I use here?
}
}
Can I even make a cast without specifying the generic type of the class?
Upvotes: 16
Views: 16152
Reputation: 15643
I know this is an old thread but all answers posted so far have not directly addressed this question and instead only suggested workarounds (i.e. "use reflection", "make your DoSomething()
method generic" or "create a non-generic base class and call this base class' method").
Can I even make a cast without specifying the generic type of the class?
So to clearly answer your question: No it is not possible. Due to the covariance constraints in C# you cannot cast into a generic class.
In more detail: I am assuming you would want to use x as Home<object>
as the lowest common denomitator in order to be be able to call toString()
provided by the Object
class. Casting your object x
to Home<object>
would require covariance which is not possible with classes (only generic interfaces and delegates can be covariant). while this is great to prevent mistakes at compile time, it is certainly an annoyance when wanting to access methods on generic classes, as in your case. @n8wrl answer is probably your best shot in terms of "casting".
That being said, you could also go for an interface-based solution, using the out flag on your T parameter:
interface IHome<out T> {
string GetClassType { get; }
}
public class Home<T> : IHome<T> where T : class
{
public string GetClassType
{
get { return typeof(T).Name; }
}
}
Then this should work:
public void DoSomething(object x)
{
if(x is // Check if Home<>)
{
var y = x as IHome<object>;
var z = y.GetClassType;
}
}
Upvotes: 2
Reputation: 19765
What if Home derived from a base class?
public class Home
{
public virtual string GetClassType { get; }
}
public class Home<T> : Home
where T : class
{
public override string GetClassType
{
get{ return T.ToString() }
}
...
}
and then
public void DoSomething(object x)
{
if(x is Home)
{
string ct = ((Home)x).GetClassType;
...
}
}
Upvotes: 7
Reputation: 113402
If you're sure the argument to DoSomething
will be a Home<T>
, why not make it a generic method?
public void DoSomething<T>(Home<T> home)
{
...
}
Of course, it would be even easier if DoSomething
should logically be an instance method on Home<T>
.
If you really want to stick with what you have, you could use reflection (untested):
public void DoSomething(object x)
{
// null checks here.
Type t = x.GetType();
if (t.IsGenericType &&
&& t.GetGenericTypeDefinition() == typeof(Home<>))
{
string result = (string) t.GetProperty("GetClassType")
.GetValue(x, null);
Console.WriteLine(result);
}
else
{
... // do nothing / throw etc.
}
}
Upvotes: 10
Reputation: 5120
How about making the function generic?
public void DoSomething<T>(object x)
{
if(x is Home<T>)
{
x as Home<T> ...
}
}
Edit:
Another possiblity would be to create an interface which holds the property GetClassName
so you would only need to check if it is of that interface.
public interface IDescribeClass
{
public string GetClassName { get; set; }
}
BTW: I would use the full qualified name
public string ClassType
{
get{ return typeof(T).FullName; }
}
Upvotes: 1
Reputation: 5381
Have you tried changing your method definition to something like this?
public void DoSomething<T>(Home<T> x)
{
}
Upvotes: 0