按名称

时间:2017-10-09 22:02:02

标签: c# arrays unity3d

我有一组像这样的整数数组 -

public int[] box1 = {1, 0, 2};
public int[] box2 = {3, 1, 0};
public int[] box3 = {2, 3, 1};

我需要做的是通过唯一的数组名称动态访问它们,并从中返回一个随机元素,使用类似的东西 -

foo="box"+2[random int];

其中foo是我的临时字符串,包括“box”前缀,添加我想要的数字“box”,并从“box2”获取一个随机元素。 (例如:foo = 3)

如果我通过字符串方法执行此操作,它会创建正确的nomanclature,但它只是一个字符串,我不能使用它来在脚本中实际访问这些作为实际的类/数组元素并将它们传递给其他东西。

我该怎么做呢?读了几个小时的手册,尝试过清单,但我想我做的不对。谢谢!

2 个答案:

答案 0 :(得分:3)

只要打破你真正想要做的事情,你会发现它是多么容易。就像我在评论部分中提到Dictionary一样,您仍然需要另外两个C#功能来完成确切的语法。

您希望能够这样做:

foo="box"+2[random int];

与此相同:

int valueFromArray  = arrayVariableName [index];

在下面的示例中,我们可以假设MyScript是我们脚本的名称。

1 。您需要能够保存名称和int数组的字典。

Dictionary<string, int[]> boxes

2 。您需要一种方法将 "box"+2 arrayVariableName 转换为当前的脚本实例。这可以通过C#中的隐式转换运算符功能来完成。您可以将 "box"+2 arrayVariableName 传递到此隐式MyScript中,然后将其存储到全局变量中以进行下一步。

//The global variable that holds the arrayVariableName to access
static string targetBox = null;

//Implicit conversion operators (box array name to this script(MyScript) instance)
public static implicit operator MyScript(string box)
{
    return setTargetAndGetInstance(box);
}

public static MyScript setTargetAndGetInstance(string box)
{
    if (instance.boxes.ContainsKey(box))
    {
        //Set the box requested. This will be needed in the Indexer overloading above
        targetBox = box;
        return instance;
    }
    else
        return null;
}

3 。现在,您可以实施 [index] 语法。这可以通过索引器重载功能来完成。

//Indexer overloading (index to int (value in array))
public int this[int index]
{
    get
    {
        //Get value based on value set in the implicit operators
        return accessBox(targetBox, index);
    }
}

现在,当您执行 "box"+2 时,它会在MyScript转换运算符的帮助下返回此实例(implicit)。然后,它会允许您使用索引器重载功能执行 [random int]

下面的代码是您的问题中的语法示例以及执行此操作的其他类似方法。 包括类似的,因为它们看起来比您要求的更好

功能简单:

int test1 = accessBox("box" + 2, UnityEngine.Random.Range(0, 3));
Debug.Log(test1);

使用arrayVariableName [index]语法:

你正在寻找这个但是MyScript的演员看起来很糟糕

int test2 = ((MyScript)("box" + 2))[UnityEngine.Random.Range(0, 3)];
Debug.Log(test2);

使用[arrayVariableName][index]语法:

int test3 = this["box" + 2][UnityEngine.Random.Range(0, 3)];
Debug.Log(test3);

使用[arrayVariableName, index]语法

int test4 = this["box" + 2, UnityEngine.Random.Range(0, 3)];
Debug.Log(test4);

完整的功能示例:

using System.Collections.Generic;
using UnityEngine;

public class MyScript : MonoBehaviour
{

    public int[] box1 = { 1, 0, 2 };
    public int[] box2 = { 3, 1, 0 };
    public int[] box3 = { 2, 3, 1 };


    public Dictionary<string, int[]> boxes = new Dictionary<string, int[]>();
    private static MyScript instance;

