You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Do nothing.
That is, leave it up to downstream libraries to ensure that if they access ModuleScope's ModuleBuilders, they must not call into their ProxyGenerator at the same time.
Deprecate ModuleScope.DefineType as well.
Not very realistic because, for instance, NSubstitute and Moq both rely on this API in order to mock delegate types.
Expose the ReaderWriterLockSlim lock that ModuleScope uses internally. ModuleScope has an API that exposes the two ModuleBuilders that it uses, which essentially means that once a user starts accessing ModuleBuilders, all thread-safety guarantees are off. We can no longer expose a Lock, but we could expose the internal ReaderWriterLockSlim instead.
Augment ModuleScope with a thread-safe alternative for DefineType.
Apart from (0) above, this is my personal preference. This could be in the form of a new method on ModuleScope which performs the necessary locking internally, for example:
+[Obsolete("This method is not thread-safe. Please use `ModuleBuilder.CreateType` instead.")]
public TypeBuilder DefineType(bool inSignedModulePreferably, string name, TypeAttributes flags)
{
…
}
+public Type CreateType(bool inStrongNamedModulePreferably,+ string name,+ TypeAttributes flags,+ Func<TypeBuilder, Type> build)+{+ TypeCache.Lock.EnterWriteLock();+ try+ {+ var module = ObtainDynamicModule(disableSignedModule == false && inStrongNamedModulePreferably);+ var typeBuilder = module.DefineType(name, flags);+ return build.Invoke(typeBuilder);+ }+ finally+ {+ TypeCache.Lock.ExitWriteLock();+ }+}
(This option would probably entail deprecating the ObtainDynamicModule API as well. ModuleScope would eventually have a less powerful API, but one where thread-safety would already be taken care of for downstream libraries.)
@castleproject/committers, do you see any other options here? If not, which one of the above do you think we should go for?
@zvirja alerted me to the fact that after deprecating
Lock(in #391), it seems no longer possible in the layers above DynamicProxy to useModuleScope.DefineTypein a thread-safe manner; see https://github.com/nsubstitute/NSubstitute/pull/420/files#r197765187.I see three options to resolve this:
Do nothing.
That is, leave it up to downstream libraries to ensure that if they access
ModuleScope'sModuleBuilders, they must not call into theirProxyGeneratorat the same time.Deprecate
ModuleScope.DefineTypeas well.Not very realistic because, for instance, NSubstitute and Moq both rely on this API in order to mock delegate types.
Revert Deprecate
LockandModuleScope's public type cache API #391.I'm biased here, but I think it would be a pity because that PR went in the right direction of closing doors into DynamicProxy's internals.
Expose the
ReaderWriterLockSlimlock thatModuleScopeuses internally.ModuleScopehas an API that exposes the twoModuleBuilders that it uses, which essentially means that once a user starts accessingModuleBuilders, all thread-safety guarantees are off. We can no longer expose aLock, but we could expose the internalReaderWriterLockSliminstead.Augment
ModuleScopewith a thread-safe alternative forDefineType.Apart from (0) above, this is my personal preference. This could be in the form of a new method on
ModuleScopewhich performs the necessary locking internally, for example:(This option would probably entail deprecating the
ObtainDynamicModuleAPI as well.ModuleScopewould eventually have a less powerful API, but one where thread-safety would already be taken care of for downstream libraries.)@castleproject/committers, do you see any other options here? If not, which one of the above do you think we should go for?