UnityEngine.RandomとSystem.Randomがあいまいなのを解決する

タイトルの通りですが、以下のように2つの名前空間を using すると Unity のクラス名と C# の標準ライブラリのクラス名が同じためエラーが出ます。

using System;
using UnityEngine;

public static class Sample
{
    public static void Foo()
    {
        // エラー CS0104 'Random' は、'UnityEngine.Random' と 'System.Random' 間のあいまいな参照です
        Random
    }
}

これは解決法が2つあります。

完全修飾名で宣言する

1つめですが Random クラスを使うときに名前空間事指定する方法です。

// 完全な名前を指定して Unity の Random クラスを使用する
UnityEngine.Random.Range(...);

// 完全な名前を指定して C# 標準の Random クラスを使用する(まぁこっちは使わないと思いますが…)
System.Random r = new System.Random();

但し毎回使用するたびに完全な名前を指定しないといけないので少し面倒です。

使用するほうに別名を付与する

2つめは、使用するクラスに別名を付ける方法です。

using System;
using UnityEngine;

// ★ Unity の Random クラスに UniRandom という別名を定義
using UniRandom = UnityEngine.Random;

public static class Sample
{
    public static void Foo()
    {
        // こうすればエラーが出ない
        UniRandom.Range(...);
    }
}

この場合、各ファイルの冒頭に宣言する必要があります。宣言はそのファイルの中でしか有効でないので、ほかのファイルに定義することは出来ません。

別名で完全にラップしてしまう

この方法は、新しい別の名前のクラスを作成してそちらを使用するようにします。使うときに毎回何か特別な事をするのが面倒な場合、別名を付けて完全にラップしたクラスを使用することで名前の重複を回避できます。(Unity の Random クラスは static なのでこういう宣言を適用しやすいです)

以下、UnityEngine.Random を UniRandom という名前で完全にラップする実装例です(もうこのままコピペして使えばいいのかも)

/// <summary>
/// <para>ゲーム用のランダムデータを簡単に生成できます。</para>
/// <para><see cref="UnityEngine.Random"/><see cref="System.Random"/> の名前が紛らわしいのを解決します。</para>
/// </summary>
public static class UniRandom
{
    /// <summary>
    /// 一様分布のランダムな回転を返します(読み取り専用)
    /// </summary>
    public static Quaternion rotationUniform
    { 
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        get => Random.rotationUniform; 
    }

    /// <summary>
    /// ランダムな回転を返します(読み取り専用)
    /// </summary>
    public static Quaternion rotation
    {
        [MethodImpl(MethodImplOptions.AggressiveInlining)] 
        get => Random.rotation;
    }

    /// <summary>
    /// 半径1.0の球体の表面上のランダムな点を返します(読み取り専用)
    /// </summary>
    public static Vector3 onUnitSphere
    {
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        get => Random.onUnitSphere;
    }
    
    /// <summary>
    /// 乱数生成器の完全な内部状態を取得または設定します(読み取り専用)
    /// </summary>
    public static Random.State state
    {
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        get => Random.state;
    }
    
    /// <summary>
    /// 0.0~1.0]の範囲のランダムな浮動小数点数を返します(読み取り専用)
    /// </summary>
    public static float value
    {
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        get => Random.value;
    }

    /// <summary>
    /// 半径1.0の球体の内側または上にあるランダムな点を返します(読み取り専用)
    /// </summary>
    public static Vector3 insideUnitSphere
    {
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        get => Random.insideUnitSphere;
    }

    /// <summary>
    /// HSVとアルファの範囲からランダムな色を生成します。
    /// </summary>
    /// <param name="hueMin">Minimum hue [0..1].</param>
    /// <param name="hueMax">Maximum hue [0..1].</param>
    /// <param name="saturationMin">Minimum saturation [0..1].</param>
    /// <param name="saturationMax">Maximum saturation [0..1].</param>
    /// <param name="valueMin">Minimum value [0..1].</param>
    /// <param name="valueMax">Maximum value [0..1].</param>
    /// <param name="alphaMin">Minimum alpha [0..1].</param>
    /// <param name="alphaMax">Maximum alpha [0..1].</param>
    /// <returns>
    /// HSV値とアルファ値を(含む)入力範囲に持つ,ランダムな色.値の値を線形補間することで、各成分の値を導き出します。
    /// </returns>
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static Color ColorHSV(float hueMin, float hueMax, 
                                 float saturationMin, float saturationMax, 
                                 float valueMin, float valueMax, float alphaMin, float alphaMax)
    {
        return Random.ColorHSV(hueMin, hueMax,
                               saturationMin, saturationMax,
                               valueMin, valueMax,
                               alphaMin, alphaMax);
    }

