问题描述
是否可以通过引用一个方法来固定传递一个 int,然后将该变量固定在内存中,以便我可以使用指针访问它?
我正在尝试使用 GCHandle.Alloc 在内存中临时固定一个 int,以便我可以安全地存储指向该整数的指针。当我尝试通过存储在 GCHandle 中的指针设置 int 的值时,我的整数不会更新。如果我使用不安全代码创建一个指向 int 的指针,我可以成功地更改 int。似乎 int 是按值传递的,我设置的 int 与实际固定的 int 不同。这是我目前面临的问题的示例:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var count = 8001;
var mc = MyClass.New(ref count);
mc.Process();
}
}
public unsafe sealed class MyClass
{
private GCHandle handle;
private readonly int* countPtr;
private MyClass(GCHandle handle,ref int totalCount)
{
this.handle = handle;
fixed (int* p = &totalCount)
countPtr = p;
}
public void Process()
{
var value = 9001;
var handlePtr = (int*)handle.AddrOfPinnedobject();
*handlePtr = (int)value; // count is unchanged
*countPtr = (int)value; // IT'S OVER 9000!
handle.Free();
}
public static MyClass New(ref int count)
{
var handle = GCHandle.Alloc(count,GCHandleType.Pinned);
return new MyClass(handle,ref count);
}
}
}
handlePtr 和 countPtr 的内存地址是不同的,这让我相信我认为固定的不是固定的......而且我可能在我的应用程序中构建了一个定时炸弹。
用例:
public IEnumerable<Rows> CallMyProcedure(int pageIndex,int pageSize,out int totalCount)
{
var rows = Call()
.SetParameter("PageIndex",pageIndex)
.SteParameter("PageSize",pageSize)
.EnumerateDataSet(commandTimeoutSeconds: 60);
return rows;
}
Call() 开始构建关于如何在运行时设置存储过程的上下文。 SetParameter 和其他几个方法将数据添加到执行 StoredProcedure 时将使用的上下文中。 EnumerateData 设置一个 IEnumerable 状态机,该状态机使用 sqlDataReader 执行存储过程,该存储过程在每行上产生。
某些存储过程使用偏移/提取来检索有限数量的结果。在这些情况下,我还需要使用 sql 输出参数输出总行数
public IEnumerable<Rows> CallMyProcedure(int pageIndex,out int totalCount)
{
var count = 0;
var rows = Call()
.SetParameter("PageIndex",pageSize)
.OutputTotalCount(x=> count = x)
.EnumerateDataSet(commandTimeoutSeconds: 60)
.ToList();
totalCount = count;
return rows;
}
将在枚举所有行并关闭 sqlDataReader 后执行我传递的操作,因为这是从 sql 存储过程获取 OutPutParameter 的唯一方法。因此,这样做的唯一原因是因为我正在调用 .ToList()。如果我不调用 .ToList(),out totalCount 将被设置为 0,则该方法返回并在读取所有行后触发设置计数的操作。
我希望添加一个额外的 OutputTotalCount 重载,以便能够使用 do
public IEnumerable<Rows> GetAllData()
{
var count = 0;
return CallMyProcedure(1,int.MaxValue,out count);
}
public DataPage GetDataPage(int pageIndex,int pageSize)
{
var count = 0;
var list = CallMyProcedure(pageIndex,pageSize,out count).ToList()
return new DataPage
{
Data = list,TotalCount = count
}
}
public IEnumerable<Rows> CallMyProcedure(int pageIndex,out int totalCount)
{
totalCount = 0; // Needed because we are leaving this method before setting
var rows = Call()
.SetParameter("PageIndex",pageSize)
.OutputTotalCount(ref totalCount)
.EnumerateDataSet(commandTimeoutSeconds: 60)
return rows;
}
此处新的 OutPutTotalCount 重载本质上将 MyClass 的实例添加到 EnumerDataSet 将在调用 GetEnumerator 时用于执行存储过程的上下文。读取所有行后将调用进程。 GCHandles 也由执行上下文跟踪,并在 try/finally 中释放。
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)