幸福清扬

之技术学习

  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
  19 随笔 :: 3 文章 :: 5 评论 :: 0 引用

2011年3月7日 #

.NET Delegates: A C# Bedtime Story

The following is an excerpt from Windows Forms 2.0 Programming, Chris Sells & Michael Weinhardt, Addison-Wesley, 2006. It's been updated from the original version for C# 2.0.

Once upon a time, in a strange land south of here, there was a worker named Peter. He was a diligent worker who would readily accept requests from his boss. However, his boss was a mean, untrusting man who insisted on steady progress reports. Since Peter did not want his boss standing in his office looking over his shoulder, Peter promised to notify his boss whenever his work progressed. Peter implemented this promise by periodically calling his boss back via a typed reference like so:

class Worker {
  Boss boss;
 
  public void Advise(Boss boss) {
    this.boss = boss;
  }
 
  public void DoWork() {
    Console.WriteLine("Worker: work started");
    if( this.boss != null ) this.boss.WorkStarted();
 
    Console.WriteLine("Worker: work progressing");
    if( this.boss != null ) this.boss.WorkProgressing();
 
    Console.WriteLine("Worker: work completed");
    if( this.boss != null ) {
      int grade = this.boss.WorkCompleted();
      Console.WriteLine("Worker grade= {0}", grade);
    }
  }
}
 
class Boss {
  public void WorkStarted() {
    // Boss doesn't care
 
}
  public void WorkProgressing() {
    // Boss doesn't care
 
}
  public int WorkCompleted() {
    Console.WriteLine("It's about time!");
    return 2; // out of 10
  }
}
 
class Universe {
  static void Main() {
    Worker peter = new Worker();
    Boss boss = new Boss();
    peter.Advise(boss);
    peter.DoWork();
 
    Console.WriteLine("Main: worker completed work");
    Console.ReadLine();
  }
}

Interfaces

Now Peter was a special person. Not only was he able to put up with his mean-spirited boss, but he also had a deep connection with the universe around him. So much so that he felt that the universe was interested in his progress. Unfortunately, there was no way for Peter to advise the Universe of his progress unless he added a special Advise method and special callbacks just for the Universe, in addition to keeping his boss informed. What Peter really wanted to do was to separate the list of potential notifications from the implementation of those notification methods. And so he decided to split the methods into an interface:

interface IWorkerEvents {
  void WorkStarted();
  void WorkProgressing();
  int WorkCompleted();
}
 
class Worker {
  IWorkerEvents events;
 
  public void Advise(IWorkerEvents events) {
    this.events = events;
  }
 
  public void DoWork() {
    Console.WriteLine("Worker: work started");
    if( this.events != null ) this.events.WorkStarted();
 
    Console.WriteLine("Worker: work progressing");
    if( this.events != null ) this.events.WorkProgressing();
 
    Console.WriteLine("Worker: work completed");
    if( this.events!= null ) {
      int grade = this.events.WorkCompleted();
      Console.WriteLine("Worker grade= {0}", grade);
    }
  }
}
 
class Boss : IWorkerEvents {
  public void WorkStarted() {
    // Boss doesn't care
  }
  public void WorkProgressing() {
    // Boss doesn't care
  }
  public int WorkCompleted() {
    Console.WriteLine("It's about time!");
    return 3; // out of 10
  }
}

Delegates

Unfortunately, Peter was so busy talking his boss into implementing this interface that he didn't get around to notifying the Universe, but he knew he would soon. At least he'd abstracted the reference of his boss far away from him so that others who implemented the IWorkerEvents interface could be notified of his work progress.

Still, his boss complained bitterly. "Peter!" his boss fumed. "Why are you bothering to notify me when you start your work or when your work is progressing?!? I don't care about those events. Not only do you force me to implement those methods, but you're wasting valuable work time waiting for me to return from the event, which is further expanded when I am far away! Can't you figure out a way to stop bothering me?"

And so, Peter decided that while interfaces were useful for many things, when it came to events, their granularity was not fine enough. He wished to be able to notify interested parties only of the events that matched their hearts' desires. So, he decided to break the methods out of the interface into separate delegate functions, each of which acted like a little tiny interface of one method each:

delegate void WorkStarted();
delegate void WorkProgressing();
delegate int WorkCompleted();
 
class Worker {
  public WorkStarted Started;
  public WorkProgressing Progressing;
  public WorkCompleted Completed;
 
