C#编程:从基础概念到实践操作
1. 理解C#编程的关键术语和缩写
在C#编程中,有许多关键的术语和缩写对于理解程序的运行环境至关重要。以下是一些常见的C#相关缩写及其定义和描述:
| 缩写 | 定义 | 描述 |
| — | — | — |
| .NET | 无 | 微软对整个CLI堆栈的实现,包括CLR、CIL和各种语言,所有这些都符合CLS规范。 |
| BCL | 基类库 | CLI规范的一部分,定义了构建几乎所有程序所需的集合、线程、控制台和其他基类。 |
| C# | 无 | 一种编程语言。需要注意的是,除了CLI标准外,还有一个C#语言规范,也得到了ECMA和ISO标准机构的批准。 |
| CIL (IL) | 通用中间语言 | CLI规范的语言,定义了在CLI实现上可执行代码的指令。有时也称为IL或Microsoft IL (MSIL),以区别于其他中间语言。为了表明它是一个比微软更广泛的标准,首选CIL而不是MSIL甚至IL。 |
| CLI | 通用语言基础结构 | 定义中间语言、基类和行为特征的规范,使实现者能够创建虚拟执行系统和编译器,在这些系统和编译器中,源语言可以在一个通用的执行环境上进行互操作。 |
| CLR | 通用语言运行时 | 微软对CLI规范中定义的运行时的实现。 |
| CLS | 通用语言规范 | CLI规范的一部分,定义了源语言必须支持的核心功能子集,以便在根据CLI规范实现的运行时上执行。 |
| CTS | 通用类型系统 | 通常由符合CLI的语言实现的标准,定义了语言在模块外部可见地暴露的类型的表示和行为。它包括类型如何组合形成新类型的概念。 |
| FCL | .NET框架类库 | 构成微软.NET框架的类库。它包括微软对BCL的实现以及大量用于Web开发、分布式通信、数据库访问、富客户端用户界面开发等的类库。 |
| VES (runtime) | 虚拟执行系统 | 管理为CLI编译的程序执行的代理。 |
这些术语和缩写构成了C#编程的基础,对于深入理解和开发C#程序具有重要意义。
2. 下载和安装C#编译器及CLI平台
要编译和运行C#程序,需要安装编译器和CLI平台的版本。以下是不同平台的安装方法:
2.1 Microsoft .NET
Microsoft .NET是主要的CLI平台,也是在Microsoft Windows上进行开发的首选平台。
-
最低安装要求
:包括编译器和支持C# 2.0语法的.NET框架的最小安装是.NET Framework 2.0或更高版本的可再发行包。可以从http://msdn.microsoft.com/en-us/netframework/default.aspx下载。
-
安装Visual Studio IDE
:如果需要一个包含智能感知和项目文件支持的丰富IDE,可以安装Visual Studio IDE的一个版本。其中Visual C# Express可以从http://lab.msdn.microsoft.com/express免费下载。
2.2 设置编译器路径
对于命令行编译,无论是否安装了Visual Studio,都必须设置PATH环境变量以包含C#编译器CSC.EXE。
-
安装了Visual Studio .NET
:如果计算机上安装了Visual Studio .NET,可以从开始菜单中选择“所有程序” -> “Microsoft Visual Studio .NET” -> “Visual Studio工具” -> “Visual Studio命令提示”来打开命令提示符。这个命令提示符会将CSC.EXE添加到路径中,以便从任何目录执行。
-
未安装Visual Studio .NET
:如果没有安装Visual Studio .NET,开始菜单中不会出现特殊的编译器命令提示符项。此时需要显式引用完整的编译器路径名或将其添加到路径中。编译器位于%Windir%\Microsoft.NET\Framework\
,其中
是.NET框架的版本(如v1.0.3705、v1.1.4322、v2.0.50727等),%Windir%是指向Windows目录位置的环境变量。可以使用以下命令将该位置添加到路径中:
Set PATH=%PATH%;%Windir%\Microsoft.NET\Framework\v2.0.50727
将 替换为实际的版本号。一旦路径中包含了框架,就可以在不提供完整路径的情况下使用.NET C#编译器CSC.EXE。
2.3 Mono
对于非Microsoft Windows平台上的CLI开发,可以考虑使用Mono,它可以从www.mono-project.com下载。与.NET平台一样,如果C#编译器不在搜索路径中,Mono也需要完整的路径。
-
Linux默认安装路径
:在Linux上,默认的安装路径是/usr/lib/mono/
,编译器是gmcs.exe或mcs.exe,具体取决于版本。
-
Windows默认安装路径
:如果Mono安装在Microsoft Windows上,默认路径是%ProgramFiles%\Mono -
\lib\mono\
\。
-
编译示例
:使用Mono平台的编译器编译HelloWorld.cs的命令如下:
C:\SAMPLES>msc.exe HelloWorld.cs
不幸的是,Linux环境不能直接运行生成的二进制文件,而是需要使用mono.exe显式执行运行时:
C:\SAMPLES>mono.exe HelloWorld.exe
Hello. My name is Inigo Montoya.
2.4 安装流程总结
graph LR
A[选择平台] --> B{Microsoft Windows}
B -- 是 --> C[安装Microsoft .NET]
C --> D[设置编译器路径]
B -- 否 --> E[安装Mono]
E --> F[设置编译器路径]
通过以上步骤,你可以成功下载和安装C#编译器及CLI平台,为后续的C#编程做好准备。
3. 完整源代码清单示例
3.1 井字棋游戏(Tic - Tac - Toe)
以下是一个简单的井字棋游戏的源代码:
#define CSHARP2
using System;
#pragma warning disable 1030 // Disable user-defined warnings
// The TicTacToe class enables two players to
// play tic-tac-toe.
class TicTacToeGame // Declares the TicTacToeGame class
{
static void Main() // Declares the entry point to the program
{
// Stores locations each player has moved.
int[] playerPositions = { 0, 0 };
// Initially set the currentPlayer to Player 1;
int currentPlayer = 1;
// Winning player
int winner = 0;
string input = null;
// Display the board and
// prompt the current player
// for his next move.
for (int turn = 1; turn <= 10; ++turn)
{
DisplayBoard(playerPositions);
#region Check for End Game
if (EndGame(winner, turn, input))
{
break;
}
#endregion Check for End Game
input = NextMove(playerPositions, currentPlayer);
winner = DetermineWinner(playerPositions);
// Switch players
currentPlayer = (currentPlayer == 2) ? 1 : 2;
}
}
private static string NextMove(int[] playerPositions,
int currentPlayer)
{
string input;
// Repeatedly prompt the player for a move
// until a valid move is entered.
bool validMove;
do
{
// Request a move from the current player.
System.Console.Write("\nPlayer {0} - Enter move:",
currentPlayer);
input = System.Console.ReadLine();
validMove = ValidateAndMove(playerPositions,
currentPlayer, input);
} while (!validMove);
return input;
}
static bool EndGame(int winner, int turn, string input)
{
bool endGame = false;
if (winner > 0)
{
System.Console.WriteLine("\nPlayer {0} has won!!!!", winner);
endGame = true;
}
else if (turn == 10)
{
// After completing the 10th display of the
// board, exit out rather than prompting the
// user again.
System.Console.WriteLine("\nThe game was a tie!");
endGame = true;
}
else if (input == "" || input == "quit")
{
// Check if user quit by hitting Enter without
// any characters or by typing "quit".
System.Console.WriteLine("The last player quit");
endGame = true;
}
return endGame;
}
static int DetermineWinner(int[] playerPositions)
{
int winner = 0;
// Determine if there is a winner
int[] winningMasks = {
7, 56, 448, 73, 146, 292, 84, 273};
foreach (int mask in winningMasks)
{
if ((mask & playerPositions[0]) == mask)
{
winner = 1;
break;
}
else if ((mask & playerPositions[1]) == mask)
{
winner = 2;
break;
}
}
return winner;
}
static bool ValidateAndMove(
int[] playerPositions, int currentPlayer, string input)
{
bool valid = false;
// Check the current player’s input.
switch (input)
{
case "1":
case "2":
case "3":
case "4":
case "5":
case "6":
case "7":
case "8":
case "9":
#warning "Same move allowed multiple times."
int shifter; // The number of places to shift
// over in order to set a bit.
int position; // The bit which is to be set.
// int.Parse() converts "input" to an integer.
// "int.Parse(input) – 1" because arrays
// are zero-based.
shifter = int.Parse(input) - 1;
// Shift mask of 00000000000000000000000000000001
// over by cellLocations.
position = 1 << shifter;
// Take the current player cells and OR them
// to set the new position as well.
// Since currentPlayer is either 1 or 2 you
// subtract one to use currentPlayer as an
// index in a 0-based array.
playerPositions[currentPlayer - 1] |= position;
valid = true;
break;
case "":
case "quit":
valid = true;
break;
default:
// If none of the other case statements
// is encountered, then the text is invalid.
System.Console.WriteLine(
"\nERROR: Enter a value from 1-9. "
+ "Push ENTER to quit");
break;
}
return valid;
}
static void DisplayBoard(int[] playerPositions)
{
// This represents the borders between each cell
// for one row.
string[] borders = {
"|", "|", "\n---+---+---\n", "|", "|",
"\n---+---+---\n", "|", "|", ""
};
// Display the current board;
int border = 0; // set the first border (border[0] = "|")
#if CSHARP2
System.Console.Clear();
#endif
for (int position = 1;
position <= 256;
position <<= 1, border++)
{
char token = CalculateToken(
playerPositions, position);
// Write out a cell value and the border that
// comes after it.
System.Console.Write(" {0} {1}",
token, borders[border]);
}
}
static char CalculateToken(
int[] playerPositions, int position)
{
// Initialize the players to 'X' and 'O'
char[] players = {'X', 'O'};
char token;
// If player has the position set,
// then set the token to that player.
if ((position & playerPositions[0]) == position)
{
// Player 1 has that position marked
token = players[0];
}
else if ((position & playerPositions[1]) == position)
{
// Player 2 has that position marked
token = players[1];
}
else
{
// The position is empty.
token = ' ';
}
return token;
}
#line 113 "TicTacToe.cs"
// Generated code goes here
#line default
}
这个程序实现了一个简单的井字棋游戏,允许两个玩家轮流下棋,直到有一方获胜或平局。
3.2 产品序列号类(ProductSerialNumber)
以下是一个表示产品序列号的类的源代码:
public sealed class ProductSerialNumber
{
public ProductSerialNumber(
string productSeries, int model, long id)
{
ProductSeries = productSeries;
Model = model;
Id = id;
}
public readonly string ProductSeries;
public readonly int Model;
public readonly long Id;
public override int GetHashCode()
{
int hashCode = ProductSeries.GetHashCode();
hashCode ^= Model; // Xor (eXclusive OR)
hashCode ^= Id.GetHashCode(); // Xor (eXclusive OR)
return hashCode;
}
public override bool Equals(object obj)
{
if (obj == null)
{
return false;
}
if (ReferenceEquals(this, obj))
{
return true;
}
if (this.GetType() != obj.GetType())
{
return false;
}
return Equals((ProductSerialNumber)obj);
}
public bool Equals(ProductSerialNumber obj)
{
// STEP 3: Possibly check for equivalent hash codes
// if (this.GetHashCode() != obj.GetHashCode())
// {
// return false;
// }
// STEP 4: Check base.Equals if base overrides Equals()
// System.Diagnostics.Debug.Assert(
// base.GetType() != typeof(object));
// if ( base.Equals(obj) )
// {
// return false;
// }
// STEP 1: Check for null
return ((obj != null)
// STEP 5: Compare identifying fields for equality.
&& (ProductSeries == obj.ProductSeries) &&
(Model == obj.Model) &&
(Id == obj.Id));
}
public static bool operator ==(
ProductSerialNumber leftHandSide,
ProductSerialNumber rightHandSide)
{
// Check if leftHandSide is null.
// (operator== would be recursive)
if (ReferenceEquals(leftHandSide, null))
{
// Return true if rightHandSide is also null
// but false otherwise.
return ReferenceEquals(rightHandSide, null);
}
return (leftHandSide.Equals(rightHandSide));
}
public static bool operator !=(
ProductSerialNumber leftHandSide,
ProductSerialNumber rightHandSide)
{
return !(leftHandSide == rightHandSide);
}
}
这个类用于表示产品的序列号,并实现了哈希码和相等性比较的方法。
3.3 二叉树和对(Binary Tree and Pair)
以下是实现二叉树和对的相关代码:
public enum PairItem
{
First,
Second
}
interface IPair<T>
{
T First
{
get;
set;
}
T Second
{
get;
set;
}
T this[PairItem index]
{
get;
set;
}
}
using System.Collections;
using System.Collections.Generic;
public struct Pair<T> : IPair<T>, IEnumerable<T>
{
public Pair(T first)
{
_First = first;
_Second = default(T);
}
public Pair(T first, T second)
{
_First = first;
_Second = second;
}
public T First
{
get
{
return _First;
}
set
{
_First = value;
}
}
private T _First;
public T Second
{
get
{
return _Second;
}
set
{
_Second = value;
}
}
private T _Second;
[System.Runtime.CompilerServices.IndexerName("Entry")]
public T this[PairItem index]
{
get
{
switch (index)
{
case PairItem.First:
return First;
case PairItem.Second:
return Second;
default:
throw new NotImplementedException(
string.Format(
"The enum {0} has not been implemented",
index.ToString()));
}
}
set
{
switch (index)
{
case PairItem.First:
First = value;
break;
case PairItem.Second:
Second = value;
break;
default:
throw new NotImplementedException(
string.Format(
"The enum {0} has not been implemented",
index.ToString()));
}
}
}
#region IEnumerable<T> Members
public IEnumerator<T> GetEnumerator()
{
yield return First;
yield return Second;
}
#endregion
#region IEnumerable Members
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
#endregion
public IEnumerable<T> GetReverseEnumerator()
{
yield return Second;
yield return First;
}
// Listing 12.24
public IEnumerable<T> GetNotNullEnumerator()
{
if ((First == null) || (Second == null))
{
yield break;
}
yield return Second;
yield return First;
}
}
using System.Collections;
using System.Collections.Generic;
public interface IBinaryTree<T>
{
T Item
{
get;
set;
}
Pair<IBinaryTree<T>> SubItems
{
get;
set;
}
}
public class BinaryTree<T> : IEnumerable<T>
{
public BinaryTree(T value)
{
Value = value;
}
public T Value
{
get { return _Value; }
set { _Value = value; }
}
private T _Value;
public Pair<BinaryTree<T>> SubItems
{
get { return _SubItems; }
set
{
IComparable first;
first = (IComparable)value.First.Value;
if (first.CompareTo(value.Second.Value) < 0)
{
// first is less than second.
}
else
{
// first and second are the same or
// second is less than first.
}
_SubItems = value;
}
}
private Pair<BinaryTree<T>> _SubItems;
public T this[params PairItem[] branches]
{
get
{
BinaryTree<T> currentNode = this;
int totalLevels =
(branches == null) ? 0 : branches.Length;
int currentLevel = 0;
while (currentLevel < totalLevels)
{
currentNode =
currentNode.SubItems[branches[currentLevel]];
if (currentNode == null)
{
// The binary tree at this location is null.
throw new IndexOutOfRangeException();
}
currentLevel++;
}
return currentNode.Value;
}
}
#region IEnumerable<T>
// Listing 12.22
public IEnumerator<T> GetEnumerator()
{
// Return the item at this node.
yield return Value;
// Iterate through each of the elements in the pair.
foreach (BinaryTree<T> tree in SubItems)
{
if (tree != null)
{
// Since each element in the pair is a tree,
// traverse the tree and yield each
// element.
foreach (T item in tree)
{
yield return item;
}
}
}
}
#endregion IEnumerable<T>
#region IEnumerable Members
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
#endregion
}
这些代码定义了一个对(Pair)和一个二叉树(BinaryTree)的接口和实现,提供了遍历和操作的方法。
3.4 命令行属性处理(Command - Line Attributes)
以下是处理命令行属性的相关代码:
using System;
using System.Diagnostics;
public partial class Program
{
public static void Main(string[] args)
{
string errorMessage;
CommandLineInfo commandLine = new CommandLineInfo();
if (!CommandLineHandler.TryParse(
args, commandLine, out errorMessage))
{
Console.WriteLine(errorMessage);
DisplayHelp();
}
if (commandLine.Help)
{
DisplayHelp();
}
else
{
if (commandLine.Priority !=
ProcessPriorityClass.Normal)
{
// Change thread priority
}
}
// ...
}
private static void DisplayHelp()
{
// Display the command-line help.
Console.WriteLine(
"Thankyou for contacting the help text");
}
}
using System;
using System.Diagnostics;
public partial class Program
{
private class CommandLineInfo
{
[CommandLineSwitchAlias("?")]
public bool Help
{
get { return _Help; }
set { _Help = value; }
}
private bool _Help;
[CommandLineSwitchRequired]
[CommandLineSwitchAlias("FileName")]
public string Out
{
get { return _Out; }
set { _Out = value; }
}
private string _Out;
public ProcessPriorityClass Priority
{
get { return _Priority; }
set { _Priority = value; }
}
private ProcessPriorityClass _Priority =
ProcessPriorityClass.Normal;
}
}
using System;
using System.Diagnostics;
using System.Reflection;
public class CommandLineHandler
{
public static void Parse(string[] args, object commandLine)
{
string errorMessage;
if (!TryParse(args, commandLine, out errorMessage))
{
throw new ApplicationException(errorMessage);
}
}
public static bool TryParse(string[] args, object commandLine,
out string errorMessage)
{
bool success = false;
errorMessage = null;
foreach (string arg in args)
{
string option;
if (arg[0] == '/' || arg[0] == '-')
{
string[] optionParts = arg.Split(
new char[] { ':' }, 2);
// Remove the slash|dash
option = optionParts[0].Remove(0, 1);
PropertyInfo property =
commandLine.GetType().GetProperty(option,
BindingFlags.IgnoreCase |
BindingFlags.Instance |
BindingFlags.Public);
if (property != null)
{
if (property.PropertyType == typeof(bool))
{
// Last parameters for handling indexers
property.SetValue(
commandLine, true, null);
success = true;
}
else if (
property.PropertyType == typeof(string))
{
property.SetValue(
commandLine, optionParts[1], null);
success = true;
}
else if (property.PropertyType.IsEnum)
{
try
{
property.SetValue(commandLine,
Enum.Parse(
typeof(ProcessPriorityClass),
optionParts[1], true),
null);
success = true;
}
catch (ArgumentException )
{
success = false;
errorMessage =
string.Format(
"The option '{0}' is " +
"invalid for '{1}'",
optionParts[1], option);
}
}
else
{
success = false;
errorMessage = string.Format(
"Data type '{0}' on {1} is not"
+ " supported.",
property.PropertyType.ToString(),
commandLine.GetType().ToString());
}
}
else
{
success = false;
errorMessage = string.Format(
"Option '{0}' is not supported.",
option);
}
}
}
return success;
}
}
using System;
using System.Collections.Specialized;
using System.Reflection;
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class CommandLineSwitchRequiredAttribute : Attribute
{
public static string[] GetMissingRequiredOptions(
object commandLine)
{
StringCollection missingOptions = new StringCollection();
PropertyInfo[] properties =
commandLine.GetType().GetProperties();
foreach (PropertyInfo property in properties)
{
Attribute[] attributes =
(Attribute[])property.GetCustomAttributes(
typeof(CommandLineSwitchRequiredAttribute),
false);
if ((attributes.Length > 0) &&
(property.GetValue(commandLine, null) == null))
{
if (property.GetValue(commandLine, null) == null)
{
missingOptions.Add(property.Name);
}
}
}
string[] results = new string[missingOptions.Count];
missingOptions.CopyTo(results, 0);
return results;
}
}
using System;
using System.Reflection;
using System.Collections.Generic;
[AttributeUsage(AttributeTargets.Property)]
public class CommandLineSwitchAliasAttribute : Attribute
{
public CommandLineSwitchAliasAttribute(string alias)
{
Alias = alias;
}
public string Alias
{
get { return _Alias; }
set { _Alias = value; }
}
private string _Alias;
public static Dictionary<string, PropertyInfo> GetSwitches(
object commandLine)
{
PropertyInfo[] properties = null;
Dictionary<string, PropertyInfo> options =
new Dictionary<string, PropertyInfo>();
properties = commandLine.GetType().GetProperties(
BindingFlags.Public | BindingFlags.NonPublic |
BindingFlags.Instance);
foreach (PropertyInfo property in properties)
{
options.Add(property.Name.ToLower(), property);
foreach (CommandLineSwitchAliasAttribute attribute in
property.GetCustomAttributes(
typeof(CommandLineSwitchAliasAttribute), false))
{
options.Add(attribute.Alias.ToLower(), property);
}
}
return options;
}
}
using System;
using System.Reflection;
using System.Collections.Generic;
public class CommandLineHandler
{
// ...
public static bool TryParse(
string[] args, object commandLine,
out string errorMessage)
{
bool success = false;
errorMessage = null;
Dictionary<string, PropertyInfo> options =
CommandLineSwitchAliasAttribute.GetSwitches(
commandLine);
foreach (string arg in args)
{
PropertyInfo property;
string option;
if (arg[0] == '/' || arg[0] == '-')
{
string[] optionParts = arg.Split(
new char[] { ':' }, 2);
option = optionParts[0].Remove(0, 1).ToLower();
if (options.TryGetValue(option, out property))
{
success = SetOption(
commandLine, property,
optionParts, ref errorMessage);
}
else
{
success = false;
errorMessage = string.Format(
"Option '{0}' is not supported.",
option);
}
}
}
return success;
}
private static bool SetOption(
object commandLine, PropertyInfo property,
string[] optionParts, ref string errorMessage)
{
bool success;
if (property.PropertyType == typeof(bool))
{
// Last parameters for handling indexers
property.SetValue(
commandLine, true, null);
success = true;
}
else
{
if ((optionParts.Length < 2)
|| optionParts[1] == ""
|| optionParts[1] == ":")
{
// No setting was provided for the switch.
success = false;
errorMessage = string.Format(
"You must specify the value for the {0} option.",
property.Name);
}
else if (
property.PropertyType == typeof(string))
{
property.SetValue(
commandLine, optionParts[1], null);
success = true;
}
else if (property.PropertyType.IsEnum)
{
success = TryParseEnumSwitch(
commandLine, optionParts,
property, ref errorMessage);
}
else
{
success = false;
errorMessage = string.Format(
"Data type '{0}' on {1} is not supported.",
property.PropertyType.ToString(),
commandLine.GetType().ToString());
}
}
return success;
}
}
这段代码实现了对命令行参数的解析和处理,包括检查必填选项、处理别名等功能。
3.5 使用P/Invoke进行虚拟计算机检测(Virtual Computer Detection Using P/Invoke)
以下是使用P/Invoke进行虚拟计算机检测的代码:
using System.Runtime.InteropServices;
class Program
{
delegate void MethodInvoker();
unsafe static int Main(string[] args)
{
// Assign redpill
byte[] redpill = {
0x0f, 0x01, 0x0d, // asm SIDT instruction
0x00, 0x00, 0x00, 0x00, // placeholder for an address
0xc3}; // asm return instruction
unsafe
{
fixed (byte* matrix = new byte[6],
redpillPtr = redpill)
{
// Move the address of matrix immediately
// following the SIDT instruction of memory.
*(uint*)&redpillPtr[3] = (uint)&matrix[0];
using (VirtualMemoryPtr codeBytesPtr =
new VirtualMemoryPtr(redpill.Length))
{
Marshal.Copy(
redpill, 0,
codeBytesPtr, redpill.Length);
MethodInvoker method =
(MethodInvoker)Marshal.GetDelegateForFunctionPointer(
codeBytesPtr, typeof(MethodInvoker));
method();
}
if (matrix[5] > 0xd0)
{
Console.WriteLine("Inside Matrix! \n");
return 1;
}
else
{
Console.WriteLine("Not in Matrix. \n");
return 0;
}
} // fixed
}
}
}
public class VirtualMemoryPtr :
System.Runtime.InteropServices.SafeHandle
{
public VirtualMemoryPtr(int memorySize) :
base(IntPtr.Zero, true)
{
ProcessHandle =
VirtualMemoryManager.GetCurrentProcessHandle();
MemorySize = (IntPtr)memorySize;
AllocatedPointer =
VirtualMemoryManager.AllocExecutionBlock(
memorySize, ProcessHandle);
Disposed = false;
}
public readonly IntPtr AllocatedPointer;
readonly IntPtr ProcessHandle;
readonly IntPtr MemorySize;
bool Disposed;
public static implicit operator IntPtr(
VirtualMemoryPtr virtualMemoryPointer)
{
return virtualMemoryPointer.AllocatedPointer;
}
// SafeHandle abstract member
public override bool IsInvalid
{
get
{
return Disposed;
}
}
// SafeHandle abstract member
protected override bool ReleaseHandle()
{
if (!Disposed)
{
Disposed = true;
GC.SuppressFinalize(this);
VirtualMemoryManager.VirtualFreeEx(ProcessHandle,
AllocatedPointer, MemorySize);
}
return true;
}
}
class VirtualMemoryManager
{
/// <summary>
/// The type of memory allocation. This parameter must
/// contain one of the following values.
/// </summary>
[Flags]
private enum AllocationType : uint
{
/// <summary>
/// Allocates physical storage in memory or in the
/// paging file on disk for the specified reserved
/// memory pages. The function initializes the memory
/// to zero.
/// </summary>
Commit = 0x1000,
/// <summary>
/// Reserves a range of the process's virtual address
/// space without allocating any actual physical
/// storage in memory or in the paging file on disk.
/// </summary>
Reserve = 0x2000,
/// <summary>
/// Indicates that data in the memory range specified by
/// lpAddress and dwSize is no longer of interest. The
/// pages should not be read from or written to the
/// paging file. However, the memory block will be used
/// again later, so it should not be decommitted. This
/// value cannot be used with any other value.
/// </summary>
Reset = 0x80000,
/// <summary>
/// Allocates physical memory with read-write access.
/// This value is solely for use with Address Windowing
/// Extensions (AWE) memory.
/// </summary>
Physical = 0x400000,
/// <summary>
/// Allocates memory at the highest possible address.
/// </summary>
TopDown = 0x100000,
}
/// <summary>
/// The memory protection for the region of pages to be
/// allocated.
/// </summary>
[Flags]
private enum ProtectionOptions : uint
{
/// <summary>
/// Enables execute access to the committed region of
/// pages. An attempt to read or write to the committed
/// region results in an access violation.
/// </summary>
Execute = 0x10,
/// <summary>
/// Enables execute and read access to the committed
/// region of pages. An attempt to write to the
/// committed region results in an access violation.
/// </summary>
PageExecuteRead = 0x20,
/// <summary>
/// Enables execute, read, and write access to the
/// committed region of pages.
/// </summary>
PageExecuteReadWrite = 0x40,
// ...
}
/// <summary>
/// The type of free operation
/// </summary>
[Flags]
private enum MemoryFreeType : uint
{
/// <summary>
/// Decommits the specified region of committed pages.
/// After the operation, the pages are in the reserved
/// state.
/// </summary>
Decommit = 0x4000,
/// <summary>
/// Releases the specified region of pages. After this
/// operation, the pages are in the free state.
/// </summary>
Release = 0x8000
}
[DllImport("kernel32.dll", EntryPoint="GetCurrentProcess")]
[DllImport("kernel32.dll")]
internal static extern IntPtr GetCurrentProcess();
[DllImport("kernel32.dll", SetLastError = true)]
private static extern IntPtr VirtualAllocEx(
IntPtr hProcess,
IntPtr lpAddress,
IntPtr dwSize,
AllocationType flAllocationType,
uint flProtect);
// ...
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern IntPtr GetCurrentProcessHandle();
static extern bool VirtualProtectEx(
IntPtr hProcess, IntPtr lpAddress,
IntPtr dwSize, uint flNewProtect,
ref uint lpflOldProtect);
public static IntPtr AllocExecutionBlock(
int size, IntPtr hProcess)
{
IntPtr codeBytesPtr;
codeBytesPtr = VirtualAllocEx(
hProcess, IntPtr.Zero,
(IntPtr)size,
AllocationType.Reserve | AllocationType.Commit,
(uint)ProtectionOptions.PageExecuteReadWrite);
if (codeBytesPtr == IntPtr.Zero)
{
throw new System.ComponentModel.Win32Exception();
}
uint lpflOldProtect = 0;
if (!VirtualProtectEx(
hProcess, codeBytesPtr,
(IntPtr)size,
(uint)ProtectionOptions.PageExecuteReadWrite,
ref lpflOldProtect))
{
throw new System.ComponentModel.Win32Exception();
}
return codeBytesPtr;
}
public static IntPtr AllocExecutionBlock(int size)
{
return AllocExecutionBlock(
size, GetCurrentProcessHandle());
}
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool VirtualFreeEx(
IntPtr hProcess, IntPtr lpAddress,
IntPtr dwSize, IntPtr dwFreeType);
public static bool VirtualFreeEx(
IntPtr hProcess, IntPtr lpAddress,
IntPtr dwSize)
{
bool result = VirtualFreeEx(
hProcess, lpAddress, dwSize,
(IntPtr)MemoryFreeType.Decommit);
if (!result)
{
throw new System.ComponentModel.Win32Exception();
}
return result;
}
public static bool VirtualFreeEx(
IntPtr lpAddress, IntPtr dwSize)
{
return VirtualFreeEx(
GetCurrentProcessHandle(), lpAddress, dwSize);
}
}
这段代码通过P/Invoke调用Windows API,实现了对虚拟计算机环境的检测。
通过以上代码示例,你可以进一步了解C#编程在不同场景下的应用,加深对C#语言的理解和掌握。
4. 代码示例分析
4.1 井字棋游戏分析
井字棋游戏代码实现了一个简单的双人游戏。以下是对该代码的详细分析:
-
核心数据结构
:使用
int[] playerPositions
数组来记录每个玩家的落子位置,通过位运算来判断玩家是否占据了特定位置。
-
游戏流程控制
:通过
Main
方法中的
for
循环控制游戏的回合数,在每一回合中调用
DisplayBoard
显示棋盘,
NextMove
获取玩家输入,
DetermineWinner
判断是否有玩家获胜,最后根据情况切换玩家。
-
输入验证
:
ValidateAndMove
方法对玩家的输入进行验证,确保输入是有效的落子位置或退出指令。
4.2 产品序列号类分析
产品序列号类
ProductSerialNumber
用于表示产品的唯一标识。
-
属性
:包含
ProductSeries
、
Model
和
Id
三个只读属性,用于存储产品的系列、型号和编号。
-
哈希码和相等性比较
:重写了
GetHashCode
和
Equals
方法,通过异或运算生成哈希码,并比较对象的属性来判断是否相等。同时,还实现了
==
和
!=
运算符的重载,方便进行对象的比较。
4.3 二叉树和对分析
这段代码定义了对(
Pair
)和二叉树(
BinaryTree
)的接口和实现。
-
对(Pair)
:实现了
IPair<T>
接口,提供了
First
和
Second
属性,以及索引器
this[PairItem index]
。同时,还实现了
IEnumerable<T>
接口,支持对元素的遍历。
-
二叉树(BinaryTree)
:实现了
IBinaryTree<T>
接口,包含
Value
属性和
SubItems
属性,用于存储节点的值和子节点。通过索引器
this[params PairItem[] branches]
可以访问二叉树中的特定节点。
4.4 命令行属性处理分析
命令行属性处理代码实现了对命令行参数的解析和处理。
-
命令行信息类
:
CommandLineInfo
类定义了命令行参数的属性,使用
CommandLineSwitchAlias
和
CommandLineSwitchRequired
属性来指定别名和必填项。
-
命令行处理类
:
CommandLineHandler
类提供了
Parse
和
TryParse
方法,用于解析命令行参数。通过反射机制,根据参数名查找对应的属性,并设置属性值。
-
属性处理
:
CommandLineSwitchRequiredAttribute
和
CommandLineSwitchAliasAttribute
类分别用于处理必填选项和别名,通过反射获取属性的自定义属性,实现对命令行参数的灵活处理。
4.5 使用P/Invoke进行虚拟计算机检测分析
这段代码通过P/Invoke调用Windows API,实现了对虚拟计算机环境的检测。
-
红药丸代码
:定义了一个包含汇编指令的字节数组
redpill
,通过修改指令中的地址,将其加载到内存中执行。
-
内存管理
:
VirtualMemoryPtr
类继承自
SafeHandle
,用于管理内存的分配和释放。通过
VirtualMemoryManager
类的静态方法,调用Windows API进行内存的分配、保护和释放。
-
检测逻辑
:执行红药丸代码后,根据内存中的特定位置的值判断是否处于虚拟计算机环境中。
graph LR
A[代码示例] --> B{游戏类}
A --> C{数据类}
A --> D{数据结构类}
A --> E{命令行处理类}
A --> F{系统交互类}
B --> G[井字棋游戏]
C --> H[产品序列号类]
D --> I[二叉树和对]
E --> J[命令行属性处理]
F --> K[虚拟计算机检测]
5. 总结与建议
5.1 总结
本文介绍了C#编程中的关键术语和缩写,详细阐述了C#编译器及CLI平台的下载和安装方法,包括Microsoft .NET和Mono平台。同时,提供了多个完整的源代码清单示例,涵盖了游戏开发、数据表示、数据结构和命令行处理等多个方面。通过对这些代码示例的分析,深入了解了C#编程在不同场景下的应用和实现方法。
5.2 建议
- 深入学习基础知识 :C#编程中的关键术语和缩写是理解和开发C#程序的基础,建议深入学习这些知识,掌握其含义和用途。
- 多实践代码示例 :通过实践代码示例,可以加深对C#语言的理解和掌握。建议按照本文提供的代码示例进行实践,并尝试对代码进行修改和扩展,以提高编程能力。
- 关注性能和安全 :在开发C#程序时,要关注性能和安全问题。例如,在使用P/Invoke调用Windows API时,要注意内存管理和异常处理,避免出现安全漏洞。
- 持续学习和更新 :C#语言和相关技术不断发展和更新,建议持续学习和关注最新的技术动态,不断提升自己的编程水平。
通过以上总结和建议,希望能够帮助你更好地学习和掌握C#编程,在实际开发中取得更好的效果。
超级会员免费看

被折叠的 条评论
为什么被折叠?



