What's the best way to store a reference to a script asset?

To clarify, at runtime I’m looking to create and add a script to an object based on what type the reference has. This functionality already exists in the form of MonoScript (ScriptReference/MonoScript.html). However MonoScript only works in the editor.

I’ve considered the following 2 approaches but they seem either inefficient or error prone:

  1. Use string properties and call gameObject.AddComponent(myString)
  2. Store script asset references as a TextAsset and then call gameObject.AddComponent(myTextAsset.name);

Option 2 might be ok but I don’t want Unity to load up the whole script file just to get its name.

Is there a better way?

You can probably just use an object reference or component reference and use AddComponent.
http://docs.unity3d.com/Documentation/ScriptReference/Object.html

http://docs.unity3d.com/Documentation/ScriptReference/Component.html

Scripts are compiled into an assembly and so are all available at runtime. I do not know if the representative assets have to be loaded however.

I would just input the name of the script using a regular string variable.

If you are using Unity 4 then you can implement a custom property drawer and attribute to achieve drag & drop in the inspector:

Usage:

public class SomeBehaviour : MonoBehaviour {
    [ScriptPicker]
    public string myScriptName;

    public void Foo() {
        gameObject.AddComponent(myScriptName);
    }
}

Attribute Implementation:

using UnityEngine;

public class ScriptPickerAttribute : PropertyAttribute {
}

Drawer Implementation:

using UnityEngine;
using UnityEditor;

[CustomPropertyDrawer(typeof(ScriptPickerAttribute))]
public class ScriptPickerPropertyDrawer : PropertyDrawer {
    public override void OnGUI(Rect position, SerializedProperty prop, GUIContent) {
        Rect rect;
        
        int controlID = GUIUtility.GetControlID(FocusType.Passive);
        int objectFieldWidth = 45;
        
        // Detect drag & drop
        CheckDragAndDrop(position, prop, controlID);
        
        // Allow manual text entry
        rect = new Rect(
            position.x,
            position.y,
            position.width - objectFieldWidth - 2,
            position.height
        );
        prop.stringValue = EditorGUI.TextField(
            rect, label, prop.stringValue
        );
        
        // Allow drag & drop or selection from dialog
        rect = new Rect(
            position.xMax - objectFieldWidth,
            position.y,
            objectFieldWidth,
            position.height
        );
        MonoScript script = (MonoScript)EditorGUI.ObjectField(
            rect, null, typeof(MonoScript), false
        );
        if (script != null) {
            prop.stringValue = script.name;
        }
    }
    
    private void CheckDragAndDrop(Rect position, SerializedProperty prop, int controlID) {
        Event e = Event.current;
        EventType eventType = e.GetTypeForControl(controlID);
        switch (eventType) {
            case EventType.DragUpdated:
            case EventType.DragPerform:
                if (position.Contains(e.mousePosition)
                    && DragAndDrop.objectReferences.Length == 1
                    && DragAndDrop.objectReferences[0] is MonoScript)
                {
                    if (eventType == EventType.DragUpdated) {
                        DragAndDrop.visualMode = DragAndDropVisualMode.Generic;
                        DragAndDrop.activeControlID = controlID;
                    }
                    else {
                        prop.stringValue = DragAndDrop.objectReferences[0].name;
                        DragAndDrop.AcceptDrag();
                        DragAndDrop.visualMode = DragAndDropVisualMode.None;
                    }
                    e.Use();
                }
                break;
        }
    }
}