posts - 3,  comments - 0,  trackbacks - 0
公告
  2006年1月12日
posted @ 2006-01-12 08:58 YuXuanT 阅读(133) 评论(0) 编辑
  2006年1月4日

在接触到一个系统中(Delphi实现)自定义了很多数据类,以及操纵数据的集合类(List)。

各个集合类有相同的属性(例Item、Count),相同的方法(例Add、Remove、Copy),只是方法所处理的数据是某一种特定的数据类,另外在某种方法里要调用所处理的数据类的方法(例SaveToStream)。


看上面AccompanyDataList处理的是AccompanyData,FormDataList处理的是FormData。但他们的方法是如此的相似。

总之有一种数据类,就有一种集合类。

在把此系统向.NET环境移植时,把各种数据类用C#改写了。但在改写集合类时,考虑到要重复很多相似的代码,而各集合类的属性名称、方法名称相同,要实现的功能相同,即把数据类的某个实例加入到集合类中,或者从集合类中删除某个实例,所以想象设计一个通用的集合类,根据集合类实例化时,类的使用者传递的参数类型,来决定这个集合类是哪种数据的集合。

这次改变,就是要实现通用的集合类,目的是为了减轻工作量,避免重复很多相似的代码。但不知此设计是否合理?为什么原系统没有合并集合类呢?

不管这些了。下面着力实现通用集合类。关键是获取集合类实例化时传递的参数的类型,再根据这个类型,创建此类型的实例,加入到集合中,为了接收任何类型,使用一个object型的变量,在需要返回某种数据类型时也只能用object代替。这样集合类的使用者必须使用强制类型转换。

public class DataList
    
{
        
private object DataType;
        
protected ArrayList List;

        
public DataList(object dataType)
        
{
            DataType
=Activator.CreateInstance(dataType.GetType());
            List
=new ArrayList();
        }


        
public virtual int Add()
        
{
            
return List.Add(Activator.CreateInstance((DataType.GetType())));
        }


        
public virtual int Add(object dataType)
        
{
            
if (dataType.GetType()==DataType.GetType())
            
{
                
return List.Add(dataType);
            }
    
            
else
            
{
                
return -1;
            }

        }

        
        
public virtual object AddItem()
        
{
            
int index=Add();
            
return List[index];
        }

}

集合类的使用:

DataList aFormList=new DataList(new FormData());
FormData aForm
=(FormData)aFormList.AddItem();

DataList aFieldList=new DataList(new FieldData());
FieldData aField
=(FieldData)aFieldList.AddItem();

基本上是实现了要求。
主要一点不同就是原来类的设计者要在集合类的内部实现类型转换,而现在是类的使用者要在集合类的外部实现类型转换。

在具体集合类调用所处理的具体数据类的方法时,可能是这样子:

public virtual void SaveToStream(Stream stream,bool isShallow)
        
{
            
for(int i=0;i<Count-1;i++)
            
{
                ((RecordData)List[i]).SaveToStream(stream,isShallow);
            }

        }

也是在集合类内部实现了类型转换(RecordData)。但在通用集合类怎么办呢?想了一下,使用运行时多态。即把通用集合类要调用的具体数据类的方法,用抽象基类包装,各个具体数据类继承自这个基类。然后在集合类中调用基类相应方法,这样根据运行时多态,达到调用具体类(子类)的方法的目的。
基类:

public abstract class DataBase
    
{
        
public abstract void Assign(object item,bool isShallow);
        
public abstract void SaveToStream(Stream stream,bool isShallow);
        
public abstract void SaveToFile(string fileName,bool isShallow);
        
public abstract void LoadFromStream(Stream stream,bool isShallow);
        
public abstract void LoadFromFile(string fileName,bool isShallow);
    }

子类:

public class RecordData:DataBase
    
{
        
public override void SaveToStream(Stream stream,bool isShallow)
        
{
            
//
        }

        
public override void SaveToFile(string fileName,bool isShallow)
        
{
            
//
        }

        
public override void LoadFromStream(Stream stream,bool isShallow)
        
{
            
//
        }

        
public override void LoadFromFile(string fileName,bool isShallow)
        
{
            
//
        }



        
public override void Assign(object item,bool isShallow)
        
{
            
if ((item as RecordData)!=null)
            
{
                formID            
=((RecordData)item).FormID;
                
            }

        }


    }

为了实现通用,涉及到具体类的方法的参数,依然用object代替。而在方法的内部,要用类型转换。

通用集合类中对应方法的实现,即用基类转换类型:

public virtual void SaveToStream(Stream stream,bool isShallow)
        
{
            
for(int i=0;i<Count;i++)
            
{
                ((DataBase)List[i]).SaveToStream(stream,isShallow);
            }

        }


总之,费了很大的牛劲,实现了通用集合类。但是是按照原来的思想,设计成一个具体数据类对应一个具体集合类呢,还是设计成不同的具体数据类,对应相同的一个通用集合类呢?是否有什么设计标准呢?就不知道了!


 

posted @ 2006-01-04 16:13 YuXuanT 阅读(447) 评论(0) 编辑
  2005年9月29日

[原址]http://www.gekko-software.nl/DotNet/Art01.htm

An (incomplete) comparison of Delphi and C# features

Delphi and C# are both rich and powerful object oriented programming languages. As a reminder a short recapitulation of what that stands for : Objects are a grouping of data and methods (functions) working on that data. Objects are based on classes. A class is a declaration of the data and the code of the methods. A class will create objects using constructor methods.

