Python異常處理詳解

来源:https://www.cnblogs.com/f-ck-need-u/archive/2018/12/13/10116936.html
-Advertisement-
Play Games

入門示例 異常處理:try/except 對於索引查找的操作,在索引越界搜索的時候會報錯。例如: 所報的錯誤是IndexError。如果將索引查找放在一個函數里: 那麼調用函數的時候,如果裡面的索引越界了,異常將彙報到函數調用者。 可以使用try/except來捕獲異常。作為入門示例,下麵是簡單版的 ...


在shell腳本中,常用if來判斷程式的某個部分是否可能會出錯,併在if的分支中做出對應的處理,從而讓程式更具健壯性。if判斷是異常處理的一種方式,所有語言都通用。對於特性完整的編程語言來說,都有專門的異常處理機制,有些語言用起來可能會很複雜,要求一堆堆的,有些語言則非常簡潔,用起來非常通暢。

入門示例

異常處理:try/except

對於索引查找的操作,在索引越界搜索的時候會報錯。例如:

>>> s="long"
>>> s[4]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: string index out of range

所報的錯誤是IndexError。如果將索引查找放在一個函數里:

>>> def fetcher(obj,index):
...     return obj[index]

那麼調用函數的時候,如果裡面的索引越界了,異常將彙報到函數調用者。

>>> fetcher(s,3)
'g'

>>> fetcher(s,4)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in fetcher
IndexError: string index out of range

可以使用try/except來捕獲異常。作為入門示例,下麵是簡單版的格式:

try:
    statement1
    ...
    statementN
except <ERRORTYPE>:
    ...statementS...

例如,try中是要監視正確執行與否的語句,ERRORTYPE是要監視的錯誤類型。

  • 只要try中的任何一條語句拋出了錯誤,try中該異常語句後面的語句都不會再執行;
  • 如果拋出的錯誤正好是except所監視的錯誤類型,就會執行statementS部分的語句;
  • 如果異常正好被except捕獲(匹配)到了,程式在執行完statementS後會繼續執行下去,如果沒有捕獲到,程式將終止;
    • 換句話說,except捕獲到錯誤後,相當於處理了這個錯誤,程式不會因為已經被處理過的錯誤而停止

例如捕獲上面的函數調用:

def fetcher(obj, index):
    return obj[index]

s = "long"
try:
    print(fetcher(s, 3) * 4)
    print(fetcher(s, 4) * 4)
except IndexError:
    print("something wrong")

print("after Exception, Continue")

輸出結果:

gggg
something wrong
after Exception, Continue

因為上面的fetcher(s, 4)會拋出異常,且正好匹配except監視的異常類型,所以輸出something wrong,異常被處理之後,程式繼續執行,即try/except後面的print()。

異常處理:try/finally

finally是try之後一定會執行的語句段落。可以結合except一起使用。

try:
    statement1
    ...
    statementN
finally:
    ...statementF...
try:
    statement1
    ...
    statementN
except <ERRORTYPE>:
    ...statementS...
finally:
    ...statementF...

不論try中的語句是否出現異常,不論except是否捕獲到對應的異常,finally都會執行:

  • 如果異常沒有被捕獲,則在執行finally之後程式退出
  • 如果異常被except捕獲,則執行完except的語句之後執行finally的語句,然後程式繼續運行下去

一般來說,finally中都會用來做程式善後清理工作。

例如:

def fetcher(obj, index):
    return obj[index]

s = "long"
try:
    print(fetcher(s, 3) * 4)
    print(fetcher(s, 4) * 4)
except IndexError:
    print("something wrong")
finally:
    print("in finally")

print("after Exception, Continue")

輸出:

gggg
something wrong
in finally
after Exception, Continue

如果把except那段代碼刪掉,得到的結果將是:

gggg
in finally      # 輸出了finally的內容
Traceback (most recent call last):
  File "g:/pycode/list.py", line 8, in <module>
    print(fetcher(s, 4) * 4)
  File "g:/pycode/list.py", line 2, in fetcher
    return obj[index]
IndexError: string index out of range

產生異常:raise和assert

使用raise或assert可以主動生成異常情況。其中raise可以直接拋出某個異常,assert需要通過布爾值來判斷,然後再拋出給定的錯誤。

