分类 C# 下的文章

20个C#热点问题解答(二)

.NET中加密和解密

如何获取foreach当前循环迭代的索引

  • 第一种方式

    int counter = 0
    //diction 是个字典集合
    foreach(object obj in diction)
    {

       Console.WriteLine(counter);
       counter++;

    }

  • 第二种方式

int curIndex = 0
//创建一个string类型的list集合
foreach(string str in stringList)
{
    curIndex = stringList.IndexOf(str);
    Console.WriteLine(curIndex.Tostring());
}
  • 第三种方式

int curIndex = 0
//创建一个string类型的Arraylist集合
foreach(string str in arrList)
{
    curIndex = stringList.IndexOf(str);
    Console.WriteLine(curIndex.Tostring());
}

如何在C#中获取自己的IP地址

using System.Net.NetWorkInformation;
using System.Net.Sockets;

foreach(var interfaces in NetWorkInterface.GetAllNetworkInterfaces())
{
    foreach(var address in interfaces.GetIPPrpperties().UnicastAddresses)
    {
        if(address.Address.AddressFamily == AddressFamily.InterNetwork)
        {
            Console.WriteLine("IP Address: "+ address.Address.Tostring());
        }
    }
}

//另一个方式

string publicip = GetPublicIP();
Console.WriteLine("public ip: " + publicip);

static string GetPublicIP()
{
    string address = "";
    WebRequest request = WebRequest.Create("Http://checkip.dydns.org/");
    using(WebResponse response = request.GetResponse())
    using(StringReader stream = new StreamReader(response.GetResponseStream()))
    {
        address = string.ReadToEnd;
    }
    //Search for the ip in the html
    int first = address.IndexOf("Address: ") + 9;
    int lase = address.LastIndex("</Body>");
    address = address.Substring(first,last - first);

    return address;
}

如何在C#中获取人的年龄

这里主要使用了DataTime

CalcAge(DateTime.Parse("10/13/1992"));

static void CalAge(DateTime birthday)
{
    DateTime curDate = DateTime.Today;
    if(birthday > curDate)
    {
        Console.WriteLine("Birthady must be equal to or before today")
    }
    else
    {
        int age = curDate.Year - birthday.Year;
        if(birthday.Month > curDate.Month)
        {
            age --;
        }
        Console.WriteLine("The person's age is :{0}",age);
    }
}

如何获取一个枚举的字符串值

public enum AuthMethod
{
    FORMS = 1;
    WINDOWAUTHENICATION = 2;    
    SINGLESIGNON = 3;
}
static void StringEnums()
{
    AuthMethod auth = AuthMethod.FORMS;
    string str = Enum.GetName(typeof(AuthMethod),auth);
    Console.WriteLine(str);
    
    str = AuthMethod.FORMS.ToString();
    Console.WriteLine(str);
}

未完...

没有写完

20个C#热点问题解答(一)

