I've read lots of times about the efficiency of the Regex
class and how important it is to either call it's static methods or cache the regex instance.
I'd like to know if the same problems would be observable if I instantiated the RNGCryptoServiceProvider
class multiple times instead of caching a single instance of the class and calling GetBytes
on it.
Instantiating it every time I need a random number would simplify my code a bit since I don't have to worry about a disposable instance hanging and propagating an IDisposable
interface across a bunch of classes.
The only thing I found about this is that creating an instance of a RNGCryptoServiceProvider should be very fast, but I'd still like to see confirmation and what would the best practices be.
Would there also be any differences in the random numbers being generated if I instantiated the class every time versus using the same instance?
Repeated construction using the default constructor shouldn't have any ill effects for performance or randomness quality.
Let's take a look at the source code...
#if !FEATURE_PAL
[System.Security.SecuritySafeCritical] // auto-generated
public RNGCryptoServiceProvider() : this((CspParameters) null) {}
#else // !FEATURE_PAL
public RNGCryptoServiceProvider() { }
#endif // !FEATURE_PAL
The FEATURE_PAL directive has to do with windows vs. non-windows platforms. But we don't need to know the details; let's just look at both true and false cases.
First, it's clear that if FEATURE_PAL is enabled, there's no code in the default constructor.
In the other case, the constructor calls a specific constructor with null CspParameters. That other constructor looks like this:
[System.Security.SecuritySafeCritical] // auto-generated
public RNGCryptoServiceProvider(CspParameters cspParams) {
if (cspParams != null) {
m_safeProvHandle = Utils.AcquireProvHandle(cspParams);
m_ownsHandle = true;
}
else {
m_safeProvHandle = Utils.StaticProvHandle;
m_ownsHandle = false;
}
}
cspParams will always be null, so the constructor is getting the value of Utils.StaticProvHandle
. That getter looks like this:
#if !FEATURE_PAL
[System.Security.SecurityCritical /*auto-generated*/]
private static SafeProvHandle _safeProvHandle = null;
internal static SafeProvHandle StaticProvHandle {
[System.Security.SecurityCritical] // auto-generated
get {
if (_safeProvHandle == null) {
lock (InternalSyncObject) {
if (_safeProvHandle == null) {
SafeProvHandle safeProvHandle = AcquireProvHandle(new CspParameters(DefaultRsaProviderType));
Thread.MemoryBarrier();
_safeProvHandle = safeProvHandle;
}
}
}
return _safeProvHandle;
}
}
#endif // !FEATURE_PAL
It's backed by a static variable. The getter uses some locks during first initialization, but subsequent calls simply return the static variable.
Now let's look back at RNGCryptoServiceProvider.cs and look at the Dispose method:
[System.Security.SecuritySafeCritical] // auto-generated
protected override void Dispose(bool disposing) {
base.Dispose(disposing);
if (disposing && m_ownsHandle) {
m_safeProvHandle.Dispose();
}
}
m_ownsHandle
is false if the default constructor was called, so it never disposes anything.
So all that happens during each construction+disposal is some simple variable access.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With