例如,在函數里做個沒什麼用的的判斷,用來演示raise:

def fetcher(obj, index):
    if index >= len(obj):
        raise IndexError
    return obj[index]

這和直接索引越界是以一樣的。上面raise拋出的異常IndexError是一個內置異常,可以直接引用這些內置異常。稍後會演示如何自定義自己的異常。

拋出異常後,就可以按照前面介紹的try來處理異常。

assert是一種斷言,在電腦語言中表示:如果斷言條件為真就跳過,如果為假就拋出異常信息。它可以自定義異常信息。

例如:

def fetcher(obj, index):
    assert index < len(obj),  "one exception"
    return obj[index]

很多時候會直接在assert中使用False、True的布爾值進行程式的調試。

assert True, "assert not hit"
assert False, "assert hit"

自定義異常

python中的異常是通過類來定義的,而且所有的異常類都繼承自Exception類,而Exception又繼承自BaseException(這個類不能直接作為其它異常類的父類)。所以自定義異常的時候,也要繼承Exception,當然,繼承某個中間異常類也可以。

例如,定義索引越界的異常類,註意這個類中直接pass,但因為繼承了Exception,它仍然會有異常信息。

class MyIndexError(Exception):
    pass

例如,判斷字母是否是大寫,如果是,就拋異常:

def fetcher(obj,index):
    if index >= len(obj):
        raise MyIndexError
    return obj[index]

測試一下:

s = "long"

print(fetcher(s, 3) * 4)
print(fetcher(s, 4) * 4)

結果:

gggg
Traceback (most recent call last):
  File "g:/pycode/list.py", line 12, in <module>
    print(fetcher(s, 4) * 4)
  File "g:/pycode/list.py", line 6, in fetcher
    raise MyIndexError
__main__.MyIndexError

需要註意,因為異常類都繼承字Exception,except監視Exception異常的時候,也會匹配其它的異常。更標準地說,監視異常父類,也會捕獲到這個類的子類異常

如何看拋出的異常

看異常信息是最基本的能力。例如,下麵的這段代碼會報除0錯誤:

def a(x, y):
    return x/y

def b(x):
    print(a(x, 0))

b(1)

執行時,報錯信息如下:

Traceback (most recent call last):
  File "g:/pycode/list.py", line 7, in <module>
    b(1)
  File "g:/pycode/list.py", line 5, in b
    print(a(x, 0))
  File "g:/pycode/list.py", line 2, in a
    return x/y
ZeroDivisionError: division by zero

這個堆棧跟蹤信息中已經明確說明瞭(most recent call last),說明最近產生異常的調用在最上面,也就是第7行。上面的整個過程是這樣的:第7行出錯,它是因為第5行的代碼引起的,而第5行之所以錯是第2行的源代碼引起的。

所以,從最底部可以看到最終是因為什麼而拋出異常,從最頂部可以看到是執行到哪一句出錯。

深入異常處理

try/except/else/finally

try:
    <statements>
except <name1>:           # 捕獲到名為name1的異常
    <statements>
except (name2, name3):    # 捕獲到name2或name3任一異常
    <statements>
except <name4> as <data>: # 捕獲name4異常,並獲取異常的示例
    <statements>
except:                   # 以上異常都不匹配時
    <statements>
else:                     # 沒有產生異常時
    <statements>
finally:                  # 一定會執行的
    <statements>

註意,當拋出的異常無法被匹配時,將歸類於空的except:,但這是很危險的行為,因為很多時候的異常是必然的,比如某些退出操作、記憶體不足、Ctrl+C等等,而這些都會被捕獲。與之大致等價的是捕獲異常類的"偽"祖先類Exception,即except Exception:,它和空異常匹配類似,但能解決不少不應該匹配的異常。但使用Exception依然是危險的,能不用儘量不用。

如果一個異常既能被name1匹配,又能被name2匹配,則先匹配到的處理這個異常。

通過as關鍵字可以將except捕獲到的異常對象賦值給data變數。用法稍後會解釋,現在需要知道的是,在python 3.x中,變數data只在當前的except塊範圍內有效,出了範圍就會被回收。如果想要保留異常對象,可以將data賦值給一個變數。例如下麵的b在出了try範圍都有效,但是a在這個except之後就無效了。