结构和类分别应在什么时候使用

  • struct是值类型,他可以包含数据和函数

  • struct是值类型,不需要的分配

  • struct直接将数据存储在结构中,而类存储的是对一个动态分配的对象的引用

  • struct适用于较小的数据结构

  • struct可能会影响性能(因为来回操作的话都是操作的单独的副本,而类操作的是原始对象,存储的是引用

  • 构造函数可以通过new操作符调用,但这不会在堆上分配内存

  • struct构造函数只返回struct值本身(通常是堆栈中的临时位置),而且在必要时这个值被复制。

以上是官方的解答。我认为最终要的是要认识到,struct是值类型,类是引用类型,然后清楚值类型和引用类型的区别才可以。比如存储的位置的区别了,存储的内容(一个是副本,一个是引用),多次操作对性能的影响了等等,了解了这些就清楚了何时使用值类型,何时使用引用类型.

如何解析XML文件

static void parseXML(string xmlString)
{
    StringBuilder sb = new StringBuilder();
    using(XmlReader reader = XmlReader.Create(new StringReader(xmlString)))
    {
        reader.ReadToFollowing("book");
        reader.MoveToFirstAttribute();
        string genre = reader.Value;
        sb.AppendLine("The genre value:" + genre);
        
        reader.ReadToFollowing("title");
        sb.AppendLine("Content of fitle element" + reader.ReadelementContentAsString());
    }

    Console.WriteLine(sb);
}

以上就是基本代码,比较简单。关于XmlReader类详见MSDN文档
现在好像用Linq也可以解析XML文件,还更加方便。

String和string的区别

•string 类型是一个封装的类(class)类型,它直接从对象继承。string 类的实例表示Unicode 字符串。
•string 类型的值可以被写为字符串。.
•string 关键字只是预定义的类System.String的别名,因此可以使用string name = “Fred”; 或String name = “Fred”;
•类似地,我们可以使用string.Concat() 或String.Concat()
•string 用于变量名称
•String 用于类方法和引用
以上是MVA中给出的解释,这里我更喜欢CLR via C#中提到的,string属于C#基元类型,而String属于FCL Framework类库类型,两者从本质上讲没有区别,string可以看成是String的别名,它们的区别可以看成是int和System.Int32的区别

如何在C#程序中输出程序所在路径

这里面使用到了反射,其实从代码来说是非常简单的。

string path = System.Reflection.Assembly.GetExecutingAssembly().Location;
Console.WriteLine(System.IO.Path.GetDirectioryName(path));

关于反射明天回从CLR via C#中讲一些

在 C# 中调用基类构造函数

在C#中调用父类基本的构造函数是很简单的

public BaseClass()
{
    public string _name = "" ;
    public BaseClass(string name)
    {
        _name = name;
    }

    public 
}


//子类
public InheritTest : BaseClass
{    
    //应该很好理解,这样就调用了父类的构造函数
    public InheritTest(string name):base(name)
    {

    }
}

但如果想在调用父类的构造函数之前,更改这个值该怎么办

//Microsoft给出的方法是:在子类中重写虚方法,并按如下方式调用

public InheritTest : BaseClass
{    
    
    public InheritTest(string name):base(ModifyBase(name))
    {

    }
    private static string ModifyBase(string newName)
    {
        return newName.Toupper();
    }
}

虚拟方法是在基类中创建的方法,并且可以在子类中重写,这也是面向对象编程中多态性概念的由来。

如何在一个字符串中统计另一个字符串的字数

这里演示了两种方法,一种使用正则表达式Regex,另一种使用了Foreach循环

foreach(Match m in Regex.Matches(test,"you"))
{
    wordCount++;
}

foreach(char value in test)
{
    if(value == 'y')
    {
        charCount ++ ;
    }
}

使用foreach统计字符的话还是比较简单的,统计字符串的话还是使用*Regex*更加简单,并且高效。


如何检测一个数是否是2的幂

static bool CheckPowerOfTwo(ulong number)
{
    return (number != 0) && ((number & (number - 1 )) == 0);
}

number - 1number&运算,如果number是2的幂,那么这个值总是为0,这就是关键点

breakcontinue的区别,中继循环和继续执行循环的区别

static void breakVSContinue()
{
    for(int i = 0;i < 10 ;i++)
    {
        if(i ==0) break;
        DoSomeThingWith(i);
    }
}

abstractvirtual函数的区别

  • 抽象函数没有任何实现,并且必须被重写

  • 虚函数可能有一个实现,这不是必须的。并且接下来能够被重写

  • 对于抽象函数你不能调用base.method(),但对于虚函数你可以这么做

refhe out区别

一个简单的回答说两者在visual stuido 中工作基本没有区别。,区别就是:你需要初始化ref,而无须初始化out

《CLR via C#》---定制特性

定制特性可宣告式的为自己的代码构造添加注解来实现特殊功能,允许为几乎每一个元数据表记录项定义和应用信息。这种可扩展的元数据信息能在运行时查询。


使用定制特性

关于自定义特性,首先要知道它们只是将一些附加信息与某个目标元素关联起来的方式,编译器在托管模块的源数据中生成和嵌套这些额外的信息。编译器只是机械的检查源代码中的特性,并生成对应的元数据。
.NET Framework类库定义了几百个定制特性,下面是一些:

  • DllImport特性应用于方法,告诉CLR该方法的实现位于指定DLL的非托管代码中

  • Serializable特性应用于类型,告诉序列化格式化器一个实例的字段可以序列化被反序列化

  • AssemblyVersion特性应用于程序集,设置程序集的版本号

  • Flag特性应用于枚举类型,枚举类型就成了位标识(bit flag)类型

下面代码使你对特性有个认识:

#region Applying Attributes
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
internal sealed class OSVERSIONINFO {
   public OSVERSIONINFO() {
      OSVersionInfoSize = (UInt32)Marshal.SizeOf(this);
 }

public UInt32 OSVersionInfoSize = 0;
public UInt32 MajorVersion = 0;
public UInt32 MinorVersion = 0;
public UInt32 BuildNumber = 0;
public UInt32 PlatformId = 0;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public String CSDVersion = null;
}

internal static class MyClass {
[DllImport("Kernel32", CharSet = CharSet.Auto, SetLastError = true)]
public static extern Boolean GetVersionEx([In, Out] OSVERSIONINFO ver);
}
#endregion

应用特性时,C#允许用一个前缀明确指定特性要应用于的目标元素。

[assembly: MyAttr(1)]         // Applied to assembly,应用于程序集
[module: MyAttr(2)]           // Applied to module,模块

[type: MyAttr(3)]             // Applied to type,类型
internal sealed class SomeType
<[typevar: MyAttr(4)] T> { // Applied to generic type variable,泛型类型

[field: MyAttr(5)]         // Applied to field,字段
public Int32 SomeField = 0;

[return: MyAttr(6)]        // Applied to return value,返回值
[method: MyAttr(7)]        // Applied to method,方法
public Int32 SomeMethod(
  [param: MyAttr(8)]      // Applied to parameter。参数
  Int32 SomeParam) { return SomeParam; }

[property: MyAttr(9)]      // Applied to property,属性
public String SomeProp {
   [method: MyAttr(10)]    // Applied to get accessor method。方法
   get { return null; }
}

[event: MyAttr(11)]        // Applied to event
[field: MyAttr(12)]        // Applied to compiler-generated field
[method: MyAttr(13)]       // Applied to compiler-generated add & remove methods
public event EventHandler SomeEvent;
}

C#运输省略Attribute后缀以减少打字两,并提升代码的可读性,如果DllImportAttribute简写为DllImport(...)

DllImport特性应用于GetVersionEx方法

[DllImport("Kernel132",CharSet = Charset.Auto,SetLastError = true)]

定义自己的特性类

假定你是Microsoft的员工,负责为枚举来行添加位标志支持,第一步定义一个FlagsAttribute类。

pubic class FlagAttribute: system.Attribute{
    public FlagsAttribute(){
        ...
    }
}

继承自System.Attribute,使用Attribute后缀。
然后再告诉FlagsAttribute类应用到枚举类型

[AttributeUasge(AttributeTargets.Enum Inherited = fasle)]
public class FlagsAttribute : sytem.Attribute(){
     ....
}

下面是FCL中该类的源代码

// 摘要: 
//     指定另一特性类的用法。 此类不能被继承。
[Serializable]
[AttributeUsage(AttributeTargets.Class, Inherited = true)]
[ComVisible(true)]
public sealed class AttributeUsageAttribute : Attribute
{
    // 摘要: 
    //     用指定的 System.AttributeTargets、System.AttributeUsageAttribute.AllowMultiple
    //     值和 System.AttributeUsageAttribute.Inherited 值列表初始化 System.AttributeUsageAttribute
    //     类的新实例。
    //
    // 参数: 
    //   validOn:
    //     使用按位"或"运算符组合的一组值,用于指示哪些程序元素是有效的。
    public AttributeUsageAttribute(AttributeTargets validOn);

    // 摘要: 
    //     获取或设置一个布尔值,该值指示能否为一个程序元素指定多个指示属性实例。
    //
    // 返回结果: 
    //     如果允许指定多个实例,则为 true;否则为 false。 默认值为 false。
    public bool AllowMultiple { get; set; }
    //
    // 摘要: 
    //     获取或设置一个布尔值,该值指示指示的属性能否由派生类和重写成员继承。
    //
    // 返回结果: 
    //     如果该属性可由派生类和重写成员继承,则为 true,否则为 false。 默认值为 true。
    public bool Inherited { get; set; }
    //
    // 摘要: 
    //     获取一组值,这组值标识指示的属性可应用到的程序元素。
    //
    // 返回结果: 
    //     一个或多个 System.AttributeTargets 值。 默认值为 All。
    public AttributeTargets ValidOn { get; }
}

总结

在以前的学习过程中,定制特性基本没有使用到,只有一次用到了。在调用非托管代码时,使用到了DllImport,这样可以调用C++写的DLL。其他内容暂时看不懂,滤过。

《CLR via C#》---数组

所有数组都隐式从System.Array抽象类派生,后者又从System.Object。这意味着数组始终是引用类型,是在托管堆上分配的。在应用程序的变量或字段中,包含的是对数组的引用,而不是数组本身的元素。

Int32[] myIntegers;
myIntegers = new Int32[100];

myIntegers指向包含Int32值的一维数组。刚开始时都为null。第二行分配了含有100个Int32值的数组,所有Int32都被初始化为0.由于数组是引用类型,就会在托管堆上分配100个未装箱Int32所需的内存块(其中里面还包含一个类型对象指针,一个同步索引和一些额外的成员)。该数组的内存地址被返回保存到myInteges变量中。

引用类型数组类似,不过是初始化为null


初始化数组元素

String[] names = new String[]{"Aidan" , "Grant"};
//可以简化成
var names = new String[]{"Aidan" , "Grant"};
//或
var names = new[]{ "Aidan" , "Grant"};
//还可以
string names = {"Aidan" , "Grant"};

这些是利用数组初始化器隐式类型局部变量完成的。

//不可以
var name = new[]{"Aidan", "Grant" , 123} //无法进行类型推断

还可以将隐式类型的数组匿名类型隐式类型局部变量结合起来

var kids = new[]{ new {Name = "Aidan"}, new {Name = "Grant"} };
//示例用法
foreach(var kid in kids)
    Console.WriteLine(kid.Name);

数组转型

成功转型要求数组维数相同,而且必须从元素源类型到目标类型的隐式或显示转换;CLR不允许将值类型元素的数组转型成任何其他类型。(不过可以利用Array.Copy方法创建数组并在其中填充元素模拟效果)

    // 创建二维FileStream数组
  FileStream[,] fs2dim = new FileStream[5, 10];

  // 把FileStream转为Object可以
  Object[,] o2dim = fs2dim;

  // 不能把二维转为一维
  // Compiler error CS0030: Cannot convert type 'object[*,*]' to 'System.IO.Stream[]'
  //Stream[] s1dim = (Stream[]) o2dim;

  // 把Object显示转型成Stream
  Stream[,] s2dim = (Stream[,])o2dim;

  // 编译通过,运行时异常
  // Compiles but throws InvalidCastException at runtime
  try {
     Type[,] t2dim = (Type[,])o2dim;
  }
  catch (InvalidCastException) {
  }

  // Int32数组,值类型
  Int32[] i1dim = new Int32[5];

  // 不能把值类型转为任何其他类型
  // Compiler error CS0030: Cannot convert type 'int[]' to 'object[]'
  // Object[] o1dim = (Object[]) i1dim;

  // However, Array.Copy knows how to coerce an array 
  // of value types to an array of boxed references
  //使用`Array.Copy`模拟
  Object[] o1dim = new Object[i1dim.Length];
  Array.Copy(i1dim, o1dim, 0);

下面演示Copy方法的另一种用法。

intername struct MyValueType:IComparable{
    public Int32 CompareTo(Object obj){
        ...
    }
}

public static class Program{
    public static void Main(){
        MyValueType[] src = new MyValueType[100];
        Icomparable[] dest = new IComparable[src.length];
        Array.Copy(src,dest,src.length); 
    }
}

所有数组都隐式派生子System.Array,都实现了IenumerabelICollectionIList接口

System.Array定义了许多方法和属性,极大方便了数组处理。CLoneCopyToGetLengthGetLongLengthGetLowerBoundGetUpperBoundLengthRank

数组的传递和返回

数组作为实参传递给方法是,实际传递的数组的引用。因此,被调用的方法能够修改数组的元素

如果定义返回数组引用的方法,而且数组中不包含元素,那么方法既可以返回null,也可以返回对包含零个元素的一维数组的引用。实现这种方法时,Microsoft建议让它返回后者,这样可以简化代码,如

Appintment[] appointments = GetAppointmentsForToday();
for(Int32 a = 0 ; a < appointments.Length ; a++){
    //对元素进行操作。
}


总结

后面还有创建下限非零的数组数组内部工作原理不安全数组等等内容,我觉得自己不大会使用到。现在也看不明白,今天的内容就是这么多。
今天整了一个四旋翼飞行器,明天试试能不能飞起来哈哈。

《CLR via C#》---枚举类型和标志位

枚举类型

枚举类型定义了一组符号名称/值配对。

 private enum Color /* : byte */ {
  White,       // Assigned a value of 0
  Red,         // Assigned a value of 1
  Green,       // Assigned a value of 2
  Blue,        // Assigned a value of 3
  Orange,      // Assigned a value of 4
}

枚举类型使程序更容易编写、阅读和维护;枚举类型是强类型的;枚举类型是值类型。

每个枚举类型都有一个基础类型,它可以是bytesbyteshortushortint(最常用,也是C#默认选择的)uintlongulong等,不能使用FCL类型。

internal enum Color:byte{
    White,
    Red,
    Green,
    Blue,
    Orange
}

//下面代码会显示`System.Byte`
Console.WriteLine(Enum.GetUnderlyingType(Typeof(Color)));

利用Enum提供的静态ParseTryParse方法,可以很容易的将符号类型转为枚举类型的实例。

//因为orange定义为4,‘C’被初始化为4
Color c = (Color)Enum.Parse(typeof(Color),"orange",true);
//没有定义Brown,所以会抛出异常
try {
     c = (Color)Enum.Parse(typeof(Color), "Brown", false);
  }
  catch (ArgumentException) {
     Console.WriteLine("Brown is not defined by the Color enumerated type.");
  }

可用IsDefined方法判断数值对于某枚举类型是否合法

// Displays "True" because Color defines Red as 1
//显示True,因为定义red为1
  Console.WriteLine(Enum.IsDefined(typeof(Color), 1));

  // Displays "True" because Color defines White as 0
  Console.WriteLine(Enum.IsDefined(typeof(Color), "White"));

  // Displays "False" because a case-sensitive check is performed 
  Console.WriteLine(Enum.IsDefined(typeof(Color), "white"));

  // Displays "False" ,因为没有和10对应的颜色
  Console.WriteLine(Enum.IsDefined(typeof(Color), 10));

IsDefined方法常被用于参数校验

public void SetColor(Color c){
    if(!Enum.IsDefined(typeof(Color),c)){
        throw(new ArgumentOutOfRangeException("C",c,"无效颜色值"));
    }
}

位标志

程序员要经常和位标志(bit flag)集合打交道。调用System.IO.File类型的GetAttributes方法,会返回FileAttributes类型的一个实例。FileAttribuges类型是基本类型为Int32的枚举类型,其中每一位都反映了文件的一个特性。FileAttributes类型在FCL中的定义为

// 摘要: 
//     提供文件和目录的属性。
[Serializable]
[ComVisible(true)]
[Flags]
public enum FileAttributes
{
    // 摘要: 
    //     此文件是只读的。
    ReadOnly = 1,//0x0001
    //
    // 摘要: 
    //     文件是隐藏的,因此没有包括在普通的目录列表中。
    Hidden = 2,//0x0002
    //
    // 摘要: 
    //     此文件是系统文件。 即,该文件是操作系统的一部分或者由操作系统以独占方式使用。
    System = 4,//0x0004
    //
    // 摘要: 
    //     此文件是一个目录。
    Directory = 16,
    //
    // 摘要: 
    //     该文件是备份或移除的候选文件。
    Archive = 32,
    //
    // 摘要: 
    //     保留供将来使用。
    Device = 64,
    //
    // 摘要: 
    //     该文件是没有特殊属性的标准文件。 仅当其单独使用时,此特性才有效。
    Normal = 128,
    //
    // 摘要: 
    //     文件是临时文件。 临时文件包含当执行应用程序时需要的,但当应用程序完成后不需要的数据。 文件系统尝试将所有数据保存在内存中,而不是将数据刷新回大容量存储,以便可以快速访问。
    //     当临时文件不再需要时,应用程序应立即删除它。
    Temporary = 256,
    //
    // 摘要: 
    //     此文件是稀疏文件。 稀疏文件一般是数据通常为零的大文件。
    SparseFile = 512,
    //
    // 摘要: 
    //     文件包含一个重新分析点,它是一个与文件或目录关联的用户定义的数据块。
    ReparsePoint = 1024,
    //
    // 摘要: 
    //     此文件是压缩文件。
    Compressed = 2048,
    //
    // 摘要: 
    //     此文件处于脱机状态, 文件数据不能立即供使用。
    Offline = 4096,
    //
    // 摘要: 
    //     将不会通过操作系统的内容索引服务来索引此文件。
    NotContentIndexed = 8192,
    //
    // 摘要: 
    //     此文件或目录已加密。 对于文件来说,表示文件中的所有数据都是加密的。 对于目录来说,表示新创建的文件和目录在默认情况下是加密的。
    Encrypted = 16384,
    //
    // 摘要: 
    //     文件或目录包括完整性支持数据。 在此值适用于文件时,文件中的所有数据流具有完整性支持。 此值将应用于一个目录时,所有新文件和子目录在该目录中和默认情况下应包括完整性支持。
    [ComVisible(false)]
    IntegrityStream = 32768,
    //
    // 摘要: 
    //     文件或目录从完整性扫描数据中排除。 此值将应用于一个目录时,所有新文件和子目录在该目录中和默认情况下应不包括数据完整性。
    [ComVisible(false)]
    NoScrubData = 131072,
}

判断文件是否隐藏可以使用以下代码

  String file = Assembly.GetEntryAssembly().Location;
  FileAttributes attributes = File.GetAttributes(file);
  Console.WriteLine("Is {0} hidden? {1}", file, (attributes & FileAttributes.Hidden) != 0);

强烈建议向枚举类型应用定制特性类型System.FlagsAttribute,如下

[Flags]     // The C# compiler allows either "Flags" or "FlagsAttribute".
public enum Actions {
  Read = 0x0001,
  Write = 0x0002,
  Delete = 0x0004,
  Query = 0x0008,
  Sync = 0x0010
}

使用Console.WriteLine(action.ToString())方法会输出Read等。

可以为枚举类型添加方法,通过使用扩展方法.

总结

今天的枚举类型在以前我使用的感觉不多,所以写起来也感觉倒也没有和前面那些一样有些恍然大悟的地方。将来会努力的使用频繁一些。