【VRChat】Udonで使えるC#と使えないC#:動かないときの見分け方

作成: 2025-12-19最終更新: 2026-09-09

普通のC#が動かないときに、自分のバグかUdonの制約かを見分けます。よく踏む4つの制約と、DataListによる代替の書き方を実際に手を動かして確かめます。

C#の入門書どおりに List<string> を書きました。Unityのエディタは赤くなり、見たことのないエラーが出ます。

書き方は間違っていません。Udonが対応していないだけです。

この見分けがつかないと、正しいコードを何度も書き直すことになります。この記事では、よく踏む制約と、その避け方 を扱います。

C#として正しくても、Udonに翻訳できないものがある

この記事でわかること

  • 制約がある理由
  • よく踏む4つの制約
  • DataList による代替の書き方
  • 使えるかどうかを自分で調べる方法

メソッドとカスタムイベント を試した状態から始めます。

Sponsored


制約があるのは、翻訳しているから

UdonSharpで書いたC#は、そのまま動いているわけではありません。

C#で書いて、Udon向けに翻訳してから動く

書いたコードは、まず Udon という仕組み向けの命令に翻訳されます。動いているのは翻訳後のほうです。

だから、翻訳先に対応する命令がないものは持っていけません。 C#として正しいかどうかは関係ありません。辞書に載っていない単語は訳せない、という話です。

この理解があると、エラーの受け止め方が変わります。「自分の書き方が悪い」ではなく、「これは翻訳できるものか」 と考えられるようになります。

よく踏む4つ

制約の一覧を覚える必要はありません。実際によく踏むのは4つです。

よく踏む4つの制約と、その代わり
使えないもの代わりに
List<T> Dictionary<K,V>DataList DataDictionary
LINQ(Where Select など)for で書く
try / catch事前に null や範囲を確かめる
配列の長さを変える新しい配列を作って詰め替える

いちばん多いのが1行目です。 持ち物リスト、参加者の一覧、スコアの記録。長さが変わるものを扱おうとすると、必ずここに来ます。

VRChatはこのために DataListDataDictionary を用意しています。使い勝手はほとんど同じ なので、置き換えは難しくありません。

残りの3つも、対処は単純です。

// LINQ は for に書き換える
int total = 0;
for (int i = 0; i < scores.Length; i++)
{
    if (scores[i] > 0) total += scores[i];
}

// try-catch の代わりに、先に確かめる
if (target != null && index >= 0 && index < items.Length)
{
    // 安全に使える
}

try / catch が使えないのは、慣れるまで不安に感じます。 ただ、ワールド制作で扱うのは自分が用意したオブジェクトと値です。null かどうかと範囲を先に見ておけば、実用上は困りません。

Sponsored

実践:持ち物リストをDataListで作る

床に置いた3つのアイテムを拾うと、掲示板に持ち物が並ぶ仕掛けを作ります。

1. アイテムと掲示板を置く

床のあるシーンに、次を置きます。

名前作り方と設定
KeyItem MapItem LampItemCube。床の上に3つ並べる。Scale (0.2, 0.2, 0.2)
BagCanvasUI Canvas(World Space)。(0, 1.8, 3)、Scale (0.004, 0.004, 0.004)
BagTextBagCanvas の子に TextMeshPro
BagRootCreate Empty。(0, 0, 0)
3つのアイテムと掲示板の配置

3つのアイテムには、それぞれ VRC Pickup を追加します。掴めるようになります。

2. 入れ物を書く

Assets/ScriptsItemBag を作ります。

using UdonSharp;
using UnityEngine;
using TMPro;
using VRC.SDK3.Data;

[UdonBehaviourSyncMode(BehaviourSyncMode.None)]
public class ItemBag : UdonSharpBehaviour
{
    [SerializeField] private TextMeshProUGUI display;

    private DataList items;   // List<string> の代わり

    private void Start()
    {
        items = new DataList();
        Refresh();
    }

    public void AddItem(string itemName)
    {
        items.Add(itemName);   // 長さを気にしなくてよい
        Refresh();
    }

