【问题标题】:C# how do i access a variable in another class?C#如何访问另一个类中的变量?
【发布时间】:2015-05-08 11:01:59
【问题描述】:

这让我得到了类的名称(“SolarPanel”),但我想得到名为“Name”的变量的值(第 30 行的那个)

【问题讨论】:

  • 为什么SolarPanel.Name 不起作用?
  • this.GetType().Name 为您提供类的名称,而不是您创建的常量 Name
  • 我不能使用 SolarPanel.Name,我有更多的类,我希望它是动态的。还有一件事。我创建“SolarPanel”、“Headquaters”等类型的对象,而不是“建筑物”类型的对象。我希望这些信息对您有所帮助
  • 几乎不可能访问嵌套范围内定义的变量。
  • @General-Doomer 不是,但我同意这很痛苦

标签: c# class unity3d member


【解决方案1】:

像这样定义虚拟属性:

/// <summary>
/// name: Building
/// </summary>
public class Building
{
    /// <summary>
    /// name of building
    /// </summary>
    public virtual string Name
    {
        get
        {
            // default name is class name with spaces between upper letters
            StringBuilder sb = new StringBuilder();
            bool wasUpper = false;
            foreach (char c in this.GetType().Name)
            {
                if (char.IsUpper(c))
                {
                    if (!wasUpper)
                    {
                        sb.Append(' ');
                        wasUpper = true;
                    }
                }
                else
                {
                    wasUpper = false;
                }
                sb.Append(c);
            }
            return sb.ToString().Trim();
        }
    }

    public void Construct()
    {
        string buildingName = this.Name;
        // do some work
    }
}

/// <summary>
/// name: Missile Station
/// </summary>
public class MissileStation : Building { }

/// <summary>
/// name: Radar Station "Buk"
/// </summary>
public class RadarBuk : Building
{
    /// <summary>
    /// overriden building name
    /// </summary>
    public override string Name { get { return @"Radar Station ""Buk"""; } }
}

【讨论】:

  • 这是实现问题要求的唯一真正明智的方法
  • @MarkPim 我的回答怎么样? :)
【解决方案2】:

您正在尝试进行向上转换,这是一件坏事(因为 Buildings 类的其他后代可能没有这样的字段)。因此,为了安全起见,您有两种选择:

  • 将字段移至父类(即建筑物)
  • 将 Construct() 方法重写为虚拟方法,以便后代可以更改行为并访问自己的字段

【讨论】:

  • 如何通过存储每个建筑物名称将字段移动到父类,而不会让自己容易出错?至于第二个想法,我不知道该怎么做:(
  • 关于第二个想法:你可以引入一个方法,比如 GetBuildingName(),而不是像“this.GetType().Name”这样的原始代码。将其标记为虚拟并在 Buildings 类的范围内返回空字符串(左右)。然后,在后代中,您可以覆盖 GetBuildingName(),因此在 SolarPanel 类中,此方法可以清楚地返回“this.Name”。
  • 您甚至可以在基础 Buildings 类中将其设为“抽象”,这意味着 Buildings 本身并没有实现它,但所有后代类都可以实现。这会强制您为您创建的所有建筑类型命名。如果您沿着这条路线走,您还必须将“建筑物”类本身标记为抽象。
【解决方案3】:

我假设您正在构造一个继承类的实例,并且您不知道构造时的类型是什么(所以SolarPanel.Name 不是一个选项)。

你可以这样做:

this.getType().GetProperty("Name").GetValue(this, null);

但如果你的所有类型都没有Name 属性,你应该先对GetProperty 进行空检查:

var prop = this.getType().GetProperty("Name");
string name = "";

if (prop != null)
{
    name = prop.GetValue(this, null);
} 

【讨论】:

  • 这不应该存在于生产代码中,我会坚持使用virtual方法/属性或Attributes
【解决方案4】:

这是Attributes的方法:

[AttributeUsage(AttributeTargets.Class)]
public class NameAttribute : Attribute {
    public readonly string Name;

    public NameAttribute(string name) {
        this.Name = name;
    }
}

public static class Extensions {
    /// <summary>
    /// If existant, returns the name tag for given object, else null
    /// </summary>
    public static string GetNameTag(this object instance) {
        return instance.GetType().GetNameTag();
    }

    /// <summary>
    /// If existant, returns the name tag for given type, else null
    /// </summary>
    public static string GetNameTag(this Type type) {
        object[] names = type.GetCustomAttributes(typeof(NameAttribute), false);
        switch(names.Length) {
            case 0:
                return null;
            case 1:
                return ((NameAttribute)names[0]).Name;
            default:
                throw new FormatException();
        }
    }
}

[Name("Headquater")]
public class Headquater : Building {
    // ...
}

[Name("Solar Panel")]
public class Solarpanel : Building {
    // ...
}

现在,您可以这样做:

object panel = new SolarPanel();
Console.WriteLine(panel.GetNameTag());

还有:

Console.WriteLine(typeof(SolarPanel).GetNameTag());

【讨论】:

  • 这是很好的代码,但是对于这个任务来说,Relection 太“重”了。尽可能使用 OOP。
  • 我同意你的观点,但从设计的角度来看,这是干净的代码,除了“名称”应该是要在资源字典中查找的 id,以便为 i18n 做好准备。
【解决方案5】:

我不同意你的班级结构,但我会尽力回答你的问题:

试试这个:

(string)this.GetType().GetField("Name").GetValue(this);

【讨论】:

  • 为了演示完全没问题
  • name 是 const 字段而不是属性
  • 这种方法的问题在于,反射是获取这些信息的一种非常缓慢的方法——如果你最终建造了数千个这样的建筑物,你可能会遇到严重的性能问题。 @General-Doomer 的回答是更好的方法
  • @w33z33,这是因为您的回答是立即修补,而不是永久治愈。主题启动者的代码设计糟糕(因为他似乎是 OOP 的新手),而您的答案是将他推向地狱,而不是从天堂伸出援助之手。 (此外,我没有在这里投反对票)
猜你喜欢
  • 2011-10-22
  • 2015-03-11
  • 2010-10-14
  • 2014-09-30
  • 2015-02-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-02
相关资源
最近更新 更多