C# static关键字是什么意思?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/827424/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What does the static keyword mean?
提问by Qooe
I am a C# beginner. I found there are 2 way to write codes and output the same results. Could you explain the different between them? And when to use #1 and #2?
我是 C# 初学者。我发现有两种编写代码并输出相同结果的方法。你能解释一下它们之间的不同吗?什么时候使用#1和#2?
#1
#1
class Program
{
static void Main()
{
Program min = new Program();
Console.WriteLine(min.isMin(1, 2));
Console.ReadLine();
}
int isMin(int value1, int value2)
{
int Min;
return Min = Math.Min(value1, value2);
}
}
#2
#2
class Program2
{
static void Main()
{
Console.WriteLine(isMin(1, 2));
Console.ReadLine();
}
static int isMin(int value1, int value2)
{
int Min;
return Min = Math.Min(value1, value2);
}
}
采纳答案by Mike Dinescu
The difference between #1 and #2 is that in #1, isMin is an instance member function of the class Program, therefore you have to create an instance of the Program class
#1和#2的区别在于#1中,isMin是Program类的实例成员函数,因此必须创建Program类的实例
Program min = new Program()
and only then call the instance member function isMin:
然后才调用实例成员函数 isMin:
min.isMin(..)
In #2, isMin is a static member function of the Program class, and since Main is also a static member function of the same class, you can make a direct call to isMin from the Main function.
#2中isMin是Program类的静态成员函数,由于Main也是同一个类的静态成员函数,所以可以直接从Main函数调用isMin。
Both are valid. The static function Main is the "entry point" into the program which means it gets executed first. The rest is just Object-Oriented semantics.
两者都有效。静态函数 Main 是程序的“入口点”,这意味着它首先被执行。其余的只是面向对象的语义。
EDIT
编辑
It seems that in order to better illustrate the point an example would be in order.
似乎为了更好地说明这一点,可以举一个例子。
The two programs below are pretty useless outside of their intended purpose of showing the differences between encapsulating your program logic into objects, and the alternative -using static functions.
下面的两个程序在展示将程序逻辑封装到对象中与替代 - 使用静态函数之间的差异的预期目的之外是非常无用的。
The program defines two operation and will work on two numbers (10 and 25 in the example). As the program runs, it will trace its' operations to a log file (one for each number). It is useful to imagine that the two operations could be replaced by more serious algorithms and that the two numbers could be replaced by a series of more useful input data.
该程序定义了两个操作并将处理两个数字(示例中为 10 和 25)。当程序运行时,它将跟踪它的操作到一个日志文件(每个数字一个)。想象一下,这两个操作可以被更严格的算法所取代,而这两个数字可以被一系列更有用的输入数据所取代。
//The instance-based version:
class Program
{
private System.IO.StreamWriter _logStream;
private int _originalNumber;
private int _currentNumber;
public Program(int number, string logFilePath)
{
_originalNumber = number;
_currentNumber = number;
try
{
_logStream = new System.IO.StreamWriter(logFilePath, true);
_logStream.WriteLine("Starting Program for {0}", _originalNumber);
}
catch
{
_logStream = null;
}
}
public void Add(int operand)
{
if (_logStream != null)
_logStream.WriteLine("For {0}: Adding {1} to {2}", _originalNumber, operand, _currentNumber);
_currentNumber += operand;
}
public void Subtract(int operand)
{
if (_logStream != null)
_logStream.WriteLine("For {0}: Subtracting {1} from {2}", _originalNumber, operand, _currentNumber);
_currentNumber -= operand;
}
public void Finish()
{
Console.WriteLine("Program finished. {0} --> {1}", _originalNumber, _currentNumber);
if (_logStream != null)
{
_logStream.WriteLine("Program finished. {0} --> {1}", _originalNumber, _currentNumber);
_logStream.Close();
_logStream = null;
}
}
static void Main(string[] args)
{
Program p = new Program(10, "log-for-10.txt");
Program q = new Program(25, "log-for-25.txt");
p.Add(3); // p._currentNumber = p._currentNumber + 3;
p.Subtract(7); // p._currentNumber = p._currentNumber - 7;
q.Add(15); // q._currentNumber = q._currentNumber + 15;
q.Subtract(20); // q._currentNumber = q._currentNumber - 20;
q.Subtract(3); // q._currentNumber = q._currentNumber - 3;
p.Finish(); // display original number and final result for p
q.Finish(); // display original number and final result for q
}
}
Following is the static functions based implementation of the same program. Notice how we have to "carry our state" into and out of each operation, and how the Main function needs to "remember" which data goes with which function call.
以下是基于静态函数的同一程序的实现。请注意我们必须如何“携带我们的状态”进出每个操作,以及 Main 函数如何需要“记住”哪个数据伴随哪个函数调用。
class Program
{
private static int Add(int number, int operand, int originalNumber, System.IO.StreamWriter logFile)
{
if (logFile != null)
logFile.WriteLine("For {0}: Adding {1} to {2}", originalNumber, operand, number);
return (number + operand);
}
private static int Subtract(int number, int operand, int originalNumber, System.IO.StreamWriter logFile)
{
if (logFile != null)
logFile.WriteLine("For {0}: Subtracting {1} from {2}", originalNumber, operand, number);
return (number - operand);
}
private static void Finish(int number, int originalNumber, System.IO.StreamWriter logFile)
{
Console.WriteLine("Program finished. {0} --> {1}", originalNumber, number);
if (logFile != null)
{
logFile.WriteLine("Program finished. {0} --> {1}", originalNumber, number);
logFile.Close();
logFile = null;
}
}
static void Main(string[] args)
{
int pNumber = 10;
int pCurrentNumber = 10;
System.IO.StreamWriter pLogFile;
int qNumber = 25;
int qCurrentNumber = 25;
System.IO.StreamWriter qLogFile;
pLogFile = new System.IO.StreamWriter("log-for-10.txt", true);
pLogFile.WriteLine("Starting Program for {0}", pNumber);
qLogFile = new System.IO.StreamWriter("log-for-25.txt", true);
qLogFile.WriteLine("Starting Program for {0}", qNumber);
pCurrentNumber = Program.Add(pCurrentNumber, 3, pNumber, pLogFile);
pCurrentNumber = Program.Subtract(pCurrentNumber, 7, pNumber, pLogFile);
qCurrentNumber = Program.Add(qCurrentNumber, 15, qNumber, qLogFile);
qCurrentNumber = Program.Subtract(qCurrentNumber, 20, qNumber, qLogFile);
qCurrentNumber = Program.Subtract(qCurrentNumber, 3, qNumber, qLogFile);
Program.Finish(pCurrentNumber, pNumber, pLogFile);
Program.Finish(qCurrentNumber, qNumber, qLogFile);
}
}
Another point to note is that although the first instance-based example works, it is more common in practice to encapsulate your logic in a different class which can be used in the Main entry point of your program. This approach is more flexible because it makes it very easy to take your program logic and move it to a different file, or even to a different assembly that could even be used by multiple applications. This is one way to do that.
另一点要注意的是,尽管第一个基于实例的示例有效,但在实践中更常见的是将您的逻辑封装在不同的类中,该类可用于程序的 Main 入口点。这种方法更加灵活,因为它可以非常轻松地将您的程序逻辑移动到不同的文件,甚至移动到甚至可以被多个应用程序使用的不同程序集。这是做到这一点的一种方法。
// Another instance-based approach
class ProgramLogic
{
private System.IO.StreamWriter _logStream;
private int _originalNumber;
private int _currentNumber;
public ProgramLogic(int number, string logFilePath)
{
_originalNumber = number;
_currentNumber = number;
try
{
_logStream = new System.IO.StreamWriter(logFilePath, true);
_logStream.WriteLine("Starting Program for {0}", _originalNumber);
}
catch
{
_logStream = null;
}
}
public void Add(int operand)
{
if (_logStream != null)
_logStream.WriteLine("For {0}: Adding {1} to {2}", _originalNumber, operand, _currentNumber);
_currentNumber += operand;
}
public void Subtract(int operand)
{
if (_logStream != null)
_logStream.WriteLine("For {0}: Subtracting {1} from {2}", _originalNumber, operand, _currentNumber);
_currentNumber -= operand;
}
public void Finish()
{
Console.WriteLine("Program finished. {0} --> {1}", _originalNumber, _currentNumber);
if (_logStream != null)
{
_logStream.WriteLine("Program finished. {0} --> {1}", _originalNumber, _currentNumber);
_logStream.Close();
_logStream = null;
}
}
}
class Program
{
static void Main(string[] args)
{
ProgramLogic p = new ProgramLogic(10, "log-for-10.txt");
ProgramLogic q = new ProgramLogic(25, "log-for-25.txt");
p.Add(3); // p._number = p._number + 3;
p.Subtract(7); // p._number = p._number - 7;
q.Add(15); // q._number = q._number + 15;
q.Subtract(20); // q._number = q._number - 20;
q.Subtract(3); // q._number = q._number - 3;
p.Finish();
q.Finish();
}
}
回答by Colin Dabritz
The key difference here is based on object oriented programming. C# is an object oriented language, and most of the things in it are objects. In this case Program is an object. It is special because it has the static void Main() function, that is the 'entry point' for the program.
这里的主要区别是基于面向对象的编程。C#是一门面向对象的语言,里面的大部分东西都是对象。在这种情况下 Program 是一个对象。它很特别,因为它具有静态 void Main() 函数,即程序的“入口点”。
The difference comes because of the static modifier on the isMin function. Classes define how the objects work. When you actually make one, as you do with new Program() you have 'instantiated', or made an actual working copy of that object.
不同之处在于 isMin 函数上的静态修饰符。类定义对象如何工作。当您真正制作一个时,就像您使用 new Program() 所做的那样,您已经“实例化”了,或者制作了该对象的实际工作副本。
Usually this is done to track a set of variables that are part of that object, but in this case there are no such variables.
通常这样做是为了跟踪属于该对象的一组变量,但在这种情况下没有这样的变量。
In the first case, you are making an instance of the object program, and telling it to execute its "isMin" function on that instance. In the second case, you are not making any instances, and you are telling it to execute the "isMin" function that is associated with the class (not the instance of the object). There is no real difference here except some easier syntax, because there is no data being tracked in an object.
在第一种情况下,您正在创建目标程序的一个实例,并告诉它在该实例上执行其“isMin”函数。在第二种情况下,您没有创建任何实例,而是告诉它执行与类(而不是对象的实例)关联的“isMin”函数。除了一些更简单的语法之外,这里没有真正的区别,因为在对象中没有被跟踪的数据。
You will find that it matter when you have data on the objects, because you will not be able to access 'instance' data when you are in a static function. To understand more, look into object oriented programming.
您会发现当您拥有对象上的数据时很重要,因为当您处于静态函数中时,您将无法访问“实例”数据。要了解更多信息,请查看面向对象编程。
回答by Noldorin
The two methods are differentiated by of an instance method (in the first) and a static method (in the second). The first declares an instance of the Program
class, and then calls the isMin
method on this instance, whereas the second simply calls the isMin
method without referring to any instance (you can think that the method always belongs to the class as a whole and is executed within this general context). If you come from a BASIC background, a static method is essentially like a method defined in a module.
这两种方法的区别在于实例方法(第一种)和静态方法(第二种)。第一个声明了一个Program
类的实例,然后isMin
在这个实例上调用方法,而第二个只是简单地调用isMin
方法,不引用任何实例(你可以认为这个方法作为一个整体总是属于这个类的,并且在这个实例中执行)一般背景)。如果您有 BASIC 背景,那么静态方法本质上就像是在模块中定义的方法。
As far as best practices go, the second method is the one to choose. There's no explicit reason to have an instance of the Program
class (consider that you will never have more than one in the same assembly/process), so why bother? It makes more sense that the isMin
method should be static, i.e. not depending on or even related to any particular instance (or any particular class even - you might as well define it in another class called MathHelper
).
就最佳实践而言,第二种方法是可供选择的方法。没有明确的理由来拥有一个Program
类的实例(考虑到在同一个程序集/过程中你永远不会有多个),那么为什么要麻烦呢?isMin
方法应该是静态的更有意义,即不依赖于或什至不与任何特定实例(甚至任何特定类 - 您也可以在另一个名为 的类中定义它MathHelper
)。
Hope that clarifies things for you.
希望能为你澄清事情。
回答by tvanfosson
The difference between the two is that the first uses instance methods and the second uses static methods. An instance method is a method that is associated with every object of a given class. A static method is associated with the class itself. In the first case you have to create an object of the class, then you can use the method associated with that particular object. In the second case, you can use the method based on just the class. Normally, you would prefix the method with the class name, but because the scope you are in is the class, the class of the static method is assumed to be the current class. That explains what the difference is at a very high level.
两者的区别在于第一个使用实例方法,第二个使用静态方法。实例方法是与给定类的每个对象相关联的方法。静态方法与类本身相关联。在第一种情况下,您必须创建类的对象,然后您可以使用与该特定对象关联的方法。在第二种情况下,您可以使用仅基于类的方法。通常,您会使用类名作为方法的前缀,但由于您所在的范围是类,静态方法的类被假定为当前类。这解释了在非常高的水平上的差异。
The more important thing is how you would actually go about writing a program using these methods. In object-oriented programming you normally think of an object as containing some data and the operations (methods) that operate on that data. In a sense, it is self-contained. The typical way of writing OO programs is to use classes with instance methods. Static methods would typically be rare, at least comparatively rare.
更重要的是您将如何实际使用这些方法编写程序。在面向对象的编程中,您通常认为一个对象包含一些数据和对这些数据进行操作的操作(方法)。从某种意义上说,它是自成一体的。编写 OO 程序的典型方法是使用具有实例方法的类。静态方法通常很少见,至少相对少见。
Why would that be? Well, static methods have to get all their data from their arguments as they aren't associated with any particular object. Remember that objects consist of data AND operations. Sometimes we have methods that this works for. The Math class is a good example. Typically it's methods are static and take one or two arguments and produce a result. There's no need for an object since the only data required are the arguments to the method and it wouldn't make sense to create a class to hold two arguments and then only do one operation on them.
为什么会这样?好吧,静态方法必须从它们的参数中获取所有数据,因为它们不与任何特定对象相关联。请记住,对象由数据 AND 操作组成。有时,我们有适用于此的方法。Math 类就是一个很好的例子。通常它的方法是静态的,并采用一两个参数并产生结果。不需要对象,因为唯一需要的数据是方法的参数,创建一个类来保存两个参数然后只对它们执行一个操作是没有意义的。
Normally, though, our class data is more complex and the various operations on them are not as simple and more numerous. In this case it makes sense to have the methods operate on the object's data rather than pass all that data around via parameters. In this case we need particular instances of a class so that we can have particular data for the operations to operate on.
但是,通常情况下,我们的类数据更复杂,对它们的各种操作也不是那么简单和更多。在这种情况下,让方法对对象的数据进行操作而不是通过参数传递所有数据是有意义的。在这种情况下,我们需要一个类的特定实例,以便我们可以拥有特定数据供操作进行操作。
As Brian Marick says, now would be a good time for an example.
正如 Brian Marick 所说,现在是举个例子的好时机。
Let's say you had a class that represented a car and were running a simulation of many cars driving around a town. Cars have many potential operations: Start, Accelerate, Turn, Brake, etc. A car would also have several properties that might affect the various algorithms for these operations: an Engine, a BrakePackage, SteeringPackage, etc. Not every car would have the same values for Engine, BrakePackage, and SteeringPackage.
假设您有一个代表汽车的类,并且正在模拟许多汽车在城镇周围行驶。汽车有许多潜在的操作:启动、加速、转弯、制动等。汽车还有一些属性可能会影响这些操作的各种算法:引擎、制动包、转向包等。不是每辆车都有相同的Engine、BrakePackage 和 SteeringPackage 的值。
Using instance methods we would let the methods: Start, Accelerate, Turn, Brake operate on the data contained in the object itself.
使用实例方法,我们可以让方法:Start、Accelerate、Turn、Brake 对包含在对象本身中的数据进行操作。
public class Car
{
public Engine Engine { get; set; }
public BrakePackage Brakes { get; set; }
public SteeringPackage Steering { get; set; }
public double X { get; private set; }
public double Y { get; private set; }
public double Z { get; private set; }
public void Accelerate( double pedalPressure )
{
this.Engine.MoveThrottle( pedalPressure, UpdatePosition );
}
public void UpdatePosition( double x, double y, double z, int deltaTime )
{
this.CalculateSpeed( this.X, this.Y, this.Z, x, y, z, deltaTime );
this.X = x;
this.Y = y;
this.Z = z;
}
...
}
On the other hand if we used static methods then we'd have to pass in all the various parameters to the methods, including those values that we want to be updated because the methods wouldn't be associated with any particular data. It's actually painful enough that I don't even want to type out the example that would be equivalent to the above.
另一方面,如果我们使用静态方法,那么我们必须将所有各种参数传递给方法,包括我们想要更新的那些值,因为这些方法不会与任何特定数据相关联。这实际上已经够痛苦了,我什至不想输入与上面等效的示例。
In a sense, it's unfortunate that you need to start out writing a program using a static Main method because it can get you started on the wrong foot. What you want to do is start thinking about your objects -- what data they need and what operations you would perform on them. Every once in a while you'll find that you have an operation that applies to all objects of a class and doesn't need to access any or much of the data in any particular object or only deals with information about the class itself. Those objects will be candidates for static methods. Most of your methods, however, will fit the pattern of your first example, not your second.
从某种意义上说,不幸的是,您需要使用静态 Main 方法开始编写程序,因为它会让您开始走错路。您要做的是开始考虑您的对象——它们需要什么数据以及您将对它们执行哪些操作。每隔一段时间,您就会发现您有一个适用于类的所有对象的操作,并且不需要访问任何特定对象中的任何或大部分数据,或者只处理有关类本身的信息。这些对象将成为静态方法的候选对象。但是,您的大多数方法都将适合您的第一个示例的模式,而不是您的第二个示例。