这本来是一个比较冗长的问题,但现在我构建了一个更小的可用示例代码,因此原文不再相关。
我有两个项目,一个包含一个没有成员的结构,名为TestType。该项目被主项目引用,但程序集不包含在可执行目录中。主项目创建一个新的应用程序域,它在其中使用包含的程序集的名称注册 AssemblyResolve 事件。在主应用程序域中,处理相同的事件,但它手动从项目资源加载程序集。
然后新的应用程序域构建了它自己的 TestType 版本,但比原始版本具有更多字段。主应用域使用虚拟版本,新应用域使用生成的版本。
当调用在其签名中具有 TestType 的方法时(即使只是返回它就足够了),它似乎只会破坏运行时的稳定性并破坏内存。
我正在使用 .NET 4.5,在 x86 下运行。
虚拟程序集:
using System;
[Serializable]
public struct TestType
{
}
主要项目:
using System;
using System.Reflection;
using System.Reflection.Emit;
internal sealed class Program
{
[STAThread]
private static void Main(string[] args)
{
Assembly assemblyCache = null;
AppDomain.CurrentDomain.AssemblyResolve += delegate(object sender, ResolveEventArgs rargs)
{
var name = new AssemblyName(rargs.Name);
if(name.Name == "DummyAssembly")
{
return assemblyCache ?? (assemblyCache = TypeSupport.LoadDummyAssembly(name.Name));
}
return null;
};
Start();
}
private static void Start()
{
var server = ServerObject.Create();
//prints 155680
server.TestMethod1("Test");
//prints 0
server.TestMethod2("Test");
}
}
public class ServerObject : MarshalByRefObject
{
public static ServerObject Create()
{
var domain = AppDomain.CreateDomain("TestDomain");
var t = typeof(ServerObject);
return (ServerObject)domain.CreateInstanceAndUnwrap(t.Assembly.FullName, t.FullName);
}
public ServerObject()
{
Assembly genAsm = TypeSupport.GenerateDynamicAssembly("DummyAssembly");
AppDomain.CurrentDomain.AssemblyResolve += delegate(object sender, ResolveEventArgs rargs)
{
var name = new AssemblyName(rargs.Name);
if(name.Name == "DummyAssembly")
{
return genAsm;
}
return null;
};
}
public TestType TestMethod1(string v)
{
Console.WriteLine(v.Length);
return default(TestType);
}
public void TestMethod2(string v)
{
Console.WriteLine(v.Length);
}
}
public static class TypeSupport
{
public static Assembly LoadDummyAssembly(string name)
{
var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(name);
if(stream != null)
{
var data = new byte[stream.Length];
stream.Read(data, 0, data.Length);
return Assembly.Load(data);
}
return null;
}
public static Assembly GenerateDynamicAssembly(string name)
{
var ab = AppDomain.CurrentDomain.DefineDynamicAssembly(
new AssemblyName(name), AssemblyBuilderAccess.Run
);
var mod = ab.DefineDynamicModule(name+".dll");
var tb = GenerateTestType(mod);
tb.CreateType();
return ab;
}
private static TypeBuilder GenerateTestType(ModuleBuilder mod)
{
var tb = mod.DefineType("TestType", TypeAttributes.Public | TypeAttributes.Serializable, typeof(ValueType));
for(int i = 0; i < 3; i++)
{
tb.DefineField("_"+i.ToString(), typeof(int), FieldAttributes.Public);
}
return tb;
}
}
虽然 TestMethod1 和 TestMethod2 都应该打印 4,但第一个访问内存的一些奇怪部分,并且似乎破坏了调用堆栈足以影响调用到第二种方法。如果我删除对第一个方法的调用,一切都很好。
如果我在 x64 下运行代码,第一个方法会抛出 NullReferenceException。
两个结构的字段数量似乎很重要。如果第二个结构总的来说比第一个大(如果我只生成一个字段或不生成任何字段),一切也都正常,如果 DummyAssembly 中的结构包含更多字段,则一切正常。这让我相信 JITter 要么错误地编译了方法(没有使用生成的程序集),要么调用了错误的 native 版本的方法。我检查过 typeof(TestType) 返回类型的正确(生成)版本。
总而言之,我没有使用任何不安全的代码,所以这不应该发生。
最佳答案
我能够在我的机器上用最新的框架重现这个问题。
我在默认应用程序域的程序集解析中添加了版本检查:
if (name.Name == "DummyAssembly" && name.Version.Major == 1)
我得到以下异常:
System.Runtime.Serialization.SerializationException: Cannot find assembly 'DummyAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'
Server stack trace:
w System.Runtime.Serialization.Formatters.Binary.BinaryAssemblyInfo.GetAssembly()
w System.Runtime.Serialization.Formatters.Binary.ObjectReader.GetType(BinaryAssemblyInfo assemblyInfo, String name)
w System.Runtime.Serialization.Formatters.Binary.ObjectMap..ctor(String objectName, String[] memberNames, BinaryTypeEnum[] binaryTypeEnumA, Object[] typeInformationA, Int32[] memberAssemIds, ObjectReader objectReader, Int32 objectId, BinaryAssemblyInfo assemblyInfo, SizedArray assemIdToAssemblyTable)
w System.Runtime.Serialization.Formatters.Binary.__BinaryParser.ReadObjectWithMapTyped(BinaryObjectWithMapTyped record)
w System.Runtime.Serialization.Formatters.Binary.__BinaryParser.ReadObjectWithMapTyped(BinaryHeaderEnum binaryHeaderEnum)
w System.Runtime.Serialization.Formatters.Binary.__BinaryParser.Run()
w System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize(HeaderHandler handler, __BinaryParser serParser, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
w System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream, HeaderHandler handler, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
w System.Runtime.Remoting.Channels.CrossAppDomainSerializer.DeserializeObject(MemoryStream stm)
w System.Runtime.Remoting.Messaging.SmuggledMethodReturnMessage.FixupForNewAppDomain()
w System.Runtime.Remoting.Channels.CrossAppDomainSink.SyncProcessMessage(IMessage reqMsg)
Exception rethrown at [0]:
w System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
w System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
w ServerObject.TestMethod1(TestType& result, String v)
Binary formatter 在这里用于 Marshaling,它从不同的 AppDomains 中找到不同大小的值类型。请注意,当您调用 TestMethod1 时,它会尝试加载版本为 0.0.0.0 的 DummyAssembly,并且您将虚拟版本 1.0 传递给它.0.0 您较早缓存,其中 TestType 具有不同的大小。
由于结构的大小不同,当您从方法中按值返回时,AppDomains 之间的编码出现问题并且堆栈变得不平衡(可能是运行时中的错误?)。通过引用返回似乎没有问题(引用的大小始终相同)。
使两个程序集中的结构大小相等/通过引用返回应该可以解决这个问题。
关于c# - 跨 AppDomain 调用破坏了运行时,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45645669/
总的来说,我对ruby还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用
我需要在客户计算机上运行Ruby应用程序。通常需要几天才能完成(复制大备份文件)。问题是如果启用sleep,它会中断应用程序。否则,计算机将持续运行数周,直到我下次访问为止。有什么方法可以防止执行期间休眠并让Windows在执行后休眠吗?欢迎任何疯狂的想法;-) 最佳答案 Here建议使用SetThreadExecutionStateWinAPI函数,使应用程序能够通知系统它正在使用中,从而防止系统在应用程序运行时进入休眠状态或关闭显示。像这样的东西:require'Win32API'ES_AWAYMODE_REQUIRED=0x0
在选择我想要运行操作的频率时,唯一的选项是“每天”、“每小时”和“每10分钟”。谢谢!我想为我的Rails3.1应用程序运行调度程序。 最佳答案 这不是一个优雅的解决方案,但您可以安排它每天运行,并在实际开始工作之前检查日期是否为当月的第一天。 关于ruby-如何每月在Heroku运行一次Scheduler插件?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/8692687/
exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby中使用两个参数异步运行exe吗?我已经尝试过ruby命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何rubygems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除
我尝试运行2.x应用程序。我使用rvm并为此应用程序设置其他版本的ruby:$rvmuseree-1.8.7-head我尝试运行服务器,然后出现很多错误:$script/serverNOTE:Gem.source_indexisdeprecated,useSpecification.Itwillberemovedonorafter2011-11-01.Gem.source_indexcalledfrom/Users/serg/rails_projects_terminal/work_proj/spohelp/config/../vendor/rails/railties/lib/r
Sinatra新手;我正在运行一些rspec测试,但在日志中收到了一堆不需要的噪音。如何消除日志中过多的噪音?我仔细检查了环境是否设置为:test,这意味着记录器级别应设置为WARN而不是DEBUG。spec_helper:require"./app"require"sinatra"require"rspec"require"rack/test"require"database_cleaner"require"factory_girl"set:environment,:testFactoryGirl.definition_file_paths=%w{./factories./test/
我正在尝试编写一个将文件上传到AWS并公开该文件的Ruby脚本。我做了以下事情:s3=Aws::S3::Resource.new(credentials:Aws::Credentials.new(KEY,SECRET),region:'us-west-2')obj=s3.bucket('stg-db').object('key')obj.upload_file(filename)这似乎工作正常,除了该文件不是公开可用的,而且我无法获得它的公共(public)URL。但是当我登录到S3时,我可以正常查看我的文件。为了使其公开可用,我将最后一行更改为obj.upload_file(file
GivenIamadumbprogrammerandIamusingrspecandIamusingsporkandIwanttodebug...mmm...let'ssaaay,aspecforPhone.那么,我应该把“require'ruby-debug'”行放在哪里,以便在phone_spec.rb的特定点停止处理?(我所要求的只是一个大而粗的箭头,即使是一个有挑战性的程序员也能看到:-3)我已经尝试了很多位置,除非我没有正确测试它们,否则会发生一些奇怪的事情:在spec_helper.rb中的以下位置:require'rubygems'require'spork'
如何在ruby中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL
我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha