简体   繁体   中英

How can I test if a value is an instance of ObservableCollection<T>?

How can I test if a value is an instance of ObservableCollection? (and then operate on the collection, without using dynamic)

How can I remove the dynamic casts from this generic, Coming from Java, I would be able to use wildcard or raw generics in order to operate on the collections, without needing to know the types.

 object copiedValue = FetchCopyValue();
 if( copiedValue is ObservableCollection<Guid> 
  || copiedValue is ObservableCollection<AViewModel>
  || copiedValue is ObservableCollection<BViewModel>
  || copiedValue is ObservableCollection<CViewModel>
  || copiedValue is ObservableCollection<DViewModel>
 )
 {
     var sourceCollection = (dynamic) copiedValue;
     var destinationCollection = (dynamic) GetDestination(copiedValue);
     destinationCollection?.Clear();
     destinationCollection?.AddRange(sourceCollection);
 }

Where GetDestination returns an Observable Collection that is the same type as copiedValue

Well, you could use method IsGenericType combined with GetGenericTypeDefinition :

var type = copiedValue.GetType();
if(type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ObservableCollection<>))

type.IsGenericType is used as a guard clause to prevent against exceptions in GetGenericTypeDefinition being thrown when called on non generic types.

This combined with Magnus's suggestion to cast it to IList should do the trick.

Since ObservableCollection<T> implements the non generic interface IList you can just cast to that. IList excepts object as parameter. Example:

var copiedValue = new ObservableCollection<int>() {1,2,3};
var list = (IList)copiedValue;

list.Clear();
for (int i = 4; i < 8; i++)
    list.Add(i);

Might be somewhat more maintainable as:

bool TryAddToDestination<T>(object o)
{
    if (o is ObservableCollection<T> sourceCollection)
    {
       var destinationCollection = GetDestination (sourceCollection);
       destinationCollection?.Clear();
       destinationCollection?.AddRange(sourceCollection);
       return true;
    }
    return false;   
}

void YourFunction()
{
    TryAddToDestination<Guid> || TryAddToDestination<AViewModel> || TryAddToDestination<BViewModel> || TryAddToDestination<CViewModel);
}

I created an extension method for such checks:

public static bool IsGenericTypeOf(this Type type, Type genericTypeDefinition)
{
    if (type == null)
        throw new ArgumentNullException(nameof(type));
    if (genericTypeDefinition == null)
        throw new ArgumentNullException(nameof(genericTypeDefinition));
    return type.IsGenericType && type.GetGenericTypeDefinition() == genericTypeDefinition;
}

Usage:

if (copiedValue.IsGenericTypeOf(typeof(ObservableCollection<>)))
{
     // as the element type can be anything you cannot treat copiedValue as ObservableCollection here
     // But considering it implements nongeneric interfaces you can cast it to IList:
     IList sourceCollection = (IList)copiedValue;
     IList destinationCollection = GetDestination(copiedValue);
     destinationCollection.Clear();
     foreach (var item in sourceCollection)
         destinationCollection.Add(item);        
}

Just after you get to know the type cast it as matching type, like this:

if(copiedValue is ObservableCollection<Guid>)
{
     ObservableCollection<Guid> guids = (ObservableCollection<Guid>)copiedValue
     //now deal with guids
}

you may create a switch-case.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM