为什么在静态方法中无法访问我声明的非静态字段?



嗨,我是 C# 的新手,我知道在表面上我不能在静态方法中使用非静态字段。但我有一个我试图从概念上理解的情况。

查看此代码片段:

class CIMConversionHelper
{
private static Logger Logger = LogManager.GetCurrentClassLogger();
private readonly ProcessingEndTimeData _procEndTimeData = new ProcessingEndTimeData();
public static TDX2KlarfResult HandleConversion(TDXProcessItem item, string fileName)
{
TDX2KlarfResult result = new TDX2KlarfResult();
result.success = true;

XmlDocument doc = new XmlDocument();
try
{
doc.Load(fileName);
}
catch (Exception ex)
{

result.success = false;
Logger.Error(ex, "XML Parsing Error: ");
return result;
}

_procEndTimeData.ToolType = toolType;
_procEndTimeData.Lot = input.cimToolContext.LOT;
_procEndTimeData.WaferScribe = input.cimWaferContainer.waferContext.WAFER_SCRIBE;
_procEndTimeData.Processing_End_Time = input.cimToolContext.PROCESSING_END_TIME;

}
public static TDX2KlarfResult Convert(TDXProcessItem item, string fileName)
{
TDX2KlarfResult result = new TDX2KlarfResult();
result.success = true;
try
{
result = CIMConversionHelper.HandleConversion(item, fileName);
}
catch (Exception ex)
{
// Failed to Parse the xml Not good mark nonrecoverable error and return.
result.errorType = "Non-Recoverable";
result.success = false;
Logger.Error(ex, "Unknown Error: ");
return result;
}
if (result.success)
{
//DBHelper.AddProcessingEndTimeToDB();
}
return result;
}
}

这是一个非常精简的片段,但抓住了我的问题。我创建了一个对象引用作为名为 _procEndTimeData 的 ProcessingEndTimeData 字段。

那么为什么它在Visual Studio中告诉我: "非静态字段、方法或属性CIMConversionHelper._procEndTimeData是否需要对象引用?

我想我应该能够为静态函数"HandleConversion"内第 4 行中的声明对象"_procEndTimeData"赋值

有人可以向我解释为什么这个参考还不够吗?为什么我必须在静态函数 HandleCOnversion 中创建另一个 ProcessingEndTimeData 对象?

我知道我可以将_procEndTimeData切换为静态,但是如果我已经在字段级别创建了引用,为什么还需要这样做呢?

想想设备的内存。

创建对象时,将为其保留内存。想象一下,由于它的属性(int,char...),它占用了32个字节。如果创建 10 个对象,则对象的内存中将占用 320 个字节。

但是,当您使用"static"时,这些属性仅为类创建一次。对于您创建的每个对象,不要一次。

因此,您的 10 个对象可以访问它们自己的属性(int、char...)以及静态属性。但是从"静态"方法中,您无法访问该类对象的属性,因为您没有它的实例。

一个非常简单的示例:您有一个具有 Name 属性的 User 类。添加整数类型的静态变量:静态整数计数。该变量将用于记录您创建的用户数。 在用户的构造函数中,您可以执行count++,因为类的实例可以访问类的属性。但是,如果您创建一个静态方法:

public static void DoSomething()
{
// You can show a message with the number of users
MessageBox.Show(count.ToString());
// But you CAN'T access to a "Name" because this method is not 
// a method of one concrete user. It's a general method, for all users
}

如果你调用DoSomething,并且你创建了两个用户,"Tom"和"Jerry",在DoSomething中你不认识任何用户。

您有 2 个选择来完成这项工作。不确定哪一个适用。我的猜测是我将展示的第一个

private readonly ProcessingEndTimeData _procEndTimeData = new ProcessingEndTimeData();

更改为

static private readonly ProcessingEndTimeData _procEndTimeData = new ProcessingEndTimeData();

这说明这个字段也是静态的,即属于类,而不是CIMConversionHelper类的实例。

另一种选择,我认为您不希望它在该方法中创建 CIMConversionHelper 的实例。正如我所说,这可能不是你想要的。

如果你的意图是这个类(CIMConversionHelper)都是静态的,即你永远不会创建它的实例,那么将类本身标记为静态,编译器将确保你不会意外地创建非静态成员。

static class CIMConversionHelper{....}

为什么会这样?

你说你在这里创建了一个参考

private readonly ProcessingEndTimeData _procEndTimeData = new ProcessingEndTimeData();

你还没有创建它。

您需要了解静态函数和实例函数和字段之间的区别。

让我们举个例子。我们有一个类 Thingy。它包括一个工厂方法,可以制作thingy实例记录它制作了多少个实例。

public class Thingy{
static s_thingyCount = 0;
string _froop;
public static CreateThingy(){
var thing = new Thingy();
......
s_thingyCount++;
thing._froop  = "hello";
return thing;
}
public void Twang(int froop){
......
}
public int Oink(string pling){
......
_froop = pling;
}
}

我们可以去

var t1 = Thingy.CreateThingy();
t1.Oink("Ole");

CreateThingy 不对类的实例进行操作,而是对类本身进行操作。count 变量不属于实例,它属于类本身。请注意,在创建方法中,我们必须说

thing._froop  = "hello";

即我们要设置哪些对象_froop(我们正在制作的对象)。

var t1 = Thingy.CreateThingy();          

现在我们有一个 Thingy 的实例,我们可以对其调用方法

t1.Oink("Ole");

查看该方法

public int Oink(string pling){
......
_froop = pling;
}

我们不说要设置哪个froop,我们正在操作类的一个实例。

我们不能做

Thingy.Oink("xxx");

哪个是更新?我们也不能这样做

Thingy._froop = "fff";

出于同样的原因

但我们可以做到

var count = Thingy.s_thingyCount;

这如何映射到您的类。 这是静态的。它就像CreateThingy一样,它没有要操作的实例。

public static TDX2KlarfResult HandleConversion(TDXProcessItem item, string fileName)

但是你这样做

_procEndTimeData.ToolType = toolType;

使用此字段

private readonly ProcessingEndTimeData _procEndTimeData = new ProcessingEndTimeData();

这就像做

_froop = "hello"

in CreateThingy

_proceEndTimeData仅存在于类的实例中。

当你这样做时,它将被创建

new CIMConversionHelper();

但我怀疑这不是你想做的。所以你需要_proceEndTimeData静态的,就像s_thingyCount

如果我理解正确,你回答自己:"我知道在表面上我不能在静态方法中使用非静态字段",然后你在方法中声明了一个非静态变量:

私有只读处理结束时间数据_procEndTimeData

它应该是静态的,如果需要,除了只读。

其原因与面向对象编程有关。若要从类访问静态方法,无需实例化它。这就是为什么不能从该类的静态方法中引用类级非静态变量的原因。希望这让它更清楚一点。

我知道

我可以将_procEndTimeData切换为静态,但是如果我已经在字段级别创建了引用,为什么还需要这样做?

你没有创建这样的东西,你的_procEndTimeData是每个CIMConversionHelper实例中的一个字段,你没有。

如果它可以帮助您更好地可视化问题,请想象一下,如果您的期望是现实并且您有以下代码,会发生什么:

CIMConversionHelper h1 = new(), h2 = new();
CIMConversionHelper.Convert(.....whatever....);

它会改变h1._procEndTimeData吗?h2._procEndTimeData?它必须选择一个,对吧?那么它选择哪一个呢?

不。static方法只能使用static字段、句点。

最新更新