  public void DoWork() {
    Console.WriteLine("Worker: work started");
    if( this.Started != null ) this.Started();
 
    Console.WriteLine("Worker: work progressing");
    if( this.Progressing != null ) this.Progressing();
 
    Console.WriteLine("Worker: work completed");
    if( this.Completed != null ) {
      int grade = this.Completed();
      Console.WriteLine("Worker grade= {0}", grade);
    }
  }
}
 
class Boss {
  public int WorkCompleted() {
    Console.WriteLine("It's about time!");
    return 4; // out of 10
  }
}
 
class Universe {
  static void Main() {
    Worker peter = new Worker();
    Boss boss = new Boss();
 
    // NOTE: We've replaced the Advise method with the assignment operation
    peter.Completed = new WorkCompleted(boss.WorkCompleted);
    peter.DoWork();
 
    Console.WriteLine("Main: worker completed work");
    Console.ReadLine();
  }
}

And, because Peter was under so much pressure, he decided to advantage of the shorthand notation for assigning delegates provided by C# 2.0:

class Universe {
  static void Main() {
    ...
    peter.Completed = boss.WorkCompleted;
    ...
  }
}

Static Listeners

Delegates accomplished the goal of not bothering his boss with events that he didn't want, but still Peter had not managed to get the universe on his list of listeners. Since the universe is an all-encompassing entity, it didn't seem right to hook delegates to instance members (imagine how many resources multiple instances of the universe would need...). Instead, Peter need to hook delegates to static members, which delegates support fully:

class Universe {
  static void WorkerStartedWork() {
    Console.WriteLine("Universe notices worker starting work");
  }
 
  static int WorkerCompletedWork() {
    Console.WriteLine("Universe pleased with worker's work");
    return 7;
  }
 
  static void Main() {
    Worker peter = new Worker();
    Boss boss = new Boss();
 
    peter.Completed = boss.WorkCompleted;
    peter.Started = WorkerStartedWork;
    peter.Completed = WorkerCompletedWork; // Oops!
    peter.DoWork();
 
    Console.WriteLine("Main: worker completed work");
    Console.ReadLine();
  }
}

Events

Unfortunately, the Universe being very busy and unaccustomed to paying attention to individuals, has managed to replace Peter's boss's delegate with its own. This is an unintended side effect of making the delegate fields public in Peter's Worker class. Likewise, if Peter's boss gets impatient, he can decide to fire Peter's delegates himself (which is just the kind of rude thing that Peter's boss was apt to do):

// Peter's boss taking matters into his own hands
if( peter.Completed != null ) peter.Completed(); 

Peter wants to make sure that neither of these can happens. He realizes he needs to add registration and unregistration functions for each delegate so that listeners can add or remove themselves, but can't clear the entire list or fire Peter's events. Instead of implementing these functions himself, Peter uses the event keyword to make the C# compiler build these methods for him:

class Worker {
  public event WorkStarted Started;
  public event WorkProgressing Progressing;
  public event WorkCompleted Completed;
  ...
}