except Exception as a:
    print(a)
    b=a

通過else分句可以知道,這段try代碼中沒有出現任何異常。否則就不會執行到else分句。

raise

raise用於手動觸發一個異常。而每一種異常都是一個異常類,所以觸發實際上是觸發一個異常類的實例對象。

raise <instance>  # 直接觸發一個異常類的對象
raise <class>     # 構建此處所給類的一個異常對象並觸發
raise             # 觸發最近觸發的異常
raise <2> from <1>  # 將<1>的異常附加在<2>上

其中第二種形式,raise會根據給定類不傳遞任何參數地自動構建一個異常對象,並觸發這個異常對象。第三種直接觸發最近觸發的異常對象,這在傳播異常的時候很有用。

例如,下麵兩種方式實際上是等價的,只不過第一種方式傳遞的是類,raise會隱式地自動創建這個異常類的實例對象。

raise IndexError
raise IndexError()

可以為異常類構建實例時指定點參數信息,這些參數會保存到名為args的元組。例如:

try:
    raise IndexError("something wrong")
except Exception as E:
    print(E.args)

輸出:

('something wrong',)

不僅如此,只要是異常類或異常對象,不管它們的存在形式如何,都可以放在raise中。例如:

err = IndexErro()
raise err

errs = [IndexError, TypeError]
raise errs[0]

對於第三種raise形式,它主要用來傳播異常,一般用在except代碼段中。例如:

try:
    raise IndexError("aaaaa")
except IndexError:
    print("something wrong")
    raise

因為異常被except捕獲後,就表示這個異常已經處理過了,程式會跳轉到finally或整個try塊的尾部繼續執行下去。但是如果不想讓程式繼續執行,而是僅僅只是想知道發生了這個異常,並做一番處理,然後繼續向上觸發異常。這就是異常傳播。

因為實際觸發的異常都是類的實例對象,所以它有屬性。而且,可以通過在except中使用as來將對象賦值給變數:

try:
    1/0
except Exception as a:
    print(a)

變數a在出了except的範圍就失效,所以可以將它保留給一個不會失效的變數:

try:
    1/0
except Exception as a:
    print(a)
    b=a

print(b)

如果在一個except中觸發了另一個異常,會造成異常鏈

try:
    1/0
except Exception as E:
    raise TypeError('Bad')

將會報告兩個異常,並提示處理異常E的時候,觸發了另一個異常TypeError。

Traceback (most recent call last):
  File "g:/pycode/list.py", line 2, in <module>
    1/0
ZeroDivisionError: division by zero

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "g:/pycode/list.py", line 4, in <module>
    raise TypeError('Bad')
TypeError: Bad

使用from關鍵字,可以讓關係更加明確。

try:
    1/0
except Exception as E:
    raise TypeError('Bad') from E

下麵是錯誤報告:

Traceback (most recent call last):
  File "g:/pycode/list.py", line 2, in <module>
    1/0
ZeroDivisionError: division by zero

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "g:/pycode/list.py", line 4, in <module>
    raise TypeError('Bad') from E
TypeError: Bad

實際上,使用from關鍵字的時候,會將E的異常對象附加到TypeError的__cause__屬性上。

但無論如何,這裡都觸發了多個異常。在python 3.3版本,可以使用from None的方式來掩蓋異常的來源,也就是禁止輸出異常E,停止異常鏈:

try:
    1/0
except Exception as E:
    raise TypeError('Bad') from None

錯誤報告如下:

Traceback (most recent call last):
  File "g:/pycode/list.py", line 4, in <module>
    raise TypeError('Bad') from None
TypeError: Bad

可見,異常信息中少了很多內容。

assert

assert斷言常用於調試。用法如下:

assert test, data

它實際上等價於是條件判斷的raise。它等價於下麵的方式:

if __debug__:
    if not test:
        raise AssertionError(data)

如果條件test的測試為真,就跳過,否則就拋出異常。這個異常是通過AssertionError類構造的,構造異常對象的參數是data。data會放進名為args的元組屬性中。

try:
    assert False,"something wrong"
except Exception as E:
    print(E.args)

同樣,assert產生的是名為AssertionError的異常,如果不捕獲這個AssertionError異常,程式將會終止。

