在jQuery中,要选择节点的第n个兄弟节点,是.next()链接n次还是.nextAll(':eq(n-1)')更快?(In jQuery, to select the nth sibling of a node, is .next() chained n times or .nextAll(':eq(n-1)') faster?)
假设节点有任意数量的兄弟节点,并且我想选择该节点的
nth sibling
节点,我应该使用.next()
链接n次,还是应该只使用一次调用.nextAll(':eq(n-1)')
?似乎前者对于大n会有很多额外的开销,并且对于大量的兄弟姐妹来说可能是后者的更大开销。 我关心一个涉及n = 2和大量兄弟姐妹的案例,所以我不确定我是否要使用
.next().next()
或.nextAll(':eq(1)')
。 有关系吗?编辑:对于n = 2和许多兄弟姐妹的情况,它看起来像
.next().next()
是最快的根据http://jsperf.com/next-next-vs-nextall-eq-1-vs- nextall-EQ-1Assuming there are an arbitrary number of siblings of a node, and I wanted to select the
nth sibling
of that node, should I be using.next()
chained up n times, or should I just use a single call to.nextAll(':eq(n-1)')
?Seems like there would be a lot of extra overhead with the former for large n, and possibly a bigger overhead with the latter for large number of siblings. I'm concerned with a case that involves n=2 and a large number of siblings, so I'm not sure if I want to use
.next().next()
or.nextAll(':eq(1)')
. Does it matter?Edit: For the case of n=2 and many siblings, it looks like
.next().next()
is fastest according to http://jsperf.com/next-next-vs-nextall-eq-1-vs-nextall-eq-1
原文:https://stackoverflow.com/questions/11961695
最满意答案
直接从C#使用本机C ++类在技术上是可行的,但它并不是微不足道的,而且它甚至都不是一个好主意。 对于初学者,您必须知道用于从DLL导入的名称,这将是C ++名称修改后的名称。 您也无法直接访问C#中的
vector
等内容。基本上有两个不错的选择:
第一种是使用C接口编写DLL,该接口仅使用可以编组为CLR类型的类型。 您可以将指针与
IntPtr
类型一起使用,但是您无法真正取消引用这些指针。 您几乎可以将它们存储在C#代码中,然后在需要时将它们传递回本机DLL。 只要您不需要深层复制来处理它们,您也可以使用简单的struct
类型。 此选项涉及使用P / Invoke。第二个选项是编写混合模式C ++ / CLI程序集,该程序集实现了访问本机代码所需的所有逻辑。 这个程序集可以直接访问C#代码中的类和数据,也可以直接访问您的本机代码,尽管您应该预先警告,有些烦人的中断,您不能将它们混合在一起。 例如,C ++ / CLI中的
ref class
不能具有shared_ptr
成员。 但是,它可以将原始C ++指针作为成员。 (混合模式)本机类也可以访问CLR句柄类型,并通过它调用C#代码。 此选项涉及使用C ++ Interop。值得注意的是,你也可以采用C ++ Interop的另一种方式。 您可以让C#代码访问混合模式C ++ / CLI程序集,该程序集为某些本机代码提供.NET接口。 但是,在这种情况下,您仍然需要进行一些翻译,因此它并不比第一个选项好很多。
关于C ++ Interop的完整教程将会相当冗长。 我建议你在这里阅读并对Google上的C ++ Interop做进一步的调查。
In order to make a
C wrapper
for aC++
class to be used in for example aC#
application you can do the following.In Visual Studio choose
Win32 Console Application
and Enter a name, Then click next and on the next pane chooseDLL
and click finish. When you are done you are represented with a DLL project including 3 files.testdll.h testdll.cpp dllmain
Delete everything that exists inside your
testdll.h
andtestdll.cpp
files and copy the following contents to each respectively. Add these lines to your testdll.h// Our C wrapper for creating a dll to be used in C# apps // The following ifdef block is the standard way of creating macros which make exporting // from a DLL simpler. All files within this DLL are compiled with the TESTDLL_EXPORTS // symbol defined on the command line. This symbol should not be defined on any project // that uses this DLL. This way any other project whose source files include this file see // TESTDLL_API functions as being imported from a DLL, whereas this DLL sees symbols // defined with this macro as being exported. #ifdef TESTDLL_EXPORTS #define TESTDLL_API __declspec(dllexport) #else #define TESTDLL_API __declspec(dllimport) #endif extern "C" { TESTDLL_API int OurTestFunction(int x, int y); }
It is inside this extern "C" block where you define your interface, functions to access your class member functions.Note the
TESTDLL
before the function prototype. All of your functions must be proceeded by that.Add these to your testdll.cpp file:
#include "testdll.h" #include "ourClass.h" #define DLL_EXPORT extern "C" { OurClass ourObject; TESTDLL_API int OurTestFunction(int x, int y) { return ourObject.Add(x,y); } }
You compile this and get a C based dll which can be used in a C# application.
There are couple of things to notice though, The more important ones are:
- You need to understand that the code you use as a proxy- i mean function definition inside your
testdll.h
, must only use C compatible types, it is C after all not C++.- is that you would want to be able to allocate new objects of your class instead of just using one global object to access all methods.
For this, if you need to pass your class objects between member functions, you need to first convert it to a
void*
which C can understand and then pass it and use it to access your member functions of whatever.For example I would have something like this inside my
testdll.h
in order to make user capable of managing the objects indirectly:#ifdef TESTDLL_EXPORTS #define TESTDLL_API __declspec(dllexport) #else #define TESTDLL_API __declspec(dllimport) #endif extern "C" { TESTDLL_API int OurTestFunction(int x, int y); TESTDLL_API void* CreateHandle(); TESTDLL_API void* GetCurrentHandle(); TESTDLL_API void DisposeCurrentHandle(); TESTDLL_API void SetCurrentHandle(void* handle); TESTDLL_API void* GetHandle(); TESTDLL_API void DisposeHandle(void*); TESTDLL_API void DisposeArrayBuffers(void); }
And inside my testdll.cpp I would define them as :
#include "testdll.h" #include "ourClass.h" #define DLL_EXPORT extern "C" { OurClass *ourObject; TESTDLL_API int OurTestFunction(int x, int y) { //return ourObject.Add(x,y); -- not any more !! ourObject = reinterpret_cast<OurClass *>(GetHandle()); } //Handle operations TESTDLL_API void* CreateHandle() { if (ourObject == nullptr) { ourObject = new OurClass ; } else { delete ourObject ; ourObject = new OurClass ; } return reinterpret_cast<void*>(ourObject); } TESTDLL_API void* GetCurrentHandle() { return reinterpret_cast<void*>(ourObject ); } TESTDLL_API void DisposeCurrentHandle() { delete ourObject ; ourObject = nullptr; } TESTDLL_API void SetCurrentHandle(void* handle) { if (handle != nullptr) { ourObject = reinterpret_cast<OurClass *>(handle); } else { ourObject = new OurClass ; } } //factory utility function TESTDLL_API void* GetHandle() { void* handle = GetCurrentHandle(); if (handle != nullptr) { return handle; } else { ourObject = new OurClass ; handle = reinterpret_cast <void*>(ourObject ); } return handle; } CDLL_API void DisposeHandle(void* handle) { OurClass * tmp = reinterpret_cast<OurClass *>(handle); delete tmp; } TESTDLL_API void DisposeArrayBuffers(void) { ourObject = reinterpret_cast<OurClass *>(GetHandle()); return ourObject ->DisposeBuffers();//This is a member function defined solely for this purpose of being used inside this wrapper to delete any allocated resources by our class object. } }
And when we compile this
Dll
, we can easily work with it inside our C# application. Before being able to use our functions defined in this dll we need to use appropriate[ImportDll()]
. So for our TestDll we would write:[DllImport(@"TestDll.dll", CallingConvention = CallingConvention.Cdecl)] public static extern int OurTestFunction(int firstNumber,int secondNumber);
And finally use it like:
private void btnReadBigram_Click(object sender, EventArgs e) { int x = OurTestFunction(10,50); MessageBox.Show(x.ToString()); }
This is all I did to make my C++ class member functions accessible inside a C# application without any hassle.
Note:
When compiling your C# application make sure you have chosen thex86
Platform for compiling your project notAnyCpu
.You can change your platform through properties.Note 2:
For knowing how to create a C++/CLI wrapper for your native C++ class read this: C++/CLI wrapper for your native C++ class.
相关问答
更多-
TCP/IP模型是一个________。[2023-10-02]
a -
下列中不属于面向对象的编程语言的是?[2022-05-30]
a -
如何在基于C的DLL或基于CLI的DLL中包装C ++类?(How to wrap a C++ class in a C based dll or a CLI based dll?)[2023-03-20]
直接从C#使用本机C ++类在技术上是可行的,但它并不是微不足道的,而且它甚至都不是一个好主意。 对于初学者,您必须知道用于从DLL导入的名称,这将是C ++名称修改后的名称。 您也无法直接访问C#中的vector等内容。 基本上有两个不错的选择: 第一种是使用C接口编写DLL,该接口仅使用可以编组为CLR类型的类型。 您可以将指针与IntPtr类型一起使用,但是您无法真正取消引用这些指针。 您几乎可以将它们存储在C#代码中,然后在需要时将它们传递回本机DLL。 只要您不需要深层复制来处理它们,您也可以使用 ... -
将本机C ++ dll中的矢量返回到托管C ++ / CLI dll(Returning a vector from a native C++ dll into a managed C++/CLI dll)[2021-09-16]
除非你想延迟Instrument::_type的编组,直到它的托管外观被访问,否则这应该让你开始: public ref class InstrumentM { String^ _type; unsigned _depth; internal: explicit InstrumentM(Instrument const& i) : _type(gcnew String(i._type.c_str())), _depth(i._depth) { } ... -
荣誉马特,感谢提示使用过程监视器。 ETL工具没有找到DLL,但进程监视器告诉我它正在检查的文件夹...我将DLL移动到其中一个选中的文件夹 我的包装函数最初是无效的,并且返回值的输出参数 - 这是导致问题的原因,因为我在ETL文档中没有一个很好的示例来说明如何调用void函数。 我改变了函数返回一个“长”,并删除了输出参数。 完成这两项更改后,它开始工作。 再次感谢马特! Kudos to Matt, thanks for the hint to use Process Monitor. ETL tool ...
-
在Visual C ++ 6.0应用程序中使用C ++ / CLI DLL(Using a C++/CLI DLL in a Visual C++ 6.0 application)[2023-07-01]
事实证明这是一个操作系统问题。 在我注意到它在Windows 8.1 PC上工作正常后,我看了一下C ++ / CLI DLL的平台工具集设置。 要获得这些,请右键单击项目 - >属性 - >配置属性 - >常规。 当我应该定位“Visual Studio 2013 - Windows XP(v120_xp)”时,我的目标是“Visual Studio 2013(v120)”。 在我更改了该设置后,DLL开始在Windows XP计算机上运行。 It turns out this is an operati ... -
除非其中一个项目是启动项目(即解决方案资源管理器中的粗体项目), 否则这些设置都不重要。 启动项目的设置非常重要。 或者,如果您不想更改启动项目,则可以执行“附加到进程”并指定哪些类型(托管,本机等)。 None of those settings matter unless one of those projects is the Start-up project (i.e. the one in bold in the solution explorer). The settings of the st ...
-
我过去所做的与MSDN文章非常相似 创建一个C ++类,并确保该cpp文件的编译器选项设置为“No Common Language RunTime Support” 然后使用pimpl在C ++ / CLI类中引用此C ++类,确保此cpp文件启用了“公共语言运行时支持(/ clr)”。 输出将是您可以在现有.NET代码中使用的DLL。 根据经验,我将确保您在包装器类中创建的接口只有double,int等,而不是引用任何C ++类。 @Bill在一些C#代码中使用这个包装器DLL只需使用“Add Refer ...
-
我应该为非托管C ++ DLL创建C ++ / CLI包装器DLL吗?(Should I create a C++/CLI wrapper DLL for an unmanaged C++ DLL?)[2023-05-09]
是的,您需要为此库创建C ++ / CLI包装器,并在此包装器内部使用非托管类。 对于暴露C风格API的非托管库,还有PInvoke选项,但它不适用于C ++类。 您还可以考虑制作COM包装器,您希望在本机COM客户端和.NET中使用此库。 但我认为制作C ++ / CLI包装器是一项更简单的任务。 Yes, you need to create C++/CLI wrapper for this library, and use unmanaged classes internally in this wr ... -
从C ++ / CLI调用DLL函数时的PInvokeStackImbalance(PInvokeStackImbalance when calling a DLL function from C++/CLI)[2022-02-10]
您正在使用的std::string的定义与用于编译本机C ++ DLL的定义之间存在差异。 即使定义相同,本机DLL可能没有使用与您相同版本的C运行时,因此当您的DLL为std::string分配内存时,Native DLL将尝试在其上调用delete (当在readFile方法结束时销毁字符串时),对delete调用将转到与分配对象不同的堆! 如果要使其工作,则必须使用与本机DLL上使用的完全相同的编译器版本。 请注意,您将仅限于项目的发布版本,因为您没有使用调试运行时编译的本机DLL。 解决此问题的正确 ...