TypeSelector
Окно выбора типа, которое вы настраиваете под каждое поле.
Быстрый старт
[TypeSelector(typeof(ITwoHanded), Allow = TypeAllow.None)]
[SerializeField] private SerializableType<Weapon> _weapon;
Поле предлагает только конкретное двуручное оружие: наследников Weapon, реализующих ITwoHanded.
| Без атрибута | С [TypeSelector] |
|---|---|
![]() ![]() | ![]() ![]() |
Где применяется
| Поле | Результат выбора |
|---|---|
string | Записывается assembly-qualified name |
| Serializable Types | Настраивается выбор обёртки |
[SerializeReference] | Создаётся экземпляр выбранной реализации — см. SerializeReference Selector |
В плеере строковое поле находит тип по имени, как Serializable Types: класс, который используется только через такой выбор, может быть вырезан при Managed Stripping Level Low и выше.
Какие типы в списке
public interface ITwoHanded { }
public abstract class Weapon { }
public abstract class MeleeWeapon : Weapon { }
public abstract class RangedWeapon : Weapon { }
public sealed class Sword : MeleeWeapon { }
public sealed class Axe : MeleeWeapon, ITwoHanded { }
public sealed class Bow : RangedWeapon, ITwoHanded { }
Типы в атрибуте сужают список: остаются только классы, совместимые со всеми сразу.
Аргументы [TypeSelector] на поле string | В списке |
|---|---|
typeof(Weapon) | Weapon, MeleeWeapon, RangedWeapon, Sword, Axe, Bow |
typeof(Weapon), typeof(ITwoHanded) | Axe, Bow |
typeof(Sword), typeof(Axe) | Пусто |
typeof(MeleeWeapon), Allow = TypeAllow.None | Sword, Axe |
T обёртки и тип поля [SerializeReference] работают как ещё один тип в атрибуте:
// Axe, Bow
[TypeSelector(typeof(ITwoHanded))]
[SerializeField] private SerializableType<Weapon> _twoHandedType;
// Axe, Bow
[TypeSelector(typeof(ITwoHanded))]
[SerializeReference] private Weapon _twoHandedWeapon;
В инспекторе runtime-объекта селектор не предлагает типы из editor-only сборок (UnityEditor, asmdef только для Editor и папки Editor): в билде плеера они не найдутся.
Свойства
| Свойство | По умолчанию | Поведение |
|---|---|---|
Allow | TypeAllow.All | Пускает в список абстрактные классы (Abstract), интерфейсы (Interface), оба вида или ни один. На [SerializeReference] игнорируется |
Required | false | Предупреждает о пустом имени типа или null в managed-ссылке |
Обязательное поле
[TypeSelector(typeof(Weapon), Required = true)]
[SerializeField] private string _secondaryWeapon;


С Required = true пункт <None> остаётся доступным. Потерянный тип с сохранённым именем проверку проходит.
Настройка проверки по всему проекту и в CI описана в разделе проверки обязательных полей.
Ограничение из другого поля
Передайте nameof(...), чтобы текущее значение поля или свойства управляло списком кандидатов:
[SerializeField] private SerializableType<Weapon> _weaponClass;
[TypeSelector(nameof(_weaponClass), Allow = TypeAllow.None)]
[SerializeField] private string _weaponName;
Выберите MeleeWeapon в Weapon Class — Weapon Name предложит его конкретных наследников. Смена ограничения не очищает ранее выбранное имя.


| Источник ограничения | Базовый тип |
|---|---|
System.Type | Значение поля |
string | Тип по имени через Type.GetType() |
SerializableType / SerializableMonoScript | Значение .Type |
| Массив этих значений | Каждый элемент; List<T> не поддерживается |
- У поля внутри
[Serializable]-класса или элемента списка источник читается из того же экземпляра. - Пока источник пуст или не разрешился, ограничения от него нет: строковый Weapon Name предложит все конкретные типы. У обёртки остаётся её собственный
T.
Ошибки в строковых аргументах
Если имя типа записано верно, но такой тип не загружен, инспектор показывает предупреждение:
[TypeSelector("Spear, Assembly-CSharp")]
[SerializeField] private string _weaponName;


TypeSelectorDisplay
[TypeSelectorDisplay] на классе меняет только его строку в окне выбора:
Параметр на Sword | В окне выбора |
|---|---|
Name = "Longsword" | Longsword в списке и в закрытом поле; поиск находит и по Sword |
Group = "Weapons/Melee" | Weapons → Melee → Longsword вместо namespace |
Tooltip = "A balanced blade" | Подсказка при наведении |
Icon = "d_ScriptableObject Icon" | Иконка: встроенная по имени, ассет по пути с расширением или из Resources без расширения |
Hidden = true | Нет в списке; присваивание из кода и уже сохранённое значение работают |
Подклассы настроек не наследуют.


[TypeSelector] и [TypeSelectorDisplay] помечены [Conditional("UNITY_EDITOR")]. В классах из внешней DLL, собранной без этого символа, их настроек нет, включая Hidden.
Окно выбора
Окно группирует типы по namespace или Group и различает одинаковые имена по сборкам.


На корневой странице окно держит типы, которые нужны чаще других:
- Favorites — избранное. Чтобы добавить тип, нажмите звёздочку справа от его строки или Space, когда строка выделена.
- Recent — последние выбранные типы.
Показ Favorites и длина Recent (0 скрывает раздел) настраиваются во вкладке Settings окна FastTools. Её открывает шестерёнка в правом нижнем углу окна выбора, там же оба списка очищаются.
Generic-типы
При выборе открытого generic-типа окно предлагает выбрать аргументы и возвращает сконструированный закрытый тип:
public abstract class Enchantment { }
public sealed class Fire : Enchantment { }
public sealed class Frost : Enchantment { }
public sealed class Enchanted<T> : Weapon
where T : Enchantment { }
Выберите Enchanted<T> в поле SerializableType<Weapon> — окно предложит наследников Enchantment, а после выбора Fire запишет Enchanted<Fire>.


- Generic-аргумент может сам быть generic-типом: окно сначала спросит его аргументы.
- Если все аргументы выводятся из типа поля, закрытый тип возвращается сразу.
- Интерфейсы, абстрактные классы и скрытые типы в аргументах не предлагаются.
TypeSelectorWindow
TypeSelectorWindow открывает то же окно из кастомного инспектора или окна редактора, например по кнопке UI Toolkit:
using Aspid.FastTools.Types.Editors;
var button = new Button { text = "Select weapon" };
button.clicked += () => TypeSelectorWindow.Show(
screenRect: GUIUtility.GUIToScreenRect(button.worldBound),
filter: new TypeSelectorFilter
{
Types = new[] { typeof(Weapon) }
},
currentAqn: selectedTypeName,
onSelected: aqn => selectedTypeName = aqn);
Обработчик получает assembly-qualified name или null при выборе <None>.
У TypeSelectorFilter Allow по умолчанию TypeAllow.None, а у [TypeSelector] — TypeAllow.All: окно выше предлагает только конкретное оружие.
Свойства фильтра и параметры окна — в справочнике API: TypeSelectorFilter, TypeSelectorWindow.
Пример в пакете
Зависимый список, имена из [TypeSelectorDisplay] и обязательное поле показаны в примере Types, а окно выбора из редакторского кода — в EditorTools.