除了調試,assert還偶爾用來判斷必要的條件,不滿足條件就異常,以便讓程式更加健壯。例如:

def f(x):
    assert x >= 0, "x must great or equal than 0"
    return x ** 2

print(f(2))
print(f(0))
print(f(-2))   # 觸發AssertionError異常

需要註意的是,寫assert的測試條件時,測試結果為假才觸發異常。所以,應該以if not true的角度去考慮條件,或者以unless的角度考慮。或者說,後面觸發的異常信息,和測試條件應該是正相關的,例如示例中異常信息的說法是x必須大於等於0,和測試條件x >= 0是正相關的。

assert還常用於父類方法的某些方法中,這些方法要求子類必須重寫父類的方法。於是:

class cls:
    ...
    def f(self):
        assert False, "you must override method: f"

此外,assert不應該用來觸發那些python早已經定義好的異常。例如索引越界、類型錯誤等等。這些python已經定義好的異常,我們再去用AssertionError觸發,這是完全多餘的。例如:

def f(obj,index):
    assert index > len(obj), "IndexError"
    return obj[index]

sys.exc_info()

該函數用來收集正在處理的異常的信息。

它返回一個包含3個值的元組(type, value, traceback),它們是當前正在處理的異常的信息。如果沒有正在處理的異常,則返回3個None組成的元組。

其中:

  • type表示正在處理的異常類
  • value表示正在處理的異常實例
  • traceback表示一個棧空間的回調對象(參考官方手冊traceback object)

看一個示例即可知道。

class General(Exception):pass

def raise0():
    x = General()
    raise x

try:
    raise0()
except Exception:
    import sys
    print(sys.exc_info())

執行結果:

(<class '__main__.General'>, General(), <traceback object at 0x0388F2B0>)

結果很明顯,第一個返回值是異常類General,第二個返回值是拋出的異常類的實例對象,第三個返回值是traceback對象。

實際上,當需要獲取當前處理的異常類時,還可以通過異常對象的__class__來獲取,因為異常對象可以在except/as中賦值給變數:

class General(Exception):pass

def raise0():
    x = General()
    raise x

try:
    raise0()
except Exception as E:
    import sys
    print(sys.exc_info()[0])
    print(E.__class__)

它們的的結果是完全一樣的:

<class '__main__.General'>
<class '__main__.General'>

什麼時候要獲取異常類的信息?當except所監視的異常類比較大範圍,同時又想知道具體的異常類。比如,except:except Exception:這兩種監視的異常範圍都非常大,前者會監視BaseException,也就是python的所有異常,後者監視的是Exception,也就是python的所有普通的異常。正因為監視範圍太大,導致不知道具體是拋出的是哪個異常。

區分異常和錯誤

錯誤都是異常,但異常並不一定都是錯誤

很常見的,文件結尾的EOF在各種語言中它都定義為異常,是異常就能被觸發捕獲,但在邏輯上卻不認為它是錯誤。

除此之外,還有操作系統的異常,比如sys.exit()引發的SystemeExit異常,ctrl+c引發的的中斷異常KeyboardInterrupt都屬於異常,但它們和普通的異常不一樣。而且python中的普通異常都繼承字Exception類,但SystemExit卻並非它的子類,而是BaseException的子類。所以能通過空的except:捕獲到它,卻不能通過except Exception:來捕獲。

異常類的繼承

所有異常類都繼承自Exception,要編寫自定義的異常時,要麼直接繼承該類,要麼繼承該類的某個子類。

例如,下麵定義三個異常類,General類繼承Exception,另外兩個繼承General類,表示這兩個是特定的、更具體的異常類。

class General(Exception):pass
class Specific1(General): pass
class Specific2(General): pass

def raise0():
    x = General()
    raise x

def raise1():
    x = Specific1()
    raise x

def raise2():
    x = Specific2()
    raise x

測試下:

for func in (raise0, raise1, raise2):
    try:
        func()
    except General as E:
        import sys
        print("caught: ", E.__class__)

執行結果:

caught:  <class '__main__.General'>
caught:  <class '__main__.Specific1'>
caught:  <class '__main__.Specific2'>

前面說過,except監視父類異常的時候,也會捕獲該類的子類異常。正如這裡監視的是Gereral類,但觸發了Specific子類異常也會被捕獲。

