分类目录归档:C#

C#中实现单实例


public class SingletonDemo
{
    private static SingletonDemo theSingleton = null;
    private SingletonDemo() { }
    public static SingletonDemo Instance()
    {
        if (theSingleton == null)
        {
            theSingleton = new SingletonDemo();
        }
        return theSingleton;
    }
    static void Main(string[] args)
    {
        SingletonDemo s1 = SingletonDemo.Instance();
        SingletonDemo s2 = SingletonDemo.Instance();
        if (s1.Equals(s2))
        {
            Console.WriteLine("see, only one instance!");
        }
    }
}

C#中同步、异步读取进程输出信息

1、异步的:

p.StartInfo.RedirectStandardError = true;
p.ErrorDataReceived += new DataReceivedEventHandler(OutputInfo);
p.Start();
p.BeginErrorReadLine();
private void OutputInfo(object sendProcess, DataReceivedEventArgs output){
  if (!String.IsNullOrEmpty(output.Data))
  {
    //处理方法...
  }
}

2、同步的

p.StartInfo.RedirectStandardError = true;
p.Start();
StreamReader sr = ffmpeg.StandardError;
p.WaitForExit();//之后就可以从sr里读了

C#中枚举类型enum的使用

1、关于enum的定义

enum Fabric
{
  Cotton = 1,
  Silk = 2,
  Wool = 4,
  Rayon = 8,
  Other = 128
}

2、符号名和常数值的互相转换

Fabric fab = Fabric.Cotton;
int fabNum = (int)fab;//转换为常数值。必须使用强制转换。
Fabric fabString = (Fabric)1;//常数值转换成符号名。如果使用ToString(),则是((Fabric)1).ToString(),注意必须有括号。
string fabType = fab.ToString();//显示符号名
string fabVal = fab.ToString ("D");//显示常数值

3、获得所有符号名的方法(具体参见Enum类)

public enum MyFamily
{
  YANGZHIPING = 1,
  GUANGUIQIN = 2,
  YANGHAORAN = 4,
  LIWEI = 8,
  GUANGUIZHI = 16,
  LISIWEN = 32,
  LISIHUA = 64,
}
foreach (string s in Enum.GetNames(typeof(MyFamily)))
{
  Console.WriteLine(s);
}

4、将枚举作为位标志来处理

根据下面的两个例子,粗略地说,一方面,设置标志[Flags]或者[FlagsAttribute],则表明要将符号名列举出来;另一方面,可以通过强制转换,将数字转换为符号名。说不准确。看下面的例子体会吧。注意:

  • 例一:
Fabric fab = Fabric.Cotton | Fabric.Rayon | Fabric.Silk;
Console.WriteLine("MyFabric = {0}", fab);//输出:Fabric.Cotton | Fabric.Rayon | Fabric.Silk;
  • 例二:
class FlagsAttributeDemo
{
  // Define an Enum without FlagsAttribute.
  enum SingleHue : short
  {
    Black = 0,
    Red = 1,
    Green = 2,
    Blue = 4
  };
  // Define an Enum with FlagsAttribute.
  [FlagsAttribute]
  enum MultiHue : short
  {
    Black = 0,
    Red = 1,
    Green = 2,
    Blue = 4
  };
  static void Main( )
  {
    Console.WriteLine(
    "This example of the FlagsAttribute attribute n" +
    "generates the following output." );
    Console.WriteLine(
    "nAll possible combinations of values of an n" +
    "Enum without FlagsAttribute:n" );
    // Display all possible combinations of values.
    for( int val = 0; val <= 8; val++ )
    Console.WriteLine( "{0,3} – {1}",  val, ( (SingleHue)val ).ToString( ) );
    Console.WriteLine(  "nAll possible combinations of values of an n" + "Enum with FlagsAttribute:n" );
    // Display all possible combinations of values.
    // Also display an invalid value.
    for( int val = 0; val <= 8; val++ )
    Console.WriteLine ( "{0,3} – {1}",  val, ( (MultiHue)val ).ToString( ) );
  }
}
/*
This example of the FlagsAttribute attribute
generates the following output.
All possible combinations of values of an
Enum without FlagsAttribute:
0 – Black
1 – Red
2 – Green
3 – 3
4 – Blue
5 – 5
6 – 6
7 – 7
8 – 8
All possible combinations of values of an
Enum with FlagsAttribute:
0 – Black
1 – Red
2 – Green
3 – Red, Green
4 – Blue
5 – Red, Blue
6 – Green, Blue
7 – Red, Green, Blue
8 – 8
*/