    void Awake()
    {
        instance = this;

        //Add to Dictionary
        addBox();

        int test1 = accessBox("box" + 2, UnityEngine.Random.Range(0, 3));
        Debug.Log(test1);

        int test2 = ((MyScript)("box" + 2))[UnityEngine.Random.Range(0, 3)];
        Debug.Log(test2);

        int test3 = this["box" + 2][UnityEngine.Random.Range(0, 3)];
        Debug.Log(test3);

        int test4 = this["box" + 2, UnityEngine.Random.Range(0, 3)];
        Debug.Log(test4);
    }

    void addBox()
    {
        boxes.Add("box1", box1);
        boxes.Add("box2", box2);
        boxes.Add("box3", box3);
    }

    public int accessBox(string box, int index)
    {
        //Return the array from the Dictionary
        int[] tempVar;
        if (boxes.TryGetValue(box, out tempVar))
        {
            //Return the spicified index
            return tempVar[index];
        }
        else
        {
            //ERROR - return -1
            return -1;
        }
    }


    //Indexer overloading (index to int (value in array))
    public int this[int index]
    {
        get
        {
            //Get value based on value set in the implicit operators
            return accessBox(targetBox, index);
        }
    }

    static string targetBox = null;

    //Implicit conversion operators (box array name to this script(MyScript) instance)
    public static implicit operator MyScript(string box)
    {
        return setTargetAndGetInstance(box);
    }

    public static MyScript setTargetAndGetInstance(string box)
    {
        if (instance.boxes.ContainsKey(box))
        {
            //Set the box requested. This will be needed in the Indexer overloading above
            targetBox = box;
            return instance;
        }
        else
            return null;
    }

    //Indexer overloading (box array name to this script(MyScript) instance)
    public MyScript this[string box]
    {
        get
        {
            return setTargetAndGetInstance(box);
        }
    }

    //Indexer overloading (box array name to int)
    public int this[string box, int index]
    {
        get
        {
            setTargetAndGetInstance(box);
            return accessBox(box, index);
        }
    }
}

答案 1 :(得分:1)

以下是使用Dictionary<TKey,TValue>的问题的通用解决方案:

主要代码:

using System;
using System.Collections.Generic;

public class Class1
{
    public void Example()
    {
        // a dictionary with string keys

        var string1 = "abcd";
        var string2 = "efgh";

        var dictionary1 = new Dictionary<string, int[]>
        {
            {string1, new[] {0, 1, 2}},
            {string2, new[] {3, 4, 5}}
        };


        // a dictionary with custom type

        var box1 = new Box(10, 10);
        var box2 = new Box(20, 20);

        var dictionary2 = new Dictionary<Box, int[]>
        {
            {box1, new[] {0, 1, 2}},
            {box2, new[] {3, 4, 5}}
        };

        // get random value from both dictionnaries

        var i1 = GetRandomInteger(dictionary1, string1);
        var i2 = GetRandomInteger(dictionary2, box1);
    }

    private int GetRandomInteger<TKey>(IDictionary<TKey, int[]> dictionary, TKey key)
    {
        if (!dictionary.ContainsKey(key))
            throw new KeyNotFoundException();

        var array = dictionary[key];

        // prefer UnityEngine.Random here since it's static 
        var index = new Random().Next(array.Length);

        var value = array[index];

        return value;
    }
}

额外代码:

public struct Box
{
    // a dictionary key should be immutable, therefore I use a struct
    // implement equality members so that when querying the dictionary,
    // it will find the value associated to the key
    // see https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/how-to-define-value-equality-for-a-type

    public int Width { get; }
    public int Height { get; }

    public Box(int width, int height)
    {
        Width = width;
        Height = height;
    }

    public bool Equals(Box other)
    {
        return Width == other.Width && Height == other.Height;
    }

    public override bool Equals(object obj)
    {
        if (ReferenceEquals(null, obj))
            return false;
        return obj is Box && Equals((Box) obj);
    }

    public override int GetHashCode()
    {
        unchecked
        {
            return (Width * 397) ^ Height;
        }
    }

    public static bool operator ==(Box left, Box right)
    {
        return left.Equals(right);
    }

    public static bool operator !=(Box left, Box right)
    {
        return !left.Equals(right);
    }
}