jeudi 9 avril 2020

How do I determine the name and reference of a class being targeted by an attribute at runtime?

I am trying to create a custom class attribute for Unity that prevents a targeted MonoBehaviour from existing on more than one object in a scene. I have done some searching and it's been said that in order to get the Type of class the attribute is targeting, I should use the constructor of the attribute; it can't be done using reflection

[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
public class DisallowMultipleInScene : Attribute
{
    public DisallowMultipleInScene(Type type)
    {
        // Do stuff with type here
    }
}

If I'm not mistaken, this means that using it on a class, such as one named ManagerManager, would be achieved like this:

[DisallowMultipleInScene(typeof(ManagerManager))]
public class ManagerManager : MonoBehaviour
{
    // Implementation
}

This seems a bit redundant, and would also allow passing in the incorrect class name. For disallowing multiple components (classes inheriting from MonoBehaviour) being placed on the same object, the [DisallowMultipleComponent] attribute is used. This attribute is similar to what I'd like. You are not required to pass in the name of the class it is being applied to, it just seems to know.

I had a look at the source in the UnityCsReference GitHub, in an attempt to learn how it works behind the scenes, but there appeared to be no implementation, just a definition, located here, excerpted below:

[RequiredByNativeCode]
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
public sealed class DisallowMultipleComponent : Attribute {}

So for my own implementation, to work similarly to the [DisallowMultipleComponent] attribute, my attribute would need to determine the class it is being applied to, and get a reference to the MonoBehaviour script, so that it can be removed from the object it was just added to.

So, firstly, how does the [DisallowMultipleComponent] attribute get around the requirement of passing the class type in as an attribute parameter, and how can I do it?

And, secondly, how do I get a reference to the newly-created instance of the class annotated with the attribute?





Aucun commentaire:

Enregistrer un commentaire