5、枚举作为函数参数。经常和switch结合起来使用。下面举例

public static double GetPrice(Fabric fab)
{
  switch (fab)
  {
    case Fabric.Cotton:
      return (3.55);
    case Fabric.Silk:
      return (5.65);
    case Fabric.Wool:
      return (4.05);
    case Fabric.Rayon:
      return (3.20);
    case Fabric.Other:
      return (2.50);
    default:
      return (0.0);
  }
}

6、上面三点一个完整的例子

//enum的定义
public enum Fabric : short
{
  Cotton = 1,
  Silk = 2,
  Wool = 3,
  Rayon = 8,
  Other = 128
}
//将枚举作为参数传递
public static double GetPrice(Fabric fab)
{
  switch (fab)
  {
    case Fabric.Cotton: return (3.55);
    case Fabric.Silk : return (5.65);
    case Fabric.Wool: return (4.05);
    case Fabric.Rayon: return (3.20);
    case Fabric.Other: return (2.50);
    default: return (0.0);
  }
}
public static void Main()
{
  Fabric fab = Fabric.Cotton;
  int fabNum = (int)fab;
  string fabType = fab.ToString();
  string fabVal = fab.ToString ("D");
  double cost = GetPrice(fab);
  Console.WriteLine("fabNum = {0}nfabType = {1}nfabVal = {2}n", fabNum, fabType, fabVal);
  Console.WriteLine("cost = {0}", cost);
}

7、Enum类的使用

Enum.IsDefindeEnum.Parse两种方法经常一起使用,来确定一个值或符号是否是一个枚举的成员,然后创建一个实例。Enum.GetName打印出一个成员的值;Enum.GetNames打印出所有成员的值。其中注意**“`typeof“`**的使用。这一点很重要。

public enum MyFamily
{
  YANGZHIPING = 1,
  GUANGUIQIN = 2,
  YANGHAORAN = 4,
  LIWEI = 8,
  GUANGUIZHI = 16,
  LISIWEN = 32,
  LISIHUA = 64,
}
string s = "YANGHAORAN";
if (Enum.IsDefined(typeof(MyFamily), s))
{
  MyFamily f = (MyFamily)Enum.Parse(typeof(MyFamily), s);
  GetMyFamily(f);
  Console.WriteLine("The name is:" + Enum. GetName(typeof(MyFamily), 2));
  string[] sa = Enum.GetNames(typeof(MyFamily));
  foreach (string ss in sa)
  {
    Console.WriteLine(ss);
  }
}

list contains 类

Subscription sub = new Subscription();
sub.Appname = subName;
if (this.Subscriptions.Contains(sub,new SubcriptionComparer<Subscription>()))
  return true;
else
  return false;
class SubcriptionComparer<T> : IEqualityComparer<T>
where T : Subscription
{
  public int GetHashCode(T obj)
  {
    return obj.GetHashCode();
  }
  public bool Equals(T t1, T t2)
  {
    return t1.Appname == t2.Appname;
  }
}

String.Format格式说明

C#格式化数值结果表

字符 说明 示例 输出
C 货币 string.Format("{0:C3}", 2) $2.000
D 十进制 string.Format("{0:D3}", 2) 002
E 科学计数法 1.20E+001 1.20E+001
G 常规 string.Format("{0:G}", 2) 2
N 用分号隔开的数字 string.Format("{0:N}", 250000) 250,000.00
X 十六进制 string.Format("{0:X000}", 12) C
string.Format("{0:000.000}", 12.2) 012.200

Strings

There really isn’t any formatting within a strong, beyond it’s alignment. Alignment works for any argument being printed in a String.Format call.

Sample Generates
String.Format("->{1,10}<-", "Hello"); -> Hello<-
String.Format("->{1,-10}<-", "Hello"); ->Hello <-

Numbers