Peter knows that the event keyword erects a property around a delegate, only allowing clients to add or remove themselves (using the += and -= operators in C#), forcing his boss and the universe to play nicely:

class Universe {
  ...
  static void Main() {
    Worker peter = new Worker();
    Boss boss = new Boss();

    peter.Completed = boss.WorkCompleted; // ERR!
    peter.Completed += boss.WorkCompleted; // OK
    peter.Started += Universe.WorkerStartedWork; // OK
    peter.Completed += Universe.WorkerCompletedWork; // OK

    peter.DoWork();

    Console.WriteLine("Main: worker completed work");
    Console.ReadLine();
  }
}

Harvesting All Results

At this point, Peter breathes a sigh of relief. He has managed to satisfy the requirements of all his listeners without having to be closely coupled with the specific implementations. However, he notices that while both his boss and the universe provide grades of his work that he's only receiving one of the grades. In the face of multiple listeners, he'd really like to harvest all of their results. So, he reaches into his delegate and pulls out the list of listeners so that he can call each of them manually:

class Worker {
  ...
  public void DoWork() {
    ...
    Console.WriteLine("Worker: work completed");
 
    if( this.Completed != null ) {
      foreach( WorkCompleted wc in this.Completed.GetInvocationList() ) {
        int grade = wc();
        Console.WriteLine("Worker grade= {0}", grade);
      }
    }
  }
}
 
public void DoWork() {
  ...
  Console.WriteLine("Worker: work completed");
 
if( completed != null ) {
    foreach( WorkCompleted wc in completed.GetInvocationList() ) {
     
int grade = wc();
      Console.WriteLine("Worker grade= " + grade);
    }
  }
}

Asynchronous Notification: Fire & Forget

In the meantime, his boss and the universe have been distracted with other things, which meant that the time it takes them to grade Peter's work is greatly expanded:

class Boss {
  public int WorkCompleted() {
    System.Threading.Thread.Sleep(5000);
    Console.WriteLine("Better...");
    return 4; // out of 10
  }
}

class Universe {
  ...
  static int WorkerCompletedWork() {
    System.Threading.Thread.Sleep(1000000);
    Console.WriteLine("Universe pleased with worker's work");
    return 7;
  }
  ...
}

Unfortunately, since Peter is notifying each listener one at a time, waiting for each to grade him, these notifications now take up quite a bit of his time when he should be working. So, he decides to forget the grade and just fire the event asynchronously:

class Worker {
  ...
  public void DoWork() {
    ...
    Console.WriteLine("Worker: work completed");
    if( this.Completed != null ) {
      foreach( WorkCompleted wc in this.Completed.GetInvocationList() ) {
        wc.BeginInvoke(null, null); // EndInvoke call required by .NET
      }
    }
  }
}

Asynchronous Notification: Polling

The call to BeginInvoke allows Peter to notify the listeners while letting Peter get back to work immediately, letting the process thread pool invoke the delegate. Over time, however, Peter finds that he misses the feedback on his work. He knows that he does a good job and appreciates the praise of the universe as a whole (if not his boss specifically). Plus, he was afraid that he was leaking .NET resources acquired by calling BeginInvoke without calling the corresponding EndInvoke method, so, he fires the event asynchronously, but polls periodically, looking for the grade to be available:

class Worker {
  ...
  public void DoWork() {
    ...
    Console.WriteLine("Worker: work completed");
    if( this.Completed != null ) {
      foreach( WorkCompleted wc in this.Completed.GetInvocationList() ) {
        IAsyncResult result = wc.BeginInvoke(null, null);
        while( !result.IsCompleted ) System.Threading.Thread.Sleep(1);
        int grade = wc.EndInvoke(result);
       Console.WriteLine("Worker grade= {0}", grade);
      }
    }
  }
}

Asynchronous Notification: Delegates

Unfortunately, Peter is back to what he wanted his boss to avoid with him in the beginning, i.e. looking over the shoulder of the entity doing the work. So, he decides to employ his own delegate as a means of notification when the asynchronous work has completed, allowing him to get back to work immediately, but still be notified when his work has been graded:

class Worker {
  ...
  public void DoWork() {
    ...
    Console.WriteLine("Worker: work completed");
    if( this.Completed != null ) {
      foreach( WorkCompleted wc in this.Completed.GetInvocationList() ) {
        wc.BeginInvoke(this.WorkGraded, wc);
      }
    }
  }

  void WorkGraded(IAsyncResult result) {
    WorkCompleted wc = (WorkCompleted)result.AsyncState;
    int grade = wc.EndInvoke(result);
    Console.WriteLine("Worker grade= {0}" + grade);
  }
}

Anonymous Delegates

At this point, Peter is using delegates to notify interested parties in the process of his work and using delegates to get notified when grades are available on the work he抯 completed. The delegates provided by his boss and the universe are provided by separate entities, so it makes sense that they are encapsulated in methods on those entities. However, in the case of the WorkGraded method, there抯 really no good reason for this to be a separate method except the syntactic requirements of C# 1.0. As of C# 2.0, Peter can drop the code required to handle the processing of his work grade into an anonymous delegate:

class Worker {
  ...
  public void DoWork() {
    ...
    Console.WriteLine("Worker: work completed");
    if( this.Completed != null ) {
      foreach( WorkCompleted wc in this.Completed.GetInvocationList() ) {
        wc.BeginInvoke(delegate(IAsyncResult result) {
          WorkCompleted wc2 = (WorkCompleted)result.AsyncState;
          int grade = wc2.EndInvoke(result);
          Console.WriteLine("Worker grade= {0}", grade);
        }
,
        wc);
      }
    }
  }
}

Here, instead of passing in the name of a method to call when his work has been graded, he抯 passing in the body of the method itself as designated with a different use of the delegate keyword to create a method with no name (and therefore 揳nonymous?. The body of the method is fundamentally the same in that Peter still passes the WorkCompleted delegate as a parameter to BeginInvoke and then pulls it out of AsyncState for use in extracting the result. However, one of the benefits of anonymous delegates that Peter knows is that he can make use of the variables in the surrounding context from within the anonymous delegate body, causing him to rewrite his code thusly:

class Worker {
  ...
  public void DoWork() {
    ...
    Console.WriteLine("Worker: work completed");
    if( this.Completed != null ) {
      foreach( WorkCompleted wc in this.Completed.GetInvocationList() ) {
        wc.BeginInvoke(delegate(IAsyncResult result) {
          // Use wc variable from surrounding context (ERR!)
          int grade = wc.EndInvoke(result);
          Console.WriteLine("Worker grade= {0}", grade);
        },
        null);
      }
    }
  }
}

This code compiles just fine, but when it抯 run, it will cause the following exception to be thrown:

System.InvalidOperationException:
  The IAsyncResult object provided does not match this delegate.

The problem is that while the wc variable is allowed to be used in the anonymous delegate, it抯 still being used by the for-each statement. As soon as the asynchronous invocation begins, the wc variable changes and the delegate used to start things (wc) no longer matches the async result passed as an argument to the anonymous delegate. Peter slaps his head and creates a hybrid solution:

class Worker {
  ...
  public void DoWork() {
    ...
    Console.WriteLine("Worker: work completed");
    if( this.Completed != null ) {
      foreach( WorkCompleted wc in this.Completed.GetInvocationList() ) {
        // Create an unchanging variable referencing the current delegate
        WorkCompleted wc2 = wc;
        wc.BeginInvoke(delegate(IAsyncResult result) {
          // Use wc2 variable from surrounding context
          int grade = wc2.EndInvoke(result);
          Console.WriteLine("Worker grade= {0}", grade);
        },
        null);
      }
    }
  }
}
 
public void DoWork() {
  ...
  Console.WriteLine("Worker: work completed");
 
if( completed != null ) {
    foreach( WorkCompleted wc in completed.GetInvocationList() ) {
      wc.BeginInvoke(
new AsyncCallback(WorkGraded), wc);
    }
  }
}
 
void WorkGraded(IAsyncResult res) {
  WorkCompleted wc = (WorkCompleted)res.AsyncState;
 
int grade = wc.EndInvoke(res);
  Console.WriteLine("Worker grade= " + grade);
}

Happiness in the Universe

Peter, his boss and the universe are finally satisfied. Peter's boss and the universe are allowed to be notified of the events that interest them, reducing the burden of implementation and the cost of unnecessary round-trips. Peter can notify them each, ignoring how long it takes them to return from their target methods, while still getting his results asynchronously and handling them using anonymous delegates, resulting in the following complete solution:

delegate void WorkStarted();
delegate void WorkProgressing();
delegate int WorkCompleted();

class Worker {
  public event WorkStarted Started;
  public event WorkProgressing Progressing;
  public event WorkCompleted Completed;
 
  public void DoWork() {
    Console.WriteLine("Worker: work started");
    if( this.Started != null )
      this.Started();
 
    Console.WriteLine("Worker: work progressing");
    if( this.Progressing != null )
      this.Progressing();
 
    Console.WriteLine("Worker: work completed");
    if( this.Completed != null ) {
      foreach( WorkCompleted wc in this.Completed.GetInvocationList() ) {
        WorkCompleted wc2 = wc;
        wc.BeginInvoke(delegate(IAsyncResult result) {
          int grade = wc2.EndInvoke(result);
          Console.WriteLine("Worker grade= {0}", grade);
        },
        null);
      }
    }
  }
}

class Boss {
  public int WorkCompleted() {
    System.Threading.Thread.Sleep(3000);
    Console.WriteLine("Better...");
    return 5; // out of 10
  }
}

class Universe {
  static void WorkerStartedWork() {
    Console.WriteLine("Universe notices worker starting work");
  }

  static int WorkerCompletedWork() {
    System.Threading.Thread.Sleep(4000);
    Console.WriteLine("Universe pleased with worker's work");
    return 7;
  }

  static void Main() {
    Worker peter = new Worker();
    Boss boss = new Boss();
    peter.Completed += boss.WorkCompleted;
    peter.Started += Universe.WorkerStartedWork;
    peter.Completed += Universe.WorkerCompletedWork;
    peter.DoWork();

    Console.WriteLine("Main: worker completed work");
  }
}

Peter knows that getting results asynchronously comes with issues, because as soon as he fires events asynchronously, the target methods are likely to be executed on another thread, as is Peter's notification of when the target method has completed. However, Peter is good friends with Mike, who is very familiar with threading issues and can provide guidance in that area.

And they all lived happily every after.

The end.

posted @ 2011-03-07 10:47 杨连国 阅读(100) 评论(0) 编辑

2010年9月16日 #

在C++内,声明一个变量的同时就为其分配了内存空间,如数组、对象等,而 new 只是针对指针类型。

 

而C#中,声明分成了引用类型和值类型,引用类型的声明只是产生了一个指针,而要获得实际的内存空间必须使用new。

 

另外,在C++中关于参数引用和函数返回值也存在类似的情况,例如类对象,如果不明确指出使用引用或指针,则按值赋值的方式复制了一遍,这和C#缺省就是引用的情况不同。

posted @ 2010-09-16 17:08 杨连国 阅读(17) 评论(0) 编辑

2010年9月10日 #

变量定义说明了3个问题:1、空间分配大小。2、数据解析方式(如果没有这一条,直接定义字节个数就得了,不需要定义这么多基本类型)。3、auto、register等前缀说明其存储位置。

posted @ 2010-09-10 10:18 杨连国 阅读(3) 评论(0) 编辑

2008年7月29日 #

 

小点滴:之间考虑程序性能的时候,总是用TickCount来计算自己算法的耗时问题,但是它只能精确到毫秒。看CLR via C# 留意到 StopWatch 这个类,就是专门干这个事的,不错,精度还高,以后就用它了。

 

接口:

1、 规定:C#支持多接口继承,但不支持多类继承。

2、 C# 接口可以定义方法签名外,还可以定义属性、事件、索引,因为它们背后对应的都是方法。但是C#不支持静态方法(尽管CLR支持,但CLS不支持)。

3、 接口可以相互“继承”,其实这里的继承的味道已经变了,而是有点“联合约定”的味道。

4、 C#编译器要求接口的实现必须声明为public,并且CLR要求该方法应该声明为virtual,如果你没有在源代码上显示标注virtual关键字,编译器会在编译时为其添加virtualsealed关键字,这阻止子类覆写该方法;如果你显示标注了virtual在源码处,编译器是不会再添加sealed关键字的,所以这就允许了子类覆写该方法。

对于sealed接口方法,尽管子类不能覆写,但是子类可以再次继承同一接口,然后实现自己的方法,在具体应用的时候,会调用哪一个就看变量类型了。(但是要注意,应该给子类的同名方法加new 关键字,使其屏蔽父类的方法。)

5、 接口的显示实现:通常情况下,继承接口的类只要实现一个和接口一样方法签名的函数就可以了,编译器会知道两者之间的关联;另外一种情况,通过添加接口类名显示指明实现了哪个接口,这该情况下,不允许对该函数实现获取修饰符(如publicprivate),也不允许使用virtual修饰,编译器会将其编译为privat virtual sealed,也就是说既不能继承,也不能通过类的实例变量调用,只能通过接口变量的方式调用到它。书上还说其,不是一个正常的类方法,通过查看IL代码发现在函数体内多了.override [mscorlib]System.IDisposable::Dispose这么一句话,具体情况还没搞懂。

6、 泛型接口:这里有两点我感觉比较有意思,一是说如果有泛型,就尽量不要用以前的非泛型,因为非泛型为了实现通用性,参数变量往往是object类型,存在安全隐患和拆装箱子的问题。之所以还存在大量的非泛型应用是因为考虑向前兼容。二是继承泛型接口可以因为type的不同,而对同一泛型接口当作两接口。例如:

// this class implements the generic IComparable<T> interface twice

       public sealed class Number : IComparable<Int32>,IComparable<String>

       {

              // 代码省略

}

7、 泛型条件限制:不多说了,这属于泛型的问题,但是可以解决值类型装箱的问题,具体查书。

8、 解决两个接口存在同名函数(方法签名也相同)的问题,可以使用接口显示声明解决。

9、 书上说使用显示接口有很多问题,慎用!看了看确实,如果不是非使用其不解决的问题,就尽量不用。

10、关于设计基类还是设计接口的问题:基本原则是IS-A 还是Can-Do,从书上的意思好像比较倾向于说基类设计好。(具体情况具体分析吧)。

posted @ 2008-07-29 17:26 杨连国 阅读(124) 评论(1) 编辑

2008年7月3日 #

     在说明生成器模式之前,不得不说一说它和抽象工厂模式的区别:两者看起来很相似,都是应对一系列“对象”的变化,而抽象出一个公共接口。不同处在于抽象工程所要创建的一系列对象尽管是相关的,但各自是各自,他们之间的具体应用关系由客户决定;而生成器模式对应的一系列对象是在一个“大对象”下的必要组成部分,也就是说,我们关心的是要得到一个“大对象”,而抽象工厂所关心的是要得到一系列对象。另一个显著的区别是,抽象工厂模式得到一系列对象的使用“算法”由用户决定,而生成器模式是用固定的算法组织生成的一系列子对象,来生成一个所要的对象。

     回归到生成器模式上来,先说动机(也就是要用模式的原因)

     在软件系统中,有时候面临着“一个复杂对象”的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对固定。(引用李建忠视频)

     上述原因说出了变化,和不变。和抽象工厂的动机比较,我们会发现多出来了“固定算法”和“要得到的是一个复杂的大对象”。既然是这样,我们就可以再定义一个组织者类,来描述算法,我们还是用抽象工厂封装变化部分。鉴于我们要得到的并不是子对象,所以只需要对外发布一个生成大对象的方法就是了。

      因为还未实际使用过该模式,所以说对这个“用算法构成大对象”,具体应该是个什么样,还缺乏感性认识。

     再琢磨一下GoF的定义:
 
     将一个负责对象的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。

           ————GoF

     哦,忘了说缺点了,如果固定的算法不再固定,就不能应用该模式。确切的说所有的模式共有的缺点就是,当假设不变的部分发生了变化,该模式就不适用。

     探讨:将固定算法放在抽象build接口内可不可以呢?
posted @ 2008-07-03 14:36 杨连国 阅读(184) 评论(1) 编辑

     类型的成员种类:没什么好说的
 
     类型的可见性:也没什么好说了,友元程序集可以在需要时了解一下

     成员的可见性

          需要知道 assembly <--> internal  family <--> protected 对应关系

          C#要求基类和子类对同一成员量的访问权限必须是一致的,例如在基类中是protected的成员变量,继承到子类后,依然是protected。而CLR却不是这么规定的,可以将protected变为public。

     静态类

          结构不能声明为静态的,因为CLR天生要求它必须实例化。

     部分类、结构、接口

          需要说明的是partial关键字是C#提供的,CLR并对此并不知晓。不错的属性!

     组件、多态和版本控制

          组件软件编程(Component Software Programming,CSP)

      如何调用虚方法

          在CLR内部调用方法有两个指令call 和 callvirt。
          call可以用来调用静态方法、实例方法和虚方法。调用静态方法是必须指明调用方
法的类型,调用实例方法或虚方法必须指明变量引用,call指令假定变量不为null。  callvirt指令用来调用实例方法和虚方法,JIT编译器在编译调用该指令时,会验证对应的变量是否为null,则抛出异常。  为什么C#编译器不只生成call指令呢?这是因为c#编译器团度觉得应该做null检查,尽管这样会牺牲一定的效率。  那是不是对虚方法的调用都会使用callvirt指令呢?有两种例外,第一种是子类覆写虚方法时调用基类的该方法,例如base.somemethod(),这是会使用call指令,因为使用callvirt会造成循环调用。第二种情况是对结构方法是用call指令,因为值类型天生就是不能为null的。

          另外需要注意,如果一个方法之前定义为非虚方法,而已经被广泛调用,就不应该再将其改为虚方法,因为之前的调用使用的是call指令,除非重新编译,否则会产生不可预期的结构。但是如果使用C#编程倒是不用担心这一点,因为C#编译器总是在调用实例方法时使用callvirt指令

     类型和成员可见性

          Jeffrey建议定义一个类时,缺省应该具有sealed关键字,并说出了几个原因,原因就不多说了,说的也对,如果仅仅是为了封装,而不需要继承,应该是sealed。但是C#缺省并无该关键字,也就是C#定义一个类,那么该类肯定可以继承,除非显示的添加了sealed关键字。但是在C#代码内,如果不加任何前缀修饰,默认是internal

     类型版本控制:说了一下new的问题,就不啰嗦了

posted @ 2008-07-03 12:46 杨连国 阅读(53) 评论(0) 编辑

2008年6月26日 #

posted @ 2008-06-26 12:42 杨连国 阅读(487) 评论(0) 编辑

posted @ 2008-06-26 09:59 杨连国 阅读(172) 评论(0) 编辑

2008年6月20日 #

posted @ 2008-06-20 16:47 杨连国 阅读(72) 评论(0) 编辑

posted @ 2008-06-20 16:45 杨连国 阅读(97) 评论(0) 编辑