C#学习之Exception类
using System;
//Represents error that occur during application execution
//Inheritance: Object→Exception
//The following example demomstrate a catch block that is defined to handle Arithmetic
//exception errors.Thic catch block also catches DivideByZero exception errors, because
//DevideByZero exception derived from Arithmetic exception and there is no catch block
explicitly defined for DevideByZero error.
namespace 基类练习之_Exception
{
class Program
{
static void Main(string[] args)
{
int x = 0;
try
{
int y = 100 / x;
}
catch(ArithmeticException excep)
{
Console.WriteLine($"Arithmetic Exception Handler:{excep}");
}
catch(Exception ex)
{
Console.WriteLine($"Generic Exception handler:{ex}");
}
// This code example produces the following results:
// Arithmetic Exception Handler:System.DivideByZeroException: 尝试除以零。
}
}
}
Errors and exception
Run-time errors can occur for a variety of reasons.However ,not all errors should be handled as exceptions in your code.Here are some categories of errors that can occur at
run time and the appropriate ways to respond to them.
- Usage errors
A usage error represents an error in program logic that can result in anexception.
However,the error should be addressed not through exception handling but by modifying the faulty code.
For example,the override of the Object.Equals(Object) mrthod inthe following
example assume that the obj argument must always be non-null
using System;
namespace 基类练习之_Exception
{
public class Person
{
private string _name;
public string Name
{
get { return _name; }
set { _name = value; }
}
public Person(string na)
{
this._name = na;
}
public override int GetHashCode()
{
return this.Name.GetHashCode();
}
public override bool Equals(object obj)
{
// This implementation contains an error in program logic
// It assums that the obj argument is not null;
Person p = (Person)obj;
return this.Name.Equals(p.Name);
}
}
class Program
{
static void Main(string[] args)
{
try
{
Person p1 = new Person("John");
Person p2 = null;
// The following throws a NullReferenceException
Console.WriteLine(p1.Equals(p2));
}
catch(Exception ex)
{
Console.WriteLine(ex);
}
Console.ReadKey();
}
// This code example produces the following results:
// System.NullReferenceException: 未将对象引用设置到对象的实例。
}
}
The NullReferenceException exceptio that results when obj is null can be eliminated
by modifying the source code to exlplicitly test for null before calling the Object.Equals()
method.The following example conatains corrected source code that handles a null argument.
using System;
namespace 基类练习之_Exception
{
public class Person
{
private string _name;
public string Name
{
get { return _name; }
set { _name = value; }
}
public Person(string na)
{
this._name = na;
}
public override int GetHashCode()
{
return this.Name.GetHashCode();
}
public override bool Equals(object obj)
{
// This implementation contains an error in program logic
// It assums that the obj argument is not null;
Person p = (Person)obj;
if (p is null)
{
return false;
}
else
{
return this.Name.Equals(p.Name);
}
}
}
class Program
{
static void Main(string[] args)
{
try
{
Person p1 = new Person("John");
Person p2 = null;
// The following throws a NullReferenceException
Console.WriteLine(p1.Equals(p2));
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
Console.ReadKey();
}
}
}
Instead of exception handling for usage errors, you can the Debug.Assert() method to
identify usage errors in debug builds.and the Trace.Assert method to identify usage errors
in both debug and release builds.
- Program errors
A program error is a run-time error that cannot necessarily be avoided by writing bug-free code.
In some cases, a program error may reflect an expected or routine error condition. In this case, you may want to avoid using exception handling to deal with the program error and instead retry the operation. For example, if the user is expected to input a date in a particular format, you can parse the date string by calling the DateTime.TryParseExact method, which returns a Boolean value that indicates whether the parse operation succeeded, instead of using the DateTime.ParseExact method, which throws a FormatException exception if the date string cannot be converted to a DateTime value.
using System;
namespace 基类练习之_Exception
{
class Program
{
static void Main(string[] args)
{
string str = "1.1r";
double res;
bool falg = double.TryParse(str, out res);
if (falg)
{
Console.WriteLine(res);
}
else
{
Console.WriteLine("转换失败");
}
Console.ReadKey();
}
}
}
- System errors
A system failure is a run-time error that cannot be handled programmatically in a meaningful way.
The following table lists common exceptio types and the conditions under which you would throw them
Exception | Condition |
---|---|
ArgumentExeption | A non-null argument is passed to a method is invalid |
ArgumentNullException | An argument that is passed to a method is null |
ArgumentOutOfRangeException | An-argument is outside of the range of valid values |
DirectioryNotFoundException | Part of a directory is not valid |
DevideByZeroException | The denominator is an integer or Decimal division operatio is zero |
DriveNotFoundException | A drive is unavailable or does not exit |
FIleNotFoundException | A file is not exception |
TimeoutException | The time interval allotted to an operation has expired. |
NotImplementedException | A method or operation is not implemented. |
InvalidOperationException | A method call is invalid in an object’s current state. |
To define your own exception class:
The following example illustrates the use of a custom exception class. It defines a NotPrimeException exception that is thrown when a client tries to retrieve a sequence of prime numbers by specifying a starting number that is not prime. The exception defines a new property, NonPrime, that returns the non-prime number that caused the exception. Besides implementing a protected parameterless constructor and a constructor with SerializationInfo and StreamingContext parameters for serialization, the NotPrimeException class defines three additional constructors to support the NonPrime property. Each constructor calls a base class constructor in addition to preserving the value of the non-prime number. The NotPrimeException class is also marked with the SerializableAttribute attribute.
The following example makes two calls to the GetPrimesFrom method with non-prime numbers, one of which crosses application domain boundaries. In both cases, the exception is thrown and successfully handled in client code.
using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.Reflection;
namespace 基类练习之_Exception
{
[Serializable()]
public class NotPrimeException:Exception
{
private int notAPrime;
protected NotPrimeException()
:base()
{ }
public NotPrimeException(int value)
: base(String.Format($"{value} is not a prime number"))
{
notAPrime = value;
}
public NotPrimeException(int value,string message)
:base(message)
{
notAPrime = value;
}
public NotPrimeException(int value,string message,Exception innerException)
:base(message,innerException)
{
notAPrime = value;
}
public NotPrimeException(SerializationInfo info,StreamingContext context)
:base(info,context)
{
}
public int NonPrime
{
get { return notAPrime; }
}
}
public class PrimeNumberGenerator
{
private const int START = 2;
private int maxUpperBound = 10000000;
private int upperBound;
private bool[] primeTable;
private List<int> primes = new List<int>();
public PrimeNumberGenerator(int upperBound)
{
if(upperBound>maxUpperBound)
{
string message = string.Format($"{upperBound} exceeds the maxUpperBound of{maxUpperBound}");
throw new ArgumentOutOfRangeException(message);
}
this.upperBound = upperBound;
// Create array and mark 0,1 as not prime(True)
primeTable = new bool[upperBound + 1];
primeTable[0] = true;
primeTable[1] = true;
// Use Sieve of Eratosthenes to determine prime numbers.
for(int ctr=START;ctr<=(int)Math.Ceiling(Math.Sqrt(upperBound)) ;ctr++)
{
if (primeTable[ctr]) continue;
for(int multiplier=ctr;multiplier<= multiplier/ctr; multiplier++)
{
if (ctr * multiplier <= upperBound) primeTable[ctr * multiplier] = true;
}
// Populate array with prime number information
int index = START;
while(index!=-1)
{
index = Array.FindIndex(primeTable, index, (flag) => !flag);
if(index>=1)
{
primes.Add(index);
index++;
}
}
}
}
public int[] GetAllPrimes()
{
return primes.ToArray();
}
public int[] GetPrimesFrom(int prime)
{
int start = primes.FindIndex((value) => value == prime);
if(start<0)
{
throw new NotPrimeException(prime, string.Format($"{prime} is not a prime number"));
}
else
{
return primes.FindAll((value) => value >= prime).ToArray();
}
}
}
class Program
{
static void Main(string[] args)
{
int limit = 10000000;
PrimeNumberGenerator primes = new PrimeNumberGenerator(limit);
int start = 1001;
try
{
int[] values = primes.GetPrimesFrom(start);
Console.WriteLine($"There are {values.Length} prime numbers from {start} to {limit}");
}
catch(NotPrimeException ex)
{
Console.WriteLine($"{ex.NonPrime} is not prime.");
Console.WriteLine( ex);
Console.WriteLine("================");
}
AppDomain domain = AppDomain.CreateDomain("Domain2");
PrimeNumberGenerator gen=(PrimeNumberGenerator)domain.CreateInstanceAndUnwrap(typeof(Program).Assembly.FullName,"PrimeNumberGenerator",
true,BindingFlags.Default,null,new Object[] { 1000000 },null,null);
try
{
start = 100;
Console.WriteLine(gen.GetPrimesFrom(start));
}
catch(NotPrimeException ex)
{
Console.WriteLine($"{ex.NonPrime} is not a prime");
Console.WriteLine(ex);
Console.WriteLine("================");
}
Console.ReadKey();
}
}
}