posts - 15, comments - 29, trackbacks - 0, articles - 0

2006年4月10日

 

log4net是Apache log4j的.net版,是一套XML配置型的日志引擎,正好最近有个程序需要日志系统,为了整合方便,就决定研究一下。感谢郝伟推荐。

 log4net系统划分了7个日志等级,如设置为"WARN",则DEBUG,INFO不会被记录。如下:

1. ALL

2. DEBUG

3. INFO

4. WARN

5. ERROR

6. FATAL

7. OFF

Creating the Sample Application

 

Step 1: 下载log4net

logging.apache.org/log4net,来获取他们的最近版,在例子里我用的是incubating-log4net-1.2.9-beta.zip,期待正式版。

 

Step 2: 创建 ASP.NET Web 应用程序

    创建这个就不多说了,在log4net-1.2.0-beta8\bin\net如图。找到对应的dll,添加到引用里。有的版本没有编译好的dll,那就自己编一下吧,用.NET V1.0的那个版本转换成1.12.0的。我觉得这不是工作失误,是故意的。他们玩java玩惯了的人好多都是这样。

Configuring the Sample Application

 

Step 3: 添加Assembly信息

打开AssemblyInfo.cs文件,添加:

[assembly: log4net.Config.DOMConfigurator()]

这句话的意思是log4net系统会自动寻找配置文件Web.config从而获得并加载其中的配置信息。如果想log4net随时监视配置文件以便重新加载的话就
稍微麻烦点了要这样写:

[assembly:log4net.Config.DOMConfigurator(ConfigFile="filename",ConfigFileExtension="log4net",Watch=true)]

Step 4: 添加配置信息

要编辑Web.config文件了,真是每次看见它都有惊喜啊。找到configuration标签,configSections要紧挨着写到它下面(一点都不替别人考虑,要在有一个也跟他一样霸道怎么办?那就单写个它的日志配置文件吧!我估计APACHE他们就是这么想的)。看看例子吧:

<?xml version="1.0" encoding="utf-8" ?>

<configuration>

 
<configSections>

    
<section name="log4net" 

             type
="log4net.Config.Log4NetConfigurationSectionHandler, log4net-net-1.0" 

    
/>

 
</configSections>

 

 
<!-- This section contains the log4net configuration settings -->

 
<log4net>

    
<!-- Define some output appenders -->

    
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">

      
<layout type="log4net.Layout.PatternLayout">

        
<param name="ConversionPattern" value="%d [%t] %-5p %c [%x] &lt;%X{auth}&gt; - %m%n" />

      
</layout>

    
</appender>

    
<!-- RollingFileAppender looks after rolling over files by size or date -->

    
<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">

      
<param name="File" value="C:\\log\\RollingLogHelloWorld.log" />

      
<param name="AppendToFile" value="true" />

      
<param name="MaxSizeRollBackups" value="10" />

      
<param name="MaximumFileSize" value="1000" />

      
<param name="RollingStyle" value="Size" />

      
<param name="StaticLogFileName" value="true" />

      
<layout type="log4net.Layout.PatternLayout">

        
<param name="ConversionPattern" value="%d [%t] %-5p %-45c [%x] - %m%n" />

      
</layout>

    
</appender>

    
<!-- FileAppender appends to a log and it is manually managed or size -->

    
<appender name="FileAppender" type="log4net.Appender.FileAppender">

      
<param name="File" value="LogHelloWorld.log" />      

      
<!-- Example using environment variables in params -->

      
<!-- <param name="File" value="${TMP}\\ApplicationKit.log" /> -->

      
<param name="AppendToFile" value="true" />

      
<layout type="log4net.Layout.PatternLayout">

        
<param name="ConversionPattern" value="%d [%t] %-5p %c [%x] - %m%n" />

      
</layout>

    
</appender>

    
<!-- Setup the root category, add the appenders and set the default level -->

    
<root>

      
<level value="INFO" />

      
<appender-ref ref="ConsoleAppender" />

    
</root>

    
<!-- ApplicationKit category - the presentation UI -->

    
<logger name="WebForm1">

      
<level value="INFO" />

      
<appender-ref ref="FileAppender" />

    
</logger>

 
</log4net>

</configuration>


注意Logger节点的NAME属性设的是WebForm1,这里指的是类名。要给每一个需要添加LOG的类都添加一个这样的节点。想起了OSWORKFLOW工作流了,灵活与方便实用往往不可兼得。这里的级别是INFO,也就是说,INFO以下的不会被记录。

Running the Sample Application

 

Step 5: 添加一个 Log 

首先是添加引用

using log4net;
using log4net.Config; 

//然后是实例化如果认真研究了配置文件,那么这个声明方式就很好理解了:

private static readonly ILog log = LogManager.GetLogger("WebForm1");

 

Step 6: 使用 Log对象

到了现在,所有的配置工作都已经完成了,接下来的工作就是测试一下,把他和应用层连起来。随便加一个按钮在响应事件Button1_Click event handler.中添加


log.Info("Hello World, I am a logger");

Step 7: Run the Application

现在可以运行了,应该是个这样子的:

这样每次点击按钮,在日至文件中就会出现

