Write such a simple example for two purposes:
1. ManyProgramPeople do not like to see generics. When they see symbols like "<>", they will suffer headaches. When I am employed, I can only do my best to initiate an action to eliminate "<>". In fact, this has become extend.
2. Extend significance: to give the collection class a stronger business significance. With more self-describing and interpreting actions owned by the set class, the behavior of the class will be more specific, such classes are popular in OO.
Generally, we use the list <t> set to operate. If we have a bunch of types that are class duck, we may need list <duck> to describe them. In this case, the problem does not seem so tricky. However, when we have a bunch of valuetype or string-type values to form a set, we will find the problem complicated, we can define list <string> studentnames to load the Student name to be loaded, and then use list <string> studentfathernames to load the student's father name, in some cases, for example, when return value exists, the getname () method is defined as list <string> getname (), therefore, the list <string> here is not so "strong type" (in fact, it is a strong type, but here I am referring to the situation that cannot be identified), maybe you will immediately point out my error, you will tell me that the getname () method name is not good, and the method name must follow the "Table expressiveness" Basic code, but we cannot guarantee that everyone can have a good quality and a serious attitude. Once such a name is used, we have to worry about the correctness of the results, and they will not be checked during compilation, when our customers use a program to ask you why the student's transcript is always printed with their father's exam score, should we laugh or cry?
But would it be better if we had another idea to do this?
Interface INAME
{String name {Get ;}}
Class student: INAME
Class studentparent: INAME
// Example:
List <student> students;
List <studentparent> studentparents;
Foreach (student item in students)
{
Item. Name; // deal with the students
}
Foreach (studentparent item in studentparents)
{
Item. Name; // deal with the studentparents
}
In this way, we will strengthen our type.
However, some people think that this set is not complicated and requires an INAME to specify a string field, or it does not need to be so troublesome, I just want to simply show my list <student> As list <string>, but make it different from the list <string> represented by list <studentparent> (note, here, the two lists <string> are required to have different abstract meanings and represent the same physical meanings.) What should I do?
In fact, this problem is too complicated for us to think about. We don't need to rely on the previous example to think about it, that's because we understand that what we need to do is the sentence in the last bracket, which has different abstract meanings and represents the same physical meaning. The same here can be specified by you, but it at least represents list <string>. I mean you can implement the same unexpected method, for example, assign different methods to your student and studentparent separately.
The following example describes the general process:
Using system;
Using system. Collections. Generic;
Using system. text;
Namespace ca_collectionbase
{
//
// The Name Of The Collection class shocould be defined like "branchcollection/employeecollection"
//
Public sealed class samplecollection: List <sample> {}
Public sealed class sample
{
Private string value;
Public String Value
{
Get {return this. value ;}
}
Public sample (string item)
{
This. value = item;
}
// Todo: Describe other logic code
}
Public sealed class stringcollection: List {/ * todo: Describe other logic Code */}
Public sealed class int32collection: list {/ * todo: Describe other logic Code */}
Public sealed class doublecollection: List {/ * todo: describe other logic Code */}
class Program
{< br> static void main (string [] ARGs)
{< br> // object type
samplecollection SC = new samplecollection ();
SC. add (new sample ("A");
SC. add (new sample ("B");
foreach (sample item in SC)
{< br> console. writeline (item. value);
}
// special reference type
stringcollection STRs = new stringcollection ();
STRs. add ("C");
STRs. add ("D");
foreach (string item in STRs)
{< br> console. writeline (item);
}
// simple valuetype
int32collection ints = new int32collection ();
ints. add (3);
ints. add (6);
foreach (int32 item in ints)
{< br> console. writeline (item);
}
// Simple valuetype
Doublecollection doubles = new doublecollection ();
Doubles. Add (1, 3.6 );
Doubles. Add (1, 6.3 );
Foreach (double item in Doubles)
{
Console. writeline (item );
}
}
}
}
TheseCodeIt can also be widely used in Asp.net. For example, it is very easy to bind the display data.
Implement the exampleclass class and return different types to it. These types include the defined set and general ilist interfaces.
Public class exampleclass
{
Public stringcollection getstrings ()
{
Stringcollection STRs = new stringcollection ();
STRs. Add ("string1 ");
STRs. Add ("string2 ");
STRs. Add ("string3 ");
STRs. Add ("string4 ");
Return STRs;
}
Public samplecollection getsamplesascollection ()
{< br> samplecollection SC = new samplecollection ();
SC. add (new sample ("A");
SC. add (new sample ("B");
SC. add (new sample ("C");
SC. add (new sample ("D");
return SC;
}
Public ilist <sample> getsamplesasilist ()
{
Samplecollection SC = new samplecollection ();
SC. Add (new sample ("alist "));
SC. Add (new sample ("blist "));
SC. Add (new sample ("clist "));
SC. Add (new sample ("Dlist "));
Return SC;
}
}
Namespace webappcollectionbasetest
{
Public partial class _ default: system. Web. UI. Page
{
Protected void page_load (Object sender, eventargs E)
{
Exampleclass exp = new exampleclass ();
// Step 1
This. gridview1.datasource = exp. getstrings ();
// Step 2
This. gridview1.datasource = exp. getsamplesascollection ();
// Step 3
This. gridview1.datasource = exp. getsamplesasilist ();
This. gridview1.databind ();
}
}
}
Is the above process perfect? Otherwise, when you actually implement todo in my comments and write your own business logic, you will find that we have not established a reasonable connection during this period, or those above can only be used as one class without additional business logic. Since we are a collection class, all business logic is bound to operate on our set, but according to the above code, we can only perform some extra operations outside the collection class, as to the inside of the Collection class, we cannot obtain the collection instance (handle handler), so we cannot operate on them. Next I will use an evolutionary process to improve our class.
We know that our class inherits list <sampleclass>. Can we use the keyword base to get the handle? In fact, it is not possible, because our list class does not pass the relevant handle to us. Instinctively we want to construct a class and pass the handle to us through it. Another idea is to use the original class to continuously provide cloning of old members through base. memberwiseclone () and operate on them. However, soon the next idea was that it was actually a small copy, and only after all the data was loaded can memberwiseclone return all the data, otherwise, the obtained data will be an incomplete (or empty) data set. We know that the List <t> class implements the ilist <t> interface, so we also need to simulate the list <t> to implement an ilist <t> interface, and return the list <t> handle.
//Set base class:
/// <Summary>
/// Set base class. You only need to inherit this base class to implement set encapsulation.
/// </Summary>
/// <Typeparam name = "T"> type </typeparam>
Public class collectionbase <t>: ilist <t>
{
Private ilist <t> list;
Public list <t> instance
{
Get {return (list <t>) This. List ;}
}
/// <Summary>
/// Add an item. If this item already exists, it is not added.
/// </Summary>
/// <Param name = "item"> </param>
/// <Returns> If the value is successfully added, true is returned; otherwise, false is returned. </returns>
Public bool addnorepeat (T item)
{
If (! This. List. Contains (item ))
{
This. List. Add (item );
Return true;
}
Return false;
}
Public collectionbase ()
{
List = new list <t> ();
}
# Region ilist <t> Member
Public int indexof (T item)
{
Return this. List. indexof (item );
}
Public void insert (INT index, t item)
{
This. List. insert (index, item );
}
Public void removeat (INT index)
{
This. List. removeat (INDEX );
}
Public t this [int Index]
{
Get
{
Return this. list [Index];
}
Set
{
This. list [Index] = value;
}
}
# Endregion
# Region icollection <t> Member
Public void add (T item)
{
This. List. Add (item );
}
Public void clear ()
{
This. List. Clear ();
}
Public bool contains (T item)
{
Return this. List. Contains (item );
}
Public void copyto (T [] array, int arrayindex)
{
This. List. copyto (array, arrayindex );
}
Public int count
{
Get {return this. List. Count ;}
}
Public bool isreadonly
{
Get {return this. List. isreadonly ;}
}
Public bool remove (T item)
{
Return this. List. Remove (item );
}
# Endregion
# Region ienumerable <t> Member
Public ienumerator <t> getenumerator ()
{
Return this. List. getenumerator ();
}
# Endregion
# Region ienumerable Member
Ienumerator ienumerable. getenumerator ()
{
Return (ienumerator) getenumerator ();
}
# Endregion
}
When using this class, we must follow certain game rules, that is, when we use the set itself in all sub-classes, we must use base. instance to obtain the collection handle, which is particularly important. In fact, this is very simple, just as we define a list <t> object in a class, and perform the same operations on it, but this process is concentrated.
// Example:
Public sealed class samplecollectionfromcollectionbase: collectionbase <sample>
{
// Other logic code which you will implement
Public override string tostring ()
{
String result = string. empty;
Foreach (sample s in base. instance)
{
Result = Result + S. Value + "";
}
Return result;
}
}
I have been talking about the same handle problem. Do you have to worry about the "crosstalk" problem? Because we know that a generic class instance depends on its type T, only one static copy class will be available for the same T type. However, you should note that it is only a static copy of the class, rather than a copy of the static object. Each class instance will own its own object and have its own reference in the heap. These references are non-crossover. Therefore, even if both classes inherit from a parent class, their base will be different rather than associated. However, to eliminate your concerns, I still try to provide you with visible "instructions". We will use a simple test to confirm our analysis results:
In the above example class, we add an instancetest method:
/// <Summary>
/// Only a test
/// </Summary>
Public void instancetest ()
{
Base. Add (new sample ("(New samplecollectionfromcollectionbase). Base. Add ()"));
Base. instance. Add (new sample ("(New samplecollectionfromcollectionbase). Base. instance. Add ()"));
}
In addition, write another class and use base to call its instance. To put it bluntly, write a class that is the same as samplecollectionfromcollectionbase above and make the type different. If our instance will be "crosstalk", we will see that after the code similar to the following is executed, two sets of identical results will be:
Samplecollectionfromcollectionbase SC3 = new samplecollectionfromcollectionbase ();
Samplecollectionfromcollectionbase sc3_1 = new samplecollectionfromcollectionbase ();
Samplecollection2fromcollectionbase SC4 = new samplecollection2fromcollectionbase ();
Sc3.instancetest ();
Sc3_1.instancetest ();
Sc4.instancetest ();
Foreach (sample s in sc3.instance)
{
Console. writeline (S. value );
}
Foreach (sample s in sc3_1.instance)
{
Console. writeline (S. value );
}
Foreach (sample s in sc4.instance)
{
Console. writeline (S. value );
}
The reason is simple, because no matter SC3, sc3_1, or SC4, It is referenced from the same instance ?!?!?
Of course, this is not the case. The execution result of this program is as follows:
(New samplecollectionfromcollectionbase). Base. Add ()
(New samplecollectionfromcollectionbase). Base. instance. Add ()
(New samplecollectionfromcollectionbase). Base. Add ()
(New samplecollectionfromcollectionbase). Base. instance. Add ()
(New samplecollection2fromcollectionbase). Base. Add ()
(New samplecollection2fromcollectionbase). Base. instance. Add ()
Lines 1st and 2 are SC3, lines 3rd and 4 are sc3_1, and lines 5th and 6 are sc4. (Do not write the test code like me, because my test code seems to have a large scope, and the test should try to execute a single function .)
Source codeDownload: ca_collectionbase.rar