Basic number formatting specifiers:

Specifier Type Format Output (Passed Double 1.42) Output (Passed Int -12400)
c Currency {0:c} $1.42 -$12,400
d Decimal (Whole number) {0:d} System.FormatException -12400
e Scientific {0:e} 1.420000e+000 -1.240000e+004
f Fixed point {0:f} 1.42 -12400.00
g General {0:g} 1.42 -12400
n Number with commas for thousands {0:n} 1.42 -12,400
r Round trippable {0:r} 1.42 System.FormatException
x Hexadecimal {0:x4} System.FormatException cf90

Custom number formatting:

Specifier Type Example Output (Passed Double 1500.42) Note
0 Zero placeholder {0:00.0000} 1500.4200 Pads with zeroes.
# Digit placeholder {0:(#).##} (1500).42
. Decimal point {0:0.0} 1500.4
, Thousand separator {0:0,0} 1,500 Must be between two zeroes.
,. Number scaling {0:0,.} 2 Comma adjacent to Period scales by 1000.
% Percent {0:0%} 150042% Multiplies by 100, adds % sign.
e Exponent placeholder {0:00e+0} 15e+2 Many exponent formats available.
; Group separator see below  

The group separator is especially useful for formatting currency values which require that negative values be enclosed in parentheses. This currency formatting example at the bottom of this document makes it obvious:

Dates

Note that date formatting is especially dependant on the system’s regional settings; the example strings here are from my local locale.

Specifier Type Example (Passed System.DateTime.Now)
d Short date 10/12/2002
D Long date December 10, 2002
t Short time 10:11 PM
T Long time 10:11:29 PM
f Full date & time December 10, 2002 10:11 PM
F Full date & time (long) December 10, 2002 10:11:29 PM
g Default date & time 10/12/2002 10:11 PM
G Default date & time (long) 10/12/2002 10:11:29 PM
M Month day pattern December 10
r RFC1123 date string Tue, 10 Dec 2002 22:11:29 GMT
s Sortable date string 2002-12-10T22:11:29
u Universal sortable, local time 2002-12-10 22:13:50Z
U Universal sortable, GMT December 11, 2002 3:13:50 AM
Y Year month pattern December, 2002

The ‘U’ specifier seems broken; that string certainly isn’t sortable.
Custom date formatting:
 

Specifier Type Example Example Output
dd Day {0:dd} 10
ddd Day name {0:ddd} Tue
dddd Full day name {0:dddd} Tuesday
f, ff, … Second fractions {0:fff} 932
gg, … Era {0:gg} A.D.
hh 2 digit hour {0:hh} 10
HH 2 digit hour, 24hr format {0:HH} 22
mm Minute 00-59 {0:mm} 38
MM Month 01-12 {0:MM} 12
MMM Month abbreviation {0:MMM} Dec
MMMM Full month name {0:MMMM} December
ss Seconds 00-59 {0:ss} 46
tt AM or PM {0:tt} PM
yy Year, 2 digits {0:yy} 02
yyyy Year {0:yyyy} 2002
zz Timezone offset, 2 digits {0:zz} -05
zzz Full timezone offset {0:zzz} -05:00
: Separator {0:hh:mm:ss} 10:43:20
/ Separator {0:dd/MM/yyyy} 10/12/2002

Enumerations

 

Specifier Type
g Default (Flag names if available, otherwise decimal)
f Flags always
d Integer always
x Eight digit hex.

Some Useful Examples

String.Format("{0:$#,##0.00;($#,##0.00);Zero}", value);
This will output "$1,240.00" if passed 1243.50. It will output the same format but in parentheses if the number is negative, and will output the string "Zero" if the number is zero.
String.Format("{0:(###) ###-####}", 18005551212);
This will output "(800) 555-1212".
 
变量.ToString()
字符型转换 转为字符串

12345.ToString("n"); //生成 12,345.00
12345.ToString("C"); //生成 ¥12,345.00
12345.ToString("e"); //生成 1.234500e+004
12345.ToString("f4"); //生成 12345.0000
12345.ToString("x"); //生成 3039 (16进制)
12345.ToString("p"); //生成 1,234,500.00%

C# List 排序

写一个sorter