2006-02-13 10:12:30,671 [1228] INFO WebForm1 [] - Hello World, I am a logger这样一条记录。

总结:

简单易用,过一阵再研究SQL日志吧,DB才素王道,呵呵。

更多信息参见http://logging.apache.org/log4net/

 

 

posted @ 2006-04-10 17:46 Phono 阅读(423) 评论(1) 编辑

Microsoft DirectX 9.0 SDK Update (Summer 2003)是微软发布的DX集成VS2003的开发包,宁为给的,但好长时间没看……辜负他了。主要是因为不好装,每次还得手动的把类库放在framework里面,而且相关的文档大多看不懂,3D基础知识薄弱。当时感觉D3D程序就是3d建模加画画,跟Photoshop也差不了多少的样子(Photoshop挺深的其实)。

前一阵子看外文书,找到了一本关于DirectX 9的,推荐一个

Introduction to 3D Game Engine Design Using DirectX 9 and C#

by Lynn Thomas Harrison               ISBN:1590590813

Apress © 2003 (422 pages)

    他们外国的IT类出版社,会把一部分比较旧的书做成chm放在网上供大家学习,出版社的网站上还有每本书相应的论坛,作者会时不时的去灌水答疑。发布勘误表,代码补丁一类的东西,东西相当好,还能学英语。而且他们的读者特别崇尚diy精神,往往有的人跟贴更新打补丁比作者还上心,大家有空去看看。

    言归正传,书中有教程我就萌生了照着做一个的卑劣想法,2003的系统启动关机有点慢,但开发决不含糊,什么都特容易装。先说说结果吧,折腾了两个多星期,败了,可耻的失败鸟。为什么呢,主要是轻敌了,这整个的编码工作量不亚于一个中小型项目,而且对文档,编码质量的要求非常高,否则就要深陷泥潭。我就被陷在里面了……这里主要说一说代码的结构吧,细节的东西太多了,想看看代码的直接跟我要吧。

象汽车一样,程序的核心也是引擎。3D游戏更是如此,引擎的好处自不必多说,要注意的是引擎不要太专化,一定要有灵活度,这样在升级的时候才不会有太多麻烦。而太过天马行云又会加大开发游戏方面的困难,必经还要考虑游戏性么,单边的设计量也不少。权衡利弊就看面向对象设计的功力了。关于人工智能呢,建议还是写在引擎外面,说实话有的时候写人工智能的跟美工建模的都不太投脾气。

嘉定我们要开发的是一个赛车类游戏,根目录结构如下:

|Root

|-----CarLib        汽车的对象

|-----GameEngine  游戏引擎

|-----Resources     资源,音频,视频,贴图之类的

|-----SampleGame  游戏主程序

|-----GameAI       传说中的人工智能

下面来详细地介绍一下这些目录底下的东西

 

 

|-----CarLib       

  |-----Car.cs 车的类

|-----Euler.cs 以欧拉变换为核心的计算类,欧拉很神奇,是个牛人,一翻书才知道他创设了许多数学符号,比如π(1736年),i(1777年),e(1748年),sin和cos(1748年),tg(1753年),△x(1755年),Σ(1755年),f(x)(1734年)等。他本人品格高尚,意志坚定,失明了17年还坚持研究,值得敬佩。

|-----Vector.cs 向量类,framework里的向量类不太够用了,要丰富,并把象限的操作尽量集中到这里通过特定接口完成。

|-----Wheel.cs 也是属于向量力学命名空间的,这里能说得可多了,悬挂,摩擦,角度,扭矩,重量,输出转速,都可以从这体现出来。这么设计主要是考虑运算方便了。

|-----LFI.cs 线性功能模块的类,把曲线变成可操作的数据,更新因斜坡,阻碍造成的数据变化。

 

 

|-----Resources 推荐写个xml把所有的素材整理在案,用起来也方便。

|-----音频文件 推荐使用wma,比mp3效率好像高一点,也可能是心理因素。

|-----图像文件 小图标,splash什么的用jpg就可以了。贴图素材推荐使用TGA格式(TGA格式(Tagged Graphics)是由美国Truevision公司为其显示卡开发的一种图像文件格式,文件后缀为“.tga”,已被国际上的图形、图像工业所接受。TGA的结构比较简单,属于一种图形、图像数据的通用格式,在多媒体领域有很大影响,是计算机生成图像向电视转换的一种首选格式。TGA图像格式最大的特点是可以做出不规则形状的图形、图像文件,一般图形、图像文件都为四方形,若需要有圆形、菱形甚至是缕空的图像文件时,TGA可就派上用场了! TGA格式支持压缩,使用不失真的压缩算法。知道为什么用它了吧)同时DDS格式也是很常用的,可以用photoshop直接输出。DDS是DirectDraw Surface的缩写,它是DirectX纹理压缩(DirectX Texture Compression,简称DXTC)的产物。DXTC减少了纹理内存消耗的50%甚至更多。NVidia全力支持的。

 

|----- GameAI     深不见底,大概其说说吧,我那么一说,大伙那么一听。

