1

How can I get the type of a property of T in a base class?

The class has a collection of type T called Values:

public class BaseHistoryViewModel<T>

public ObservableCollection<T> Values { get; set; }

This type T is always a class derived from another base class BaseHistoryItemViewModel that has a property Value<T> where T : BaseModel

In my BaseHistoryViewModel I want to determine what the type of the Value property is:

    protected virtual async void HandleOnDataChanged(object sender, DataChangedEventArgs e)
    {
        if (e.DataModelType == typeof(T))
        {
            await this.LoadDataAsync(true);
        }
    }

So far this would resolve to Weight == WeightItemViewModelso I really need something like:

typeof(T.Value). I could implement this method in all my derived classes instead but there are nine of them as would rather handle this in the base if possible. Any help would be greatly appreciated.

UPDATE: This is what I did in the end from @Zohar's answer:

protected virtual async void HandleOnDataChanged(object sender, DataChangedEventArgs e)
{
    var typeOfValues = typeof(T).GetProperty("Value").PropertyType;
    if (e.DataModelType == typeOfValues)
    {
        await this.LoadDataAsync(true);
    }
}
5
  • I think T.Values.GetType() should work. Commented Aug 19, 2018 at 6:33
  • You shouldn't do that as it would break your encapsulation and prevent you from utilizing polymorphism Commented Aug 19, 2018 at 6:33
  • Not sure I understand @Amit can you explain further please? Commented Aug 19, 2018 at 6:40
  • 1
    Possible duplicate of How to get the type of T from a member of a generic class or method? Commented Aug 19, 2018 at 7:01
  • The fact that your function explicitly compares types (in this case the type of a member of the generic type) means it had to be modified any time a new type is introduced into your system. That's the opposite of the goal of polymorphism and is a kind of implementation leak Commented Aug 19, 2018 at 11:41

1 Answer 1

3

This type T is always a class derived from another base class BaseHistoryItemViewModel

In that case, you can use a generic constraint to indicate that:

public class BaseHistoryViewModel<T> where T : BaseHistoryItemViewModel

Once you do that, the compiler will know that every T has a generic property called Value - so you could use typeof(T.Value) (Please note that it's not actually T.Value but the actual reference of type T - suppose you have an instance of T called Item, it would be typeof(Item.Value)) in BaseHistoryViewModel<T> just as you want.

However, Please note that the fact that you are using typeof(T) inside a generic method or class is a pretty good indicator that you are not using generics properly in the first place.
The point of using generics is to be able to write a single method (or class) to act on a variety of different types without special handling for each type.

Update

You can use reflection to get the type of the Values property from inside the BaseHistoryViewModel<T> class, like this:

this.GetType().GetProperty("Values").PropertyType.GetGenericArguments()[0];

This will return the type of T for the Values property - even if it does not contain any elements.

Of course, you can use the same technique inside the BaseHistoryItemViewModel<T> class to get the type of the Value property.

Sign up to request clarification or add additional context in comments.

5 Comments

Thanks @Zohar. Added the where clause constraint and that is all good. There is something wrong with the syntax of typeof(T.Value), I get an error Cannot do a member lookup on T because it is a type parameter. Any ideas?
Yes, sorry, It's not T.Value, but rather the instance of T's Value property. I thought that was quite obvious. Editing my answer.
The things is, I have this.Values (which are of type T) but it is a collection that may not have any items in it. So I am not sure how I can get the equivalent of typeof(this.Values[0].Value) when Values is empty.
Thanks @Zohar. Made a slight alteration: var typeOfValues = this.GetType().GetProperty("Values").PropertyType.GetGenericArguments()[0].GetProperty("Value").PropertyType; and it works. Are there any null checks I need to make? So now to decide whether I should be doing this at all :)
No null checks needed, this can never be null, and everything else is just types, so they will not be null either. And yes, if you are using generics, you should probably not be messing around with types inside. Perhaps a better alternative would be to create the LoadDataAsync as an abstract method in the BaseModel and then implement it in it's derived classes, sparing you the need to check what exact type is the Value property.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.