public class CourseSorter:IComparer
{
  #region IComparer Members
  public int Compare(CourseDto x, CourseDto y)
  {
    return x.Title.CompareTo(y.Title);
  }
  #endregion
}

用的时候list.sort(new Sorter());即可

String.getBytes()方法中的中文编码问题

String 的getBytes()方法是得到一个字串的字节数组,这是众所周知的。但特别要注意的是,本方法将返回该操作系统默认的编码格式的字节数组。如果你在使 用这个方法时不考虑到这一点,你会发现在一个平台上运行良好的系统,放到另外一台机器后会产生意想不到的问题。

String的getBytes()方法是得到一个字串的字节数组,这是众所周知的。但特别要注意的是,本方法将返回该操作系统默认的编码格式的字 节数组。如果你在使用这个方法时不考虑到这一点,你会发现在一个平台上运行良好的系统,放到另外一台机器后会产生意想不到的问题。比如下面的程序:

class TestCharset 
{

    public static void main(String[] args) 
{
new TestCharset().execute();
}

    private void execute() {
String s = "Hello!你好!";

byte[] bytes = s.getBytes();

        System.out.println("bytes
lenght is:" + bytes.length);

}

}

在一个中文WindowsXP系统下,运行时,结果为:

bytes lenght is:12

 但是如果放到了一个英文的UNIX环境下运行:

$ java TestCharset
bytes lenght is:9

如果你的程序依赖于该结果,将在后续操作中引起问题。为什么在一个系统中结果为12,而在另外一个却变成了9了呢?上面已经提到了,该方法是和平台(编码)相关的。

在中文操作系统中,getBytes方法返回的是一个GBK或者GB2312的中文编码的字节数组,其中中文字符,各占两个字节。而在英文平台中,一般的默认编码是“ISO-8859-1”,每个字符都只取一个字节(而不管是否非拉丁字符)。

Java中的编码支持

Java是支持多国编码的,在Java中,字符都是以Unicode进行存储的,比如,“你”字的Unicode编码是“4f60”,我们可以通过下面的实验代码来验证:

class TestCharset 
{

    public static void main(String[] args) 
{
char c = ‘你’;
int i = c;
System.out.println(c);
System.out.println(i);
}

}

不管你在任何平台上执行,都会有相同的输出:

20320

20320就是Unicode “4f60”的整数值。其实,你可以反编译上面的类,可以发现在生成的.class文件中字符“你”(或者其它任何中文字串)本身就是以Unicode编码进行存储的:

char c = ‘u4F60’;
… …

即使你知道了编码的编码格式,比如:

javac -encoding GBK TestCharset.java

编译后生成的.class文件中仍然是以Unicode格式存储中文字符或字符串的。使用String.getBytes(String charset)方法

所以,为了避免这种问题,我建议大家都在编码中使用String.getBytes(String charset)方法。下面我们将从字串分别提取ISO-8859-1和GBK两种编码格式的字节数组,看看会有什么结果:

class TestCharset 
{

    public static void main(String[] args) 
{
new TestCharset().execute();
}

