【问题标题】:How to store random class variable in way that can be accessed from other methods in C#?如何以可以从 C# 中的其他方法访问的方式存储随机类变量?
【发布时间】:2018-06-11 19:50:01
【问题描述】:

我需要一个随机类,存储到一个“全局类”变量中(这样我就可以用其他方法访问它),但是我找不到任何好的方法来做,我一直在尝试做正在使用对象变量...我是从 python 到 c#,所以对象变量的属性对我来说看起来有点神秘...我一直在寻找如何使它工作,但我找不到合适的没有一堆 if 语句的方法......

//There might not be all the necessary namespaces to run this code
using UnityEngine; //where the random.range() came from

public class man1 //Initialization of the first class
{
    public int val = 1;
}

public class man2 //Initialization of the second class
{
    public int val = 2;
}

public class man3 //Initialization of the third class
{
    public int val = 3;
}

public class allMan
{ //Where all classes 'merge'

    private object chosenMan; //Where the chosen it's going to be stored

    public allMan() //Constructor
    {
        //Have all man in one array to easily get the chosen from index
        object[] men = new object[] { new man1(), new man2(), new man3() }; 
        var choice = Random.range(0, men.Length); //Randomly get the index
        chosenMan = men[choice]; // Atribute the chosen class
    }
    public void doActionWithChoosedMan()
    {
        Console.WriteLine(chosenMan.val); //ERROR
    }
}

我应该如何解决这个问题?谢谢。

【问题讨论】:

  • 类 man1、man2 和 man3 没有提供足够的细节来说明您为什么会这样做。您介意使用 man1、2 和 3 的另一个示例,它们的功能与您实际想要的类似,说明您这样做的原因吗?
  • 你可能只是有一个非常糟糕的例子。但是,如果所有类共享共同特征,则创建一个基类来表示共同特征并让所有类都派生自共同基类。然后,您将选择的对象作为基类类型。
  • 尝试以下匿名定义:var men = new { man1 = new man1(), man2 = new man2(), man3 = new man3() };
  • 它是一个(伪)随机数生成器,那么为什么不能在需要它们的地方创建任意数量的随机数呢?输出不会改变

标签: c# arrays class oop typed


【解决方案1】:

虽然@programtreasures 发布了一个很好的即时解决方案,但您需要考虑到 C# 是一种强类型语言。这意味着,与 python 和 javascript 不同,您不能尝试随机访问对象上未声明的属性和方法。

请注意,在您演示的案例中,您的 3 个班级之间没有区别。它们应该只是 Man 类型的实例,就像这样

class Man 
{
 public int Val { get; set; } // try to use properties to hold externally accessible values
}

public class AllMan // c# uses Pascal casing
{ //Where all classes 'merge'

    private Man chosenMan; //Where the chosen it's going to be stored

    public AllMan() //Constructor
    {
        //Have all man in one array to easily get the chosen from index
        var men = new Man[] { new Man() { Val = 1 }, new Man() { Val = 2 }, new Man() { Val = 3 } }; 
        var choice = Random.range(0, men.Length); //Randomly get the index
        chosenMan = men[choice]; // Atribute the chosen class
    }

    public void DoActionWithChoosedMan()
    {
        Console.WriteLine(chosenMan.Val);
    }
}

对于需要你在类型上有差异的东西,你可以声明一个接口,例如

interface IMan
{
int Val {get;}
}

然后让你的不同类型实现这个:

class Man1 : IMan
{
public int Val {get;} = 1;
public string SomethingElse {get;set;}
}

class Man2 : IMan
{
public int Val {get;} = 2;
public boolean AmICool {get;set;}
}

然后你可以像上面一样运行代码,但是将chosenMan字段的类型更改为IMan

此外,您可能还想实现一个abstract 基类来只保存您需要的属性,然后将其余的东西堆叠在上面。这取决于默认初始化是否跨类共享,以及是否有其他常见的需要实现的东西。

【讨论】:

    【解决方案2】:

    解决方案 1: 在 doActionWithChoosedMan() 方法中,您直接使用了 selectedMan,但这不是正确的做法。

    在使用它之前,你必须检查 selectedMan 的类型 由

    if(chosenMan.GetType() == typeof(man1)){
                man1 man11= new man1();
                Console.WriteLine(man11.val); //No Error
    }if(chosenMan.GetType() == typeof(man2)){
                man1 man22= new man1();
                Console.WriteLine(man22.val); //No Error
    }if(chosenMan.GetType() == typeof(man3)){
                man1 man33= new man1();
                Console.WriteLine(man33.val); //No Error
    }
    

    同样你必须检查所有对象然后创建主类的对象,这里是“man1”,然后你就可以访问“val”了。

    解决方案 2:您可以让 selectedMan 动态化。

    【讨论】:

    • 我不明白这有什么作用?所有案例都做同样的事情。代码都可以简化为Console.WriteLine(new man1().val); 此外,您可能希望使用else if 以避免不必要的比较。
    【解决方案3】:

    编译器将一个变量键入为对象,编译器将验证所有实例成员是否有效。另一个变量是动态类型的,编译器将忽略所有实例成员,并在执行时由 DLR 调用。

    您可以使用dynamic 代替object

     public class allMan
       { 
        //Where all classes 'merge'
    
        private dynamic chosenMan; //Where the chosen it's going to be stored
    
        public allMan() //Constructor
        {
            //Have all man in one array to easily get the chosen from index
            object[] men = new object[] { new man1(), new man2(), new man3() };
            var choice = Random.range(0, men.Length); //Randomly get the index
            chosenMan = men[choice]; // Atribute the chosen class
        }
        public void doActionWithChoosedMan()
        {
            Console.WriteLine(chosenMan.val); //ERROR
        }
    }
    

    【讨论】:

    • @OP 如果你选择这样做,请注意,这通常不是一个很好的 C# 实践
    • 为什么会不好?
    • 使用动态也不会增加运行时的工作量,而且您不会在编译时获得类型检查的优势。当它可以使用继承/接口完成时(根据 Zaitsman 的回答),那么为什么要使用动态?
    • @KaiqueSantos 动态是不好的做法(除了 CreativeManix 提到的事情),因为它告诉任何阅读您的代码的人您不知道该对象将具有什么类型。而只需阅读您的代码,他们就可以看到它在编译时是已知的。编译语言的想法通常是在开发时尝试捕获任何错误,而不是运行代码。 (原因是,运行代码的可能是用户,而不是开发人员)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-08-23
    • 1970-01-01
    • 2012-08-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多