在.NET 4中不推荐使用代码访问安全性(CAS)。每当您调用隐式使用它的方法时,它都会失败并显示NotSupportedException
,可以使用configuration switch来解决该问题,使其回归旧行为。
我们有一个在.NET 3.5和.NET 4中都使用的公共库,所以我们需要能够判断我们是否应该使用CAS方法。
例如,在.NET 3.5中我应该调用:
Assembly.Load(string, Evidence);
而在.NET 4中,我想调用
Assembly.Load(string);
致电Load(string, Evidence)
会引发NotSupportedException
。
当然这有效,但我想知道是否有更好的方法:
try
{
asm = Assembly.Load(someString, someEvidence);
}
catch(NotSupportedException)
{
asm = Assembly.Load(someString);
}
答案 0 :(得分:2)
HI,
使用Environment.Version.Major
和Environment.Version.Minor
可以解决问题。
Version v = Environment.Version;
if (Environment.Version.Major <= 3)
{
//DO 3.5 here
}
else if (Environment.Version.Major >= 4)
{
//DO 4 here
}
希望这有帮助。
编辑:更改条件以假设将在未来版本的.NET上实现相同的CAS。
答案 1 :(得分:1)
这直接针对该功能进行编码。
public static Assembly LoadAssembly(string assembly, Evidence evidence)
{
Assembly asm;
MethodInfo load =
typeof(Assembly).GetMethod("Load",
new Type[] {typeof(string), typeof(Evidence)});
if (Attribute.IsDefined(load, typeof(ObsoleteAttribute)))
{
asm = Assembly.Load(assembly);
}
else
{
asm = Assembly.Load(assembly, evidence);
}
return asm;
}
此代码假定以下使用语句。
using System;
using System.Reflection;
using System.Security.Policy;
如果经常调用它,你可以避免这样的反射性能。
private static bool? _isEvidenceObsolete = null;
public static Assembly AssemblyLoader(string assembly, Evidence evidence)
{
Assembly asm;
if (!_isEvidenceObsolete.HasValue)
{
MethodInfo load =
typeof(Assembly).GetMethod("Load",
new Type[] { typeof(string), typeof(Evidence) });
_isEvidenceObsolete = Attribute.IsDefined(load, typeof(ObsoleteAttribute));
}
if (_isEvidenceObsolete.Value)
{
asm = Assembly.Load(assembly);
}
else
{
asm = Assembly.Load(assembly, evidence);
}
return asm;
}
编辑:我必须亲自看看性能统计数据是什么,这就是我得到的。
经过的时间(以毫秒为单位):
Catch Exception: 45331
Reflection: 58
Static Reflection: 1
以下是我用于进行基准测试的代码:
public static void BenchmarkLoaders()
{
Stopwatch timer = new Stopwatch();
// Benchmark catching Exceptions
timer.Start();
for (int i = 0; i < 10000; i++)
{
NotSupported notSupported = new NotSupported();
try
{
notSupported.ThrowException("Obsoleted Method Call");
}
catch (NotSupportedException nse)
{
//Do something
}
}
timer.Stop();
Console.WriteLine("Catch Exception: {0}", timer.ElapsedMilliseconds);
timer.Reset();
// Benchmark Reflection
timer.Start();
for (int i = 0; i < 10000; i++)
{
NotSupported notSupported = new NotSupported();
notSupported.ReflectAssembly();
}
timer.Stop();
Console.WriteLine("Reflection: {0}", timer.ElapsedMilliseconds);
timer.Reset();
// Benchmark Static Reflection
timer.Start();
for (int i = 0; i < 10000; i++)
{
NotSupported.ReflectAssemblyStatic();
}
timer.Stop();
Console.WriteLine("Static Reflection: {0}", timer.ElapsedMilliseconds);
timer.Reset();
}
这是 NotSupported
类。
public class NotSupported
{
public void ThrowException(string message)
{
throw new NotSupportedException(message);
}
public void ReflectAssembly()
{
MethodInfo load =
typeof(Assembly).GetMethod("Load",
new Type[] { typeof(string), typeof(Evidence) });
if (Attribute.IsDefined(load, typeof(ObsoleteAttribute)))
{
// Do something
}
}
private static bool? _isEvidenceObsolete = null;
public static void ReflectAssemblyStatic()
{
Assembly asm;
if (!_isEvidenceObsolete.HasValue)
{
MethodInfo load =
typeof(Assembly).GetMethod("Load",
new Type[] { typeof(string), typeof(Evidence) });
_isEvidenceObsolete = Attribute.IsDefined(load, typeof(ObsoleteAttribute));
}
if (_isEvidenceObsolete.Value)
{
//Do Stuff
}
}
}
我意识到这些不是真实世界的数字,但它确实为使用反映异常提供了一个非常有说服力的论据。
答案 2 :(得分:0)
System.Security.HostSecurityManager.DomainPolicy属性的getter是一种公共的轻量级方法,如果未应用旧版CAS策略开关,它将在.NET 4.0中快速失败。您可能需要考虑设置一个帮助程序类,以避免不止一次地产生潜在异常的成本。 e.g :
internal static class CasPolicyHelper
{
private static bool? _isCasPolicyEnabled;
internal static bool IsCasPolicyEnabled
{
get
{
if (_isCasPolicyEnabled == null)
{
HostSecurityManager hostSecurityManager = new HostSecurityManager();
try
{
PolicyLevel level = hostSecurityManager.DomainPolicy;
_isCasPolicyEnabled = true;
}
catch (NotSupportedException)
{
_isCasPolicyEnabled = false;
}
}
return _isCasPolicyEnabled.Value;
}
}
}