    private void execute() {
String s = "Hello!你好!";

byte[] bytesISO8859 =null;
byte[] bytesGBK = null;

        try
{
bytesISO8859 =
s.getBytes("iso-8859-1");
bytesGBK = s.getBytes("GBK");
}
catch
(java.io.UnsupportedEncodingException e)
{
e.printStackTrace();
}

        System.out.println
("————–
n 8859 bytes:");
System.out.println("bytes is:     " + arrayToString(bytesISO8859));
System.out.println("hex format is:"
+ encodeHex(bytesISO8859));
System.out.println();

        System.out.println
("————–
n GBK bytes:");
System.out.println("bytes is:   
" + arrayToString(bytesGBK));
System.out.println("hex format
is:" + encodeHex(bytesGBK));

    }

    public static final String
encodeHex (byte[] bytes)
{
StringBuffer buff =
new StringBuffer(bytes.length * 2);
String b;
for (int i=0; i< bytes.length ; i++)
{
b = Integer.toHexString(bytes[i]); 
// byte是两个字节的,
而上面的Integer.toHexString会把字节扩展为4个字节
buff.append(b.length() > 2 ? b.substring(6,8) : b); 
buff.append(" ");
}
return buff.toString();
}

    public static final String
arrayToString (byte[] bytes)
{
StringBuffer buff = new StringBuffer();
for (int i=0; i< bytes.length ; i++)
{
buff.append(bytes[i] + " ");
}
return buff.toString();
}

}

执行上面程序将打印出:

————–
8859 bytes:
bytes is:     72 101 108 108 111 33 63 63 63
hex format is:48 65 6c 6c 6f 21 3f 3f 3f

————–
GBK bytes:
bytes is:     72 101 108 108 111 33
-60 -29 -70 -61 -93 -95
hex format is:48 65 6c 6c 6f 21 c4 e3 ba c3 a3 a1

可见,在s中提取的8859-1格式的字节数组长度为9,中文字符都变成了“63”,ASCII码为63的是“?”,一些国外的程序在国内中文环境下运行时,经常出现乱码,上面布满了“?”,就是因为编码没有进行正确处理的结果。

而提取的GBK编码的字节数组中正确得到了中文字符的GBK编码。字符“你”“好”“!”的GBK编码分别是:“c4e3”“bac3”“a3a1”。得到了正确的以GBK编码的字节数组,以后需要还原为中文字串时,可以使用下面方法:

new String(byte[] bytes,
String charset)

C#中class和struct的区别和用法

1,class 是引用类型,structs是值类型

既然class是引用类型,class可以设为null。但是我们不能将struct设为null,因为它是值类型。

struct AStruct
{
  int aField;
}
class  AClass
{
  int aField;
}
class MainClass
{
  public static void Main()
  {
    AClass b = null; // No error.
    AStruct s = null; // Error [ Cannot convert null to 'AStruct'
    because it is a value type ].
  }
}

2,当你实例一个class,它将创建在堆上。而你实例一个struct,它将创建在栈上

3,你使用的是一个对class实例的引用。而你使用的不是对一个struct的引用。(而是直接使用它们)

4,当我们将class作为参数传给一个方法,我们传递的是一个引用。struct传递的是值而非引用。

5,structs, 不可以有初始化器,class可以有初始化器。

class MyClass
{
  int myVar =10;  //  no syntax error.
  public void MyFun( )
  {
    // statements
  }
}
struct MyStruct
{
  int myVar = 10;  //  syntax error.
  public void MyFun( )
  {
    // statements
  }
}

6,Classes 可以有明显的无参数构造器,但是Struct不可以

class MyClass
{
  int myVar = 10;
  public MyClass( ) // no syntax error.
  {
    // statements
  }
}
struct MyStruct
{
  int myVar;
  public MyStruct( ) // syntax error.
  {
    // statements
  }
}

7, 类使用前必须new关键字实例化,Struct不需要

MyClass aClassObj;     //  MyClass aClassObj=new MyClass(); is the correct format.aClassObj.
myVar=100;//NullReferenceException(because aClassObj does not contain a reference to an object of type myClass).
MyStruct  aStructObj;
aStructObj.myVar=100; //  no exception.

8, class支持继承和多态,Struct不支持. 注意:但是Struct 可以鹤类一样实现接口

9, 既然Struct不支持继承,其成员不能以protected 或Protected Internal 修饰

10, Class的构造器不需要初始化全部字段,Struct的构造器必须初始化所有字段

class MyClass    //No error( No matter whether the Field ’ MyClass.myString ’ is initialized or not ).
{
  int myInt;
  string myString;
  public MyClass( int aInt )
  {
    myInt = aInt;
  }
}
struct MyStruct    // Error ( Field ’ MyStruct.myString ’ must be fully assigned before it leaves the constructor ).
{
  int myInt;
  string myString;
  public MyStruct( int aInt )
  {
    myInt = aInt;
  }
}

11, Class可以定义析构器但是Struct不可以

12, Class比较适合大的和复杂的数据,Struct适用于作为经常使用的一些数据组合成的新类型。

适用场合:Struct有性能优势,Class有面向对象的扩展优势。
用于底层数据存储的类型设计为Struct类型,将用于定义应用程序行为的类型设计为Class。如果对类型将来的应用情况不能确定,应该使用Class。