    /// <summary>
    /// HSVとアルファの範囲からランダムな色を生成します。
    /// </summary>
    /// <returns>
    /// HSV値とアルファ値を(含む)入力範囲に持つ,ランダムな色.値の値を線形補間することで、各成分の値を導き出します。
    /// </returns>
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static Color ColorHSV() => Random.ColorHSV();

    /// <summary>
    /// HSVとアルファの範囲からランダムな色を生成します。
    /// </summary>
    /// <param name="hueMin">Minimum hue [0..1].</param>
    /// <param name="hueMax">Maximum hue [0..1].</param>
    /// <returns>
    /// HSV値とアルファ値を(含む)入力範囲に持つ,ランダムな色.値の値を線形補間することで、各成分の値を導き出します。
    /// </returns>
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static Color ColorHSV(float hueMin, float hueMax) => Random.ColorHSV(hueMin, hueMax);

    /// <summary>
    /// HSVとアルファの範囲からランダムな色を生成します。
    /// </summary>
    /// <param name="hueMin">Minimum hue [0..1].</param>
    /// <param name="hueMax">Maximum hue [0..1].</param>
    /// <param name="saturationMin">Minimum saturation [0..1].</param>
    /// <param name="saturationMax">Maximum saturation [0..1].</param>
    /// <returns>
    /// HSV値とアルファ値を(含む)入力範囲に持つ,ランダムな色.値の値を線形補間することで、各成分の値を導き出します。
    /// </returns>
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static Color ColorHSV(float hueMin, float hueMax, float saturationMin, float saturationMax)
    {
        return Random.ColorHSV(hueMin, hueMax, saturationMin, saturationMax);
    }

    /// <summary>
    /// HSVとアルファの範囲からランダムな色を生成します。
    /// </summary>
    /// <param name="hueMin">Minimum hue [0..1].</param>
    /// <param name="hueMax">Maximum hue [0..1].</param>
    /// <param name="saturationMin">Minimum saturation [0..1].</param>
    /// <param name="saturationMax">Maximum saturation [0..1].</param>
    /// <param name="valueMin">Minimum value [0..1].</param>
    /// <param name="valueMax">Maximum value [0..1].</param>
    /// <param name="alphaMin">Minimum alpha [0..1].</param>
    /// <param name="alphaMax">Maximum alpha [0..1].</param>
    /// <returns>
    /// HSV値とアルファ値を(含む)入力範囲に持つ,ランダムな色.値の値を線形補間することで、各成分の値を導き出します。
    /// </returns>
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static Color ColorHSV(float hueMin, float hueMax, 
                                 float saturationMin, float saturationMax, float valueMin, float valueMax)
    {
        return Random.ColorHSV(hueMin, hueMax, saturationMin, saturationMax, valueMin, valueMax);
    }

    //
    // 概要:
    //     Initializes the random number generator state with a seed.
    //
    // パラメーター:
    //   seed:
    //     Seed used to initialize the random number generator.
    /// <summary>
    /// 乱数生成器の状態をシードで初期化します。
    /// </summary>
    /// <param name="seed">乱数生成器を初期化するためのシード。</param>
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static void InitState(int seed) => Random.InitState(seed);

    /// <summary>
    /// min ~ max 以内のランダムな int を返します。
    /// </summary>
    /// <param name="minInclusive">最小値</param>
    /// <param name="maxExclusive">最大値(この値は含まない)</param>
    /// <returns></returns>
    [MethodImpl(MethodImplOptions.AggressiveInlining)] 
    public static int Range(int minInclusive, int maxExclusive) => Random.Range(minInclusive, maxExclusive);

    /// <summary>
    /// min ~ max 以内のランダムな float を返します。
    /// </summary>
    /// <param name="minInclusive">最小値</param>
    /// <param name="maxExclusive">最大値(この値を含む)</param>
    /// <returns></returns>
    [MethodImpl(MethodImplOptions.AggressiveInlining)] 
    public static float Range(float minInclusive, float maxInclusive) 
    {
        return Random.Range(minInclusive, maxInclusive);
    }
}

重複している Random と Debug クラスはこういった方法で最初からぶつからないようにしておいた方がいいのかもしれませんね。