0

I am working with Unity Engine where there is a base class Component and multiple classes deriving from it, including Transform, MeshRenderer and many classes created by me.

I want to execute an action (in this case Destroy all the components that aren't of types: Transform, MeshRenderer, MeshFilter, Collider and BuildMenuItem). My basic approach looks like this:

Component[] components = obj.GetComponents<Component>();
foreach (var component in components) {
    if (component is MeshFilter)
        continue;
    if (component is MeshRenderer)
        continue;
    if (component is Transform)
        continue;
    if (component is Collider)
        continue;
    if (component is BuildMenuItem)
        continue;

    Destroy(component);
}

In my opinion it looks ugly and the only way to shorten it I found is to use || operator, but it doesn't fix a lot and IMO looks even worse. Is there a cleaner way of implementing that?

Kirill Polishchuk
  • 54,804
  • 11
  • 122
  • 125
Rasmond
  • 442
  • 4
  • 15
  • I'd suggest having a look at https://stackoverflow.com/questions/4559257/how-can-i-implement-notoftypet-in-linq-that-has-a-nice-calling-syntax . – mjwills Jun 24 '19 at 00:04

2 Answers2

3

You can initialize a collection of Types (e.g. List<Type>, HashSet<Tepe>, etc.), add all required types into it (typeof(Transform), ...), and then use Contains to check whether component type is within that collection.

var types = new HashSet<Type> {typeof(Transform), typeof(MeshRenderer)};

Component[] components = obj.GetComponents<Component>();
foreach (var component in components.Where(c => !types.Contains(c.GetType())))
{
    Destroy(component);
}

Updated:

Type[] types = { typeof(Transform), typeof(MeshRenderer) };

Component[] components = obj.GetComponents<Component>();
foreach (var component in components.Where(c => !types.Any(x => c.GetType().IsAssignableFrom(x))))
{
    Destroy(component);
}
Kirill Polishchuk
  • 54,804
  • 11
  • 122
  • 125
  • This unfortunately doesn't include the derived classes (eg. a `BoxCollider` which derives from `Collider` gets destroyed in your approach and not in the original) – Rasmond Jun 23 '19 at 23:50
  • How about modifying the lambda to `c => !types.Any(x => c.GetType().IsAssignableFrom(x))`.edit just saw the edit. – Immorality Jun 24 '19 at 00:06
  • @Immorality, good point, `IsAssignableFrom` is more suitable here – Kirill Polishchuk Jun 24 '19 at 00:10
0

Create an interface INotDestroyable, make non destroyable types Transform, MeshRenderer, MeshFilter, Collider and BuildMenuItem implement it, and then on your loop just check if the element doesn’t implements it. The interface doesn’t have to have any properties or members defined.

Pablo Recalde
  • 3,334
  • 1
  • 22
  • 47
  • It's a good idea, but for my needs it's too... "constant". I might want to have another function which filters other types and so I would need to create multiple interfaces for each of them. Although it doesn't match my needs it still has a great value – Rasmond Jun 23 '19 at 23:54
  • Also, a lot of the mentioned classes are Unity classes and therefore not editable. – Immorality Jun 24 '19 at 00:02