    private void Refresh()
    {
        string text = "持ち物 " + items.Count + " 個\n";

        for (int i = 0; i < items.Count; i++)
        {
            // 取り出すときは DataToken を経由する
            if (items.TryGetValue(i, TokenType.String, out DataToken token))
            {
                text += "・" + token.String + "\n";
            }
        }

        if (display != null) display.text = text;
    }
}

List<string>DataList に変えただけです。 Add()Count も同じ名前で、for の書き方も変わりません。

違うのは、取り出すときに DataToken を通ること です。DataList はいろいろな型を入れられるので、「これは文字列として取り出したい」と指定します。

型が合わなければ TryGetValuefalse を返します。try / catch が使えない分を、この形が受け持っています。

3. アイテム側を書く

Assets/ScriptsBagItem を作ります。

using UdonSharp;
using UnityEngine;

[UdonBehaviourSyncMode(BehaviourSyncMode.None)]
public class BagItem : UdonSharpBehaviour
{
    [SerializeField] private ItemBag bag;
    [SerializeField] private string itemName = "鍵";

    public override void OnPickup()
    {
        if (bag != null) bag.AddItem(itemName);
        gameObject.SetActive(false);   // 拾ったら消える
    }
}

3つのアイテムそれぞれに付けて、Bagに BagRoot を、Item Nameに 地図 ランタン を入れます。

BagRoot には ItemBag を付けて、Displayに BagText をドラッグします。

4. 確かめる

Playして、3つのアイテムを順に拾います。

順序操作掲示板の表示
1何も拾わない持ち物 0 個
2鍵を拾う持ち物 1 個・鍵
3地図を拾う持ち物 2 個・鍵 ・地図
4ランタンを拾う持ち物 3 個 と3行

配列の長さを気にする処理を、1行も書いていません。 List<T> でやりたかったことが、そのままできています。

Sponsored

使えるかどうかを自分で調べる

新しいメソッドを使いたいとき、先に調べられます。

一覧に出てくれば使える、出てこなければ使えない

Unityのメニューから VRChat SDK → Utilities → Class Exposure Tree を開きます。Udonから触れるクラスとメソッドの一覧です。

使い方は単純です。

  1. 検索欄にクラス名かメソッド名を入れる
  2. 出てくれば使える。出てこなければ使えない

エラーの原因を切り分けるときにも役立ちます。

エラーの様子疑うもの
型名やメソッド名が出ていて、C#としては正しい書き方Udonの制約
つづり違い、; の抜け、括弧の対応自分のミス
インスペクタの割り当てが None制約でもミスでもなく設定

見分けがつかないときは、その1行だけを消してみてください。 通るなら制約、通らないなら他に原因があります。

おまけ:先に知っておくと良いこと

  • DataDictionary もある: 名前で引きたいときは DataDictionary を使います。ContainsKeyTryGetValue があって、使い方は Dictionary に近いものです
  • 文字列の連結は控えめに: + でつなぐのは使えますが、毎フレーム作ると重くなります。表示が変わったときだけ作ってください
  • 配列で足りることも多い: 数が最初から決まっているなら、普通の配列がいちばん軽くて確実です。長さが変わるときだけ DataList にします
  • 公式のサンプルを読む: SDKに入っているサンプルは、当然すべて動く書き方です。迷ったら、そこにある形をまねるのが早道です
  • 制約は緩んでいくもの: SDKの更新で使えるようになるものもあります。古い記事で「使えない」とあっても、いま試すと通ることがあります

まとめ

Udonの制約は、翻訳できるかどうかの問題です。

  • C#として正しくても、Udonに命令がなければ動かない
  • よく踏むのは、List・LINQ・try-catch・可変長配列の4つ
  • ListDictionaryDataListDataDictionary で置き換えられる
  • 使えるかどうかは Class Exposure Tree で調べられる

エラーを見たときの問いかけは、「これはC#の書き方の問題か、翻訳できるかの問題か」 です。ここを分ければ、直す先がすぐ決まります。

動かない原因を追いたいなら 動かないときの直し方、仕掛けを軽くするなら Udonを軽くする へ進んでください。

VRChat このセクションのノート63