An real object oriented language supports encapsulation, inheritance and polymorphism. Encapsulation hides everything inside an object except what you explicitly want to show to the outer world. Inheritance lets you re-use a class to create a  derived class with added functionality. Polymorphism lets you re-use a class and alter its exposed behavior.

Delphi has a great support for object orientation but you can write a plain Pascal program without using any object at all. In C# everything is an object, including the application itself. Running a C# program means creating an object and executing the object's main method. C# does not know how to handle any "loose" procedures or constants either, everything has to belong to a class.

The Delphi-VCL couple shares a lot with the C#-.NET couple which makes a comparison on items possible. This list is by far incomplete, it is just a road-sketch from a Delphi perspective:

Both have

In a hierarchy of objects every derived class class can introduce a new constructor. Which constructors actually get executed differs between the two languages, in Delphi each constructor has to be called explicitly. Besides the constructors Delphi's tObject base class has a method AfterConstruction, which will be executed after the last constructor has finished. So there are many places where a Delphi object can be initialized.

In C# the constructor of the ultimate base class System.object always will be executed first, the execution of a constructor of any other base class has to be explicitly asked for in the declaration of the constructor as ": base." There is no AfterConstruction in C#, everything has to be (and can be) done in the constructors themselves.

Type
    tMyClass = class(tObject)
    constructor createEx;
end;

tMyClass2 = class(tMyClass)
    constructor createEx; override;
    procedure AfterConstruction override;
end;

constructor tMyClass.CreateEx;
    begin
    ...
    end;

constructor tMyClass2.CreateEx;
    begin
    inherited CreateEx;
    ...
    end;

procedure tMyClass2.AfterConstruction
    begin
    inherited;
    // Initialization
    end;

public class MyClass
{
    public MyClass(int anInt)
        {...}
}

public class MyClass2 : MyClass
{
    public MyClass2(int anInt) : base(anInt)
        {
         ...
        // Initialization
        }
}

      

        

To the user of the object a property behaves like any other field. In the actual implementation reading or writing the property will be done by an internal method. In this method the value can be checked or calculated. By only implementing only the getter or only the setter the property will be read or write only. In this example both the getter and the setter guard the property against a value less then 0.

type MyClass = class(tObject)
private
    fMyProp : integer;
    function GetMyProp: integer;
    procedure SetMyProp(const Value: integer);
public
    property MyProp : integer read GetMyProp write SetMyProp;
end;

function MyClass.GetMyProp: integer;
    begin
    result:= max(fMyProp,0);
    end;

procedure MyClass.SetMyProp(const Value: integer);
    begin
    if Value >= 0 then
       fMyProp:= Value;
    end;

In C# the value passed in the property setter is named value.

public class MyClass
{
    private int myProp = 0;
   
public  int MyProp
       
{
       
get { return Math.Max(myProp, 0); }
       
set { if (value > 0)
                 
myProp = value; }
        }
}

 

procedure MyEventHandler(sender : object)
begin
    ShowMessage('You clicked the button');
end;

MyButton.OnClick:= MyEventHandler;

private void MyClick1(object sender, System.EventArgs e)
{
   
MessageBox.Show("You clicked the button");
}

private void MyClick2(object sender, System.EventArgs e)
{
   
MessageBox.Show("And I'll tell you twice");
}

MyButton.Click += new System.EventHandler(MyClick1);
MyButton.Click += new System.EventHandler(MyClick2);

 

 

C# - .NET has

As an extra option C# offers custom type conversions. This offers the possibility to explicitly program what will happen to (the members of) an object when it is typecast from one type to another. In Inside C# Tom Archer gives a very clear example. He takes two temperature types, Celsius and Fahrenheit. Typecasting a Celsius variable to a Fahrenheit variable will handle the conversion of the value on the fly.

Celcius c = new Celsius(0F);
Fahrenheit f = (Fahrenheit)c;

The variable f will now hold a value of 32 (degrees Fahrenheit)

 

 

As all variables in .NET are objects, performing operations on them boils down to making methods calls. Methods can be overloaded, in .NET this is also possible for many of the basic operators like +, -, <, etc. This can be very useful in your own classes. Let's take  an invoice class in which the + operator is overloaded

public class Invoice
{
    public double Total;
    public static Invoice operator+ (Invoice invoice1, Invoice invoice2)
    {
        Invoice NewInvoice = new Invoice();
        NewInvoice.Total = invoice1.Total + invoice2.Total;
        return NewInvoice;
    }
}

The method operator+ takes two Invoice objects as a parameter, constructs a new invoice and sets it's properties. After this declaration you can code:

Invoice anInvoice = new Invoice();
Invoice anotherInvoice = new Invoice();
anInvoice.Total = 1200;
anotherInvoice.Total = 2500;
textBox1.Text = "Total amount is " + (anInvoice + anotherInvoice).Total.ToString();

The + operator applied on two Invoice object will result in another Invoice object with a total amount of 3700. The + operator applied on objects of any other type will result in a default addition, the + operator is overloaded for the Invoice class.

 

Where are we ?

C# and .NET can very well be compared to Delphi and the VCL. The fact that the first is a clean start based on yesterdays lessons and today's needs make it a very tempting development environment. Working with C# in Visual Studio.net has been a very pleasing experience to me, it shows a stable and powerful implementation of all ideas and will keep the pleasure in programming for quite some time.

Gekko Software home page

 

 

posted @ 2005-09-29 09:02 YuXuanT 阅读(212) 评论(0) 编辑
仅列出标题