異常類的嵌套

這是非常常見的陷阱。有兩種異常嵌套的方式:try的嵌套;代碼塊的異常嵌套(比如函數嵌套)。無論是哪種嵌套模式,異常都只在最近(或者說是最內層)的代碼塊中被處理,但是finally塊是所有try都會執行的。

第一種try的嵌套模式:

try:
    try:
        (1)
    except xxx:
        (2)
    finally:
        (3)
except yyy:
    ...
finally:
    (4)

如果在(1)處拋出了異常,無論yyy是否匹配這個異常,只要xxx能匹配這個異常,就會執行(2)。但(3)、(4)這兩個finally都會執行。

第二種代碼塊嵌套,常見的是函數調用的嵌套,這種情況可能會比較隱式。例如:

def action2():
    print(1 + [])

def action1():
    try:
        action2()
    except TypeError:
        print('inner try')

try:
    action1()
except TypeError:
    print('outer try')

執行結果:

inner try

上面的action2()會拋出一個TypeError的異常。在action1()中用了try包圍action2()的調用,於是action2()的異常彙報給action1()層,然後被捕獲。

但是在最外面,使用try包圍action1()的調用,看上去異常也會被捕獲,但實際上並不會,因為在action2()中就已經通過except處理好了異常,而處理過的異常將不再是異常,不會再觸發外層的異常,所以上面不會輸出"outer try"。

except應該捕獲哪些異常

在考慮異常捕獲的時候,需要註意幾點:

  1. except監視的範圍別太大了
  2. except監視的範圍別太小了
  3. 有些異常本就該讓它中斷程式的運行,不要去捕獲它

第三點很容易理解,有些異常會導致程式無法進行後續的運行,改中斷還是得中斷。

對於第一點,可能常用的大範圍異常監視就是下麵兩種方式:

except:
except Exception:

這兩種方式監視的範圍都太大了,比如有些不想處理的異常也會被它們監視到。更糟糕的可能是本該彙報給上層的異常,結果卻被這種大範圍捕獲了。例如:

def func():
    try:
        ...
    except:
        ...

try:
    func()
except IndexErro:
    ...

本來是想在外層的try中明確捕獲func觸發的IndexError異常的,但是func()內卻使用了空的except:,使得異常直接在這裡被處理,外層的try永遠也捕獲不到任何該函數的異常。

關於第二點,不應該監視範圍太小的異常。範圍小,意味著監視的異常太過具體,太過細緻,這種監視方式雖然精確,但卻不利於維護。例如E1異常類有2個子異常類E2、E3,在代碼中監視了E2、E3,但如果未來又添加了一個E1的子異常類E4,那麼又得去改代碼讓它監視E4。如果代碼是寫給自己用的倒無所謂,但如果像通用模塊一樣交給別人用的,這意味著讓別的模塊使用者也去改代碼。

自定義異常類

在前面設計異常類的時候,總是使用pass跳過類代碼體。但卻仍然能使用這個類作為異常類,因為它繼承了Exception,在Exception中有相關代碼可以輸出異常信息。

前面說過,在構造異常類的時候可以傳遞參數,它們會放進異常實例對象的args屬性中:

try:
    raise IndexError("something wrong")
except Exception as E:
    print(E.args)

try:
    assert False,"something wrong too"
except Exception as E:
    print(E.args)

I = IndexError('text')
print(I.args)

對於用戶自定義的類,也一樣如此:

class MyError(Exception):pass
try:
    raise MyError('something wrong')
except MyError as E:
    print(E.args)

不僅如此,雖然異常實例對象是一個對象,但如果直接輸出實例對象,那麼得到的結果將是給定的異常信息,只不過它不在元組中。

I = IndexError("index wrong")
print(I)      # 輸出"index wrong"

很容易想到,這是因為Exception類中重寫了__str__或者__repr__中的某一個或兩個都重寫了。

自定義異常輸出

於是,自定義異常類的時候,也可以重寫這兩個中的一個,從而可以定製屬於自己的異常類的輸出信息。一般來說只重寫__str__,因為Exception中也是重寫該類,且它的優先順序高於__repr__

例如下麵自定義的異常類。當然,這個示例的效果非常簡陋,但已足夠說明問題。