|----- Thinker.cs Thinker类由很多的ArrayList组成,这些List还会时时的排序更新,每一个动作会触发一个thinker线程,循环处理传感器触发的事件列表,需要手动回收,把空的thinker线程sleep掉。而动作列表则忠实地记录每一个事件,以供Thinker参考处理。

|----- Expressio.cs 可不是正则表达式,是语法表达,也就是说话和听话,但这些行动都要过过“脑子”——thinker类。

|----- Fact.cs 通过XML记录事件,并提供逻辑所需的各种枚举和常量及各种真假判断方法。

|----- Logic.cs 这个我就不懂了,那会儿没选人工智能,晓佳,酷弟可能会,回头问问他们去。最匪夷所思的就是第一事实,第二事实。可能是作判断时的权不一样吧。剩下的就是一些评估逻辑,学名叫博弈。

|-----Transitioner.cs 完成状态转换间的过渡,交接工作。容易被忽视,但确实是很有重要的一个类。

|----- GameEngine 也就是最主要的类了,描述了游戏3d引擎的构成,乱七八糟的太多了,就简单说说吧。

|-----BillBoard.cs 我理解就是咱们所说的场景,因为3d程序中的计算要在矩阵中进行,但最后还是会由镜头投影成2d图像,因此就有了这个叫法,Matrix,Objects,Texture,场景本身是一个3d对象,就像一个摄影棚。

|-----Camera.cs 摄像机本身的属性和方法很多,3dMAX里面的差不多,这里值得一提的是调整对象和获取距离这两个方法,因为添加到镜头中的对象,不会只有一个,要根据其重要程度和对象形状大小来调整焦点,这些方法不能有对象本身持有。获取距离也是这个道理。

|-----各种材质的类  引擎里的材质值得是材质的抽象类,贴图什么的不归他管,只是留出了引入贴图的方法,定义木石材质的摩擦度,衣服的光鲜程度,和灯光人物的一些基本属性和方法。

|-----D3DApp.cs  是所有3d程序的基类,他继承自普通的winform,并把他封装成通用的3d图像应用程序,如计时,加载显示设备和渲染设备,设置基本的菜单和相应的对话框及处理,还要定义异常处理系统(这个累很辛苦啊)。另外以前看到有的书说c#不农用指针,这个说法是不对的,在设计图像处理的时候,指针的速度是不容置疑的,但使用指针的程序会运行于“不安全状态”在“调试”里面可以设置,权衡利弊吧。

|-----GameMath.cs  用来完成游戏中的计算任务,主要的计算源自合并对象,和调整对象间距。

|----- Object3D.cs  游戏中所有3d对象的基类了,除了作为向量的xyz以外,还要定义空间位置,老外叫north,west,height,也就是坐标的三个轴了,想想挺贴切的。还有三个是Roll,Pitch,Heading,这三个人地加入就可以完全定义一个对象的空间状态了。用弧度计算,用角度显示。

|-----SkyFace.cs  这个好像在vrml里提过,具体的忘记鸟。很无聊的一个类,但有点总揽全局那意思。但主要还是用来承载和渲染天空和环境的一个类。使用VertexBuffer后效率似乎会更高。

|----- Quad.cs  可不是四芯电缆,呵呵,是东南西北四向的意思。用来构建对象树,即把三维的对象加入到管理体系中。以便Matrix管理,呵呵,太拽了点。

|----- Music.cs  其实就是丰富一下Microsoft.DirectX.AudioVideoPlayback.Audio类,但这个类被保护起来了,不让继承了。不过也好,封装一下总是有好处的。可以把循环播放什么写在里面。

Enjoy!

posted @ 2006-04-10 17:29 Phono 阅读(1743) 评论(13) 编辑

    一个被终止的对象常驻内存重而不被使用的话,会占用很多系统资源,于是.net的垃圾回收器就会将它放在中止化队列中,一旦时机成熟,该对象就会被唤醒,并调用他的finalize方法,来彻底的终结他,但是利用这一机制,就可以将耗费资源的巨型类放入到一个对象池中,在程序的整个生存期内重复的使用他(结束的标志是clr认为在进程中不存在任何该应用程序的根)。我们称这些巨型类为Expensive对象,下面来讨论一下管理Expensive对象的对象池的结构。

Class Expensive{

Static Stack pool 
= new Stack();



Public 
static Expensive GetObjectFromPool(){

Retun (Expensive) pool.Pop();

}




Public 
static void ShutdownThePool(){

Pool 
= null;

}


Public Expensive()
{

//先构造对象

Pool.push(
this);

}


Finalize ()
{

If(pool
!=null){

GC.RegisterForFinally(
this;)//先把他叫醒挨宰

Pool.push(
this);//将“清醒的”对象加入到对象池中,让他起死回生

}


}


}




Class app
{

Static 
void main(){

New expensive();

……

Expensive e 
= Expensiv. GetObjectFromPool();

//下面就可以使用e了

Expensive.shutdownThepool();
//关闭应用程序前,先关闭对象池,否则会在内存中留下“孔洞”,因为Finalize已经被重写了

}


}

posted @ 2006-04-10 17:14 Phono 阅读(166) 评论(0) 编辑