16. What is the difference between classes and structures?
A:
Class:
The class is allocated by the reference type on the stack. The class instance only copies the reference and points to the memory allocated by the same actual object.
Class constructor and destructor
Class can be inherited and inherited
Structure:
Structure is the value type allocated on the stack (although the access speed of the stack is faster than that of the stack, but the stack resources are limited), The Structure assignment will generate a new object.
The structure has no constructor, but can be added. No destructor for the Structure
The structure cannot inherit from another structure or be inherited, but can inherit from the interface like the class.
Example:
Based on the above comparison, we can conclude that some lightweight objects are best structured, but classes are best used for large data volumes or complex processing logic objects.
For example, Geoemtry (an introduction to GIS, which is defined in the OGC standard) is best to use classes, while it is best for members of the ry midpoint to use structures.
Using System;
Using System. Collections. Generic;
Using System. Text;
Namespace Example16
{
Interface IPoint
{
Double X
{
Get;
Set;
}
Double Y
{
Get;
Set;
}
Double Z
{
Get;
Set;
}
}
// The structure can also be inherited from the interface
Struct Point: IPoint
{
Private double x, y, z;
// The constructor can be added to the structure.
Public Point (double X, double Y, double Z)
{
This. x = X;
This. y = Y;
This. z = Z;
}
Public double X
{
Get {return x ;}
Set {x = value ;}
}
Public double Y
{
Get {return x ;}
Set {x = value ;}
}
Public double Z
{
Get {return x ;}
Set {x = value ;}
}
}
// This simplifies the design of Point Geometry. The actual product also contains complex operations such as Project (Coordinate Transformation ).
Class PointGeometry
{
Private Point value;
Public PointGeometry (double X, double Y, double Z)
{
Value = new Point (X, Y, Z );
}
Public PointGeometry (Point value)
{
// Structure assignment will allocate new memory
This. value = value;
}
Public double X
{
Get {return value. X ;}
Set {this. value. X = value ;}
}
Public double Y
{
Get {return value. Y ;}
Set {this. value. Y = value ;}
}
Public double Z
{
Get {return value. Z ;}
Set {this. value. Z = value ;}
}
Public static PointGeometry operator + (PointGeometry Left, PointGeometry riry)
{
Return new PointGeometry (Left. X + riw.x, Left. Y + riw.y, Left. Z + riw.z );
}
Public override string ToString ()
{
Return string. Format ("X: {0}, Y: {1}, Z: {2}", value. X, value. Y, value. Z );
}
}
Class Program
{
Static void Main (string [] args)
{
Point tmpPoint = new Point (1, 2, 3 );
PointGeometry tmpPG1 = new PointGeometry (tmpPoint );
PointGeometry tmpPG2 = new PointGeometry (tmpPoint );
TmpPG2.X = 4;
TmpPG2.Y = 5;
TmpPG2.Z = 6;
// Because the structure is a value type, the coordinates of tmpPG1 and tmpPG2 are not the same
Console. WriteLine (tmpPG1 );
Console. WriteLine (tmpPG2 );
// Because the class is of reference type, after the tmpPG1 coordinate is modified, tmpPG3 is affected.
PointGeometry tmpPG3 = tmpPG1;
TmpPG1.X = 7;
TmpPG1.Y = 8;
TmpPG1.Z = 9;
Console. WriteLine (tmpPG1 );
Console. WriteLine (tmpPG3 );
Console. ReadLine ();
}
}
}
Result:
X: 1, Y: 2, Z: 3
X: 4, Y: 5, Z: 6
X: 7, Y: 8, Z: 9
X: 7, Y: 8, Z: 9
17. What problems does interface multi-inheritance bring about?
A:
The interfaces in C # are different from the classes. You can use multi-inheritance, that is, a sub-interface can have multiple parent interfaces. However, if the two parent members have members with the same name, this creates ambiguity (this is one of the reasons why the class in C # cancels multi-inheritance ), in this case, it is best to use an explicit statement for implementation.
Example:
Using System;
Using System. Collections. Generic;
Using System. Text;
Namespace Example17
{
Class Program
{
// A complete interface declaration example
Interface IExample
{
// Attributes
String P
{
Get;
Set;
}
// Method
String F (int Value );
// Event
Event EventHandler E;
// Index indicator
String this [int Index]
{
Get;
Set;
}
}
Interface IA
{
Int Count {get; set ;}
}
Interface IB
{
Int Count ();
}
// Multi-inheritance of the IC interface from IA and IB
Interface IC: IA, IB
{
}
Class C: IC
{
Private int count = 100;
// Explicitly declare and implement the Count attribute in the IA Interface
Int IA. Count
{
Get {return 100 ;}
Set {count = value ;}
}
// Explicitly declare and implement the Count method in the IB Interface
Int IB. Count ()
{
Return count * count;
}
}
Static void Main (string [] args)
{
C tmpObj = new C ();
// Explicit conversion is also required during the call.
Console. WriteLine ("Count property: {0}", (IA) tmpObj). Count );
Console. WriteLine ("Count function: {0}", (IB) tmpObj). Count ());
Console. ReadLine ();
}
}
}
Result:
Count property: 100
Count function: 10000
18. What is the difference between an abstract class and an interface?
A:
Abstract class can contain function definitions and implementations. interfaces can only contain function definitions.
Abstract classes are abstract concepts from a series of related objects, so they reflect the internal commonalities of things. interfaces are a functional Convention defined to satisfy external calls, therefore, it reflects the external characteristics of things.
Analyzes objects and extracts internal commonalities to form abstract classes to indicate the object nature, that is, "What"
Interfaces are preferred when external calls or functions need to be expanded
19. What is an alias indicator?
A:
Using alias indicators, we can create an alias for a type.
It is mainly used to resolve conflicts between two namespaces with the same name type or avoid redundant namespaces.
The alias indicator is defined in the outermost layer of all namespaces and has the scope of the entire unit file. If it is defined in a namespace, it takes effect only in the directly affiliated namespace.
Example:
Class1.cs:
Using System;
Using System. Collections. Generic;
Using System. Text;
Namespace com. nblogs. reonlyrun. CSharp25QExample. Example19.Lib01
{
Class Class1
{
Public override string ToString ()
{
Return "com. nblogs. reonlyrun. CSharp25QExample. Example19.Lib01's Class1 ";
}
}
}
Class2.cs:
Using System;
Using System. Collections. Generic;
Using System. Text;
Namespace com. nblogs. reonlyrun. CSharp25QExample. Example19.Lib02
{
Class Class1
{
Public override string ToString ()
{
Return "com. nblogs. reonlyrun. CSharp25QExample. Example19.Lib02's Class1 ";
}
}
}
Main Unit (Program. cs ):
Using System;
Using System. Collections. Generic;
Using System. Text;
// Use the alias indicator to resolve conflicts with the same name Type
// Defines the outermost layer of all namespaces and the scope is the entire unit file.
Using Lib01Class1 = com. nblogs. reonlyrun. CSharp25QExample. Example19.Lib01. Class1;
Using Lib02Class2 = com. nblogs. reonlyrun. CSharp25QExample. Example19.Lib02. Class1;
Namespace Example19
{
Namespace Test1
{
// Test1Class1 is defined in the Test1 namespace, And the scope is only within Test1
Using Test1Class1 = com. nblogs. reonlyrun. CSharp25QExample. Example19.Lib01. Class1;
Class Class1
{
// Lib01Class1 and Lib02Class2 can be used normally here
Lib01Class1 tmpObj1 = new Lib01Class1 ();
Lib02Class2 tmpObj2 = new Lib02Class2 ();
// TestClass1 can be used normally here
Test1Class1 tmpObj3 = new Test1Class1 ();
}
}
Namespace Test2
{
Using Test1Class2 = com. nblogs. reonlyrun. CSharp25QExample. Example19.Lib01. Class1;
Class Program
{
Static void Main (string [] args)
{
// Lib01Class1 and Lib02Class2 can be used normally here
Lib01Class1 tmpObj1 = new Lib01Class1 ();
Lib02Class2 tmpObj2 = new Lib02Class2 ();
// Note that TestClass1 cannot be used normally.
// Because the alias defined in the Test1 namespace cannot be used in the Test2 namespace
// Test1Class1 tmpObj3 = new Test1Class1 ();
// TestClass2 can be used normally here
Test1Class2 tmpObj3 = new Test1Class2 ();
Console. WriteLine (tmpObj1 );
Console. WriteLine (tmpObj2 );
Console. WriteLine (tmpObj3 );
Console. ReadLine ();
}
}
}
}
Result:
Com. nblogs. reonlyrun. CSharp25QExample. Example19.Lib01's Class1
Com. nblogs. reonlyrun. CSharp25QExample. Example19.Lib02's Class1
Com. nblogs. reonlyrun. CSharp25QExample. Example19.Lib01's Class1
20. How to manually release resources?
A:
The. NET platform provides GC (Garbage Collection) for Memory Management, which is responsible for automatically releasing managed resources and memory recovery. However, we need to manually release resources in the following two cases: 1. Because it cannot release unmanaged resources, therefore, we must provide our own methods to release the unmanaged resources allocated to the object. For example, you use a COM object in the object implementation code; 2. When your class is running, it will produce a large number of instances (such as Geometry in GIS). You must manually release these resources to improve the program running efficiency.
The ideal solution is to explicitly provide an interface to the client call end to manually release the object. The System namespace has an IDisposable interface, which is very suitable, it saves us the trouble to declare another interface.
Example:
Using System;
Using System. Collections. Generic;
Using System. Text;
Namespace Example20
{
Class Program
{
Class Class1: IDisposable
{
// Destructor. After compilation, it becomes protected void Finalize (). GC will call this method before reclaiming the object.
~ Class1 ()
{
Dispose (false );
}
// By implementing this interface, the customer can release objects explicitly without waiting for GC to release resources. It is said that this will reduce the efficiency.
Void IDisposable. Dispose ()
{
Dispose (true );
}
// Design the release of unmanaged resources into a virtual function to provide the ability to release the base class resources in the inheritance class
Protected virtual void ReleaseUnmanageResources ()
{
// Do something...
}
// Private functions are used to release unmanaged resources.
Private void Dispose (bool disposing)
{
ReleaseUnmanageResources ();
// If the value is true, it indicates that the release function is explicitly called by the customer. You must notify GC not to call the Finalize method of the object.
// If it is false, the GC must have called the Finalize method of the object, so there is no need to tell the GC that you should not call my Finalize method.
If (disposing)
{
GC. SuppressFinalize (this );
}
}
}
Static void Main (string [] args)
{
// TmpObj1 does not manually release the resource, so wait for the GC to release it slowly.
Class1 tmpObj1 = new Class1 ();
// TmpObj2 calls the Dispose method, which is more efficient than waiting for GC to release it.
// I personally think it is because I want to view the metadata of objects one by one to confirm whether the Dispose method is implemented.
// Of course, the most important thing is that we can determine the release time to save memory and optimize the program running efficiency.
Class1 tmpObj2 = new Class1 ();
(IDisposable) tmpObj2). Dispose ();
}
}
}