class MyError(Exception):
    def __str__(self):
        return 'output this message for something wrong'

try:
    raise MyError("hahhaha")
except MyError as E:
    print(E)

輸出結果:

output this message for something wrong

提供構造方法

自定義異常類的時候,可以重寫構造方法__init__(),這樣raise異常的時候,可以指定構造的數據。而且更進一步的,還可以重寫__str__來自定義異常輸出。

例如,格式化文件的程式中定義一個異常類,用來提示解析到哪個文件的哪一行出錯。

class MyError(Exception):
    def __init__(self,line,file):
        self.line = line
        self.file = file
    def __str__(self):
        return "format failed: %s at %s" % (self.file, self.line)

def format():
    ...
    raise MyError(42, "a.json")
    ...

try:
    format()
except MyError as E:
    print(E)

提供異常類的其它方法

異常類既然是類,說明它可以像普通類一樣拿來應用。比如添加其它類方法。

例如,可以將異常信息寫入到文件中。只需提供一個向文件寫入的方法,併在except的語句塊中調用這個方法即可。

class MyError(Exception):
    def __init__(self, line, file):
        self.line = line
        self.file = file

    def logerr(self):
        with open('Error.log', 'a') as logfile:
            print(self, file=logfile)

    def __str__(self):
        return "format failed: %s at %s" % (self.file, self.line)

def format():
    raise MyError(42, "a.json")

try:
    format()
except MyError as E:
    E.logerr()

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一 簡介:Spring Security是一個能夠為基於Spring的企業應用系統提供聲明式的安全訪問控制解決方案的安全框架。它提供了一組可以在Spring應用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反轉Inversion of Control ,DI:Dependency ...
  • MyBatis開發原始Dao層請閱讀我的上一篇博客:MyBatis開發Dao層的兩種方式(原始Dao層開發) 接上一篇博客繼續介紹MyBatis開發Dao層的第二種方式:Mapper動態代理方式 Mapper介面開發方法只需要程式員編寫Mapper介面(相當於Dao介面),由Mybatis框架根據接 ...
  • 一:簡介:前身是阿裡巴巴的一個開源的項目,後來停止維護,由噹噹網繼續維護,它致力於rpc遠程的調度方案.是一個服務框架 二:執行原理圖: 節點角色說明: · Provider: 暴露服務的服務提供方。 · Consumer: 調用遠程服務的服務消費方。 · Registry: 服務註冊與發現的註冊中 ...
  • 本周我們介紹了以繼承方式實現的媒體資料庫,在課程代碼實現的基礎上,請實現一個表達MP3的媒體類型,能和CD、DVD一樣存放進這個Database。請提交這個MP3類的代碼。如果你認為為了能存放MP3,需要修改Item和Database,也請一併提交Item和Database的代碼。 本周我們介紹了以 ...
  • 1.昨日的補充 reversed 翻轉, 將一個序列翻轉,返回翻轉序列的迭代器 lst = ["河南話", "四川話", "東北", "山東", "上海"] n = reversed(lst) print(list(n)) lst = ["河南話", "四川話", "東北", "山東", "上海"] ...
  • 給定一個數組 nums,有一個大小為 k 的滑動視窗從數組的最左側移動到數組的最右側。你只可以看到在滑動視窗 k 內的數字。滑動視窗每次只向右移動一位。 返回滑動視窗最大值 其實這道題就是求給定數組中獲取全部K個連續元素中最大值的集合 首先我們可能會遇到三中情況 當原始數組為空的,那就直接返回一個空 ...
  • 一:環境準備: Windows、JDK1.8+、Maven、Git 二:RocketMQ準備: 1.http://rocketmq.apache.org/release_notes/release-notes-4.2.0/ 2.選擇‘Binary’進行下載 下完完畢之後解壓 三:配置 進行環境變數配 ...
  • 工廠模式 實現創建者和調用者的分離 簡單工廠,工廠方法,抽象工廠模式。 面向對象的設計原則:OCP(開閉原則):軟體的設計應該對擴展開放,對修改關閉 DIP(依賴倒轉原則):應該針對介面編程,不應該針對實現編程。 簡單工廠: 例: //頂級介面 public interface Car extend ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...