`

ADO在.NET应用程序中挥洒自如

 
阅读更多

ADO 在 .NET 应用程序中挥洒自如

发布日期: 4/1/2004 | 更新日期: 4/1/2004

Dino Esposito

2001 年 2 月 22 日

下载 Data02222001.exe

*

软件地质学家声称这种岩石起源于后 Internet 时代,即在第一次 ODBC 冰河期后出现。在过去的数年时间里建立的所有 DNA 系统中,都多次发现了这种矿石代码 — 在这段时间里,无疑存在地质学时代的软件雏形。

了解 ADO 岩石的形成过程有助于获得有关上一个软件时代中的周围环境和业务逻辑的有用信息。推断过去并了解其促成因素始终是一种判断如何规划和面向未来的有效方法。

这种基本的哲学原则在翻译为软件术语后,就成了一条人们耳熟能详的警示:“做好管理您的遗传代码的准备。”(我们所有人都有某些种类的遗传代码,因此,至少在没有翻箱倒柜地进行仔细查找之前不要断言您没有遗传代码。)

从 .NET 应用程序的观点来看,所有 ADO 代码都是遗传代码。事实上,要在 .NET 中完成数据处理,您应该使用新的 ADO.NET 类。如果您剪切和粘贴使用 ADO 对象的现有 Visual Basic_ 或 ASP 应用程序,并将它保存为 .NET 等效应用程序,则一定会出现许多错误,对此,您一定要有心理准备。

简而言之,您可以将 ADO 类导入到任何类别的 .NET 应用程序(Windows 窗体、Web 窗体或 Web 服务)或者将其替换为 ADO.NET。问题难就难在,人们将 ADO.NET 看成是基于 Web 的下一级 ADO。然而,它在功能上并不等同于 ADO,但也不是与 ADO 完全无关。

正如您所看到的一样,这会产生许多重要的设计问题,其中最重要的无疑是在 .NET 应用程序中如何集成 ADO。第二点(但绝非不重要)是找出 ADO.NET 和 ADO 在功能上的差异,以及因而为在两个框架中获得相同结果而应采取的措施。

本期将设法详细解答这些问题。换句话说,此处,我最大目的是描述一些基本的规则,以预测在您以后的一些项目中可能出现的代码地震或功能冰河。

在穿越 COM 河流的过程中架起了一座 Interop 的桥梁(此外,需要修改样式)

对于所有 .NET 应用程序,ADO 就是一个外部组件,即各种组件模型的子模型。对于所有 .NET 应用程序,调用 ADO 对象与调用任何其他 COM(+) 组件绝无两样。所有 .NET 应用程序必须执行一些非常规的操作来调用 COM(+) 组件。在 nutshell 中,ADO 在 .NET 领域是一个不折不扣的门外汉。

另一方面,.NET 框架只不过是在不断发展的组件结构中向前迈出的自然而然的一步,这种结构是 COM 在数年前创立的。尽管 COM 和 .NET 有很多共同之处(包括组件重复使用和语言中立性),但两者仍是差别很大的实体。要从其中一个实体调用另一个实体,需要搭建特殊的桥梁来保证兼容性。

COM Interop 模块提供了从 .NET 应用程序访问现有 COM 组件所需的中间代码层。它作为本地代理,并负责将 COM 组件公开为本机 .NET 类。更为重要的是,它执行此操作时不需要修改原始组件。

为将现有的 COM 组件加入到 .NET 托管应用程序中,您可以通过系统提供的特殊实用程序(称为 TLBIMP)导入组件的类型库。它为 .NET 应用程序提供一个与 COM 对象具有相同编程接口的新框架类。完成此操作后,调用 COM 对象就像调用本机 .NET 类一样。

如何导入 ADO

TLBIMP.EXE 是 .NET 框架提供的一个免费系统实用程序。它生成一个程序集,其中包含基于指定 COM 类型库的常规 .NET 元数据。(存在类型库是完成此操作的必要条件。)

因此,要将 ADO 对象类型导入到 .NET,您需要按如下方式操作:

tlbimp.exe msado15.dll

msado15.dll 中包含对象的整个 ADO 层次结构,该文件通常安装在 c:/program files/common files/system/ado 文件夹中。在这种情况下,TLBIMP 在当前文件夹中创建一个名为 adodb.dll 的文件。除非您指定一个输出文件名,否则该实用程序将使用库的名称。您可以在命令行中使用 /out:name 开关设置输出名称。

如果您使用 Visual Studio .NET 来生成 .NET 应用程序,您甚至不需要了解 TLBIMP。在这种情况下,在解决方案资源管理器中右键单击“引用”节点,并从提供的已注册的 COM 组件列表中选取 ADO 库即可。

在完成此操作后,就可以在 .NET 代码中将 ADO 对象作为本机类使用。对于从 SQL Server 表提取某些记录并通过列表视图对它们进行显示的典型 Visual Basic 应用程序,现在可以使用 C# 进行重写,如下所示:

String conn = "PROVIDER=SQLOLEDB;INITIAL CATALOG=Northwind;" + 
              "SERVER=localhost;UID=sa;PWD=;";
String cmd = "SELECT firstname, lastname FROM Employees";

ADODB.Recordset adoRS = new ADODB.Recordset();
adoRS.Open(cmd, conn, ADODB.CursorTypeEnum.adOpenForwardOnly,
      ADODB.LockTypeEnum.adLockReadOnly, 0);
         
while (!adoRS.EOF) {
   listView1.ListItems.Add(adoRS.Fields["lastname"].Value + 
         ", " + 
         adoRS.Fields["firstname"].Value);
         adoRS.MoveNext();         
}

此处的关键在于,在代码需要新的 ADODB.Recordset 对象实例时,会发生什么情况。您在下面看到的 Windows 窗体应用程序是一个 .NET 客户端,表面上看来该客户端是在创建一个 ADO 记录集 COM 对象实例。然而,在内部所发生的情况却略有不同。

data02222001-fig1.gif

图 1. 使用 ADO 提取数据的 Windows 窗体应用程序

客户端仍然与一个常规 .NET 类通信,该类称为运行库可调用包装类 (RCW),其工作方式就像原始 Recordset 对象一样。在创建 RCW 类时,它立即实例化目标组件。然后,RCW 类的工作方式就像未托管组件的某种代理一样。

未托管对象与其 .NET 版本类具有一对一的关系。不同 COM 组件实例是通过不同 RCW 类管理的,但没有使用新的 RCW 对相同实例进行额外的引用。

RCW 基础结构负责在托管代码和非托管代码之间封送方法参数和返回值。当然,仅当 COM 和 .NET 中的数据表示形式不同时,才会进行这种类型的转换。例如,BSTR 变量必须变为字符串变量,反之亦然。

COM 和 .NET 在很多方面是不同的,这些方面包括异常处理、内存管理、函数标识和线程处理等等。RCW 层必须以某种方式隐藏所有这些差异,以使连接的每一端(RCW 类和 COM 对象)看到它知道如何使用的编程接口和环境。

COM 客户端应该直接控制它们所实例化的对象的生命周期。相反,.NET 客户端知道系统垃圾回收器将随后清理内存。RCW 类(TLBIMP 在所生成的程序集中对其进行硬编码)是从知道如何处理此差异的基类继承的。

类似地,.NET 应用程序应该以线程安全的方式公开共享资源。而 COM 客户端应该知道服务器组件支持的线程模型。需要重申的是,RCW 类负责在正确类型的单元内实例化目标 COM 对象。

COM 对象通过 HRESULT 返回代码返回成功或失败,而 .NET 客户端从引发的异常了解到其调用出现了错误。RCW 则将其遇到的任何失败的 HRESULT 值都转换为 .NET 异常。(因此,应该避免使用通过 HRESULT 返回提示性信息内容的 COM 对象。)

现在我们应该清楚以下事实:从 .NET 客户端调用 ADO 对象是可行的,并且并不是特别费事。但是,每次从 .NET 上下文中调用 COM 服务器对象时,将在您的应用程序和实际对象之间不知不觉地插入大量代码。您与看不见的代理进行通信,该代理又进而询问 COM 对象,而使您看不到 COM 和 .NET 之间的结构差异。

代理给您造成快速而方便地进行通信的错觉。实际上,每次您调用它时,都要在波涛汹涌的水上搭建一座桥梁。计算此过程的实际工作量完全在于您自己,并且取决于您的项目。

这种系统开销只影响通信信道,可通过此信道在 .NET 客户端和 COM 组件之间传递请求和响应。如果 COM 组件又调用其他 COM 对象(例如,使用 ADO 或 ATL COM 使用者调用 OLE DB 提供程序的 Visual Basic 数据访问组件),则不需要进一步进行处理。

COM Interop 层的开销是由于在 .NET 岛和 COM 陆地之间搭建桥梁造成的。因此,您只支付一次全价。访问 ADO 的 .NET 客户端执行相同的操作,无论它是直接调用 ADO 对象模型,还是向下调用不同的数据访问组件。

在 .NET 中使用记录集

如果您使用 ADO,则最终要用到 Recordset 对象。但是,ADO.NET 中没有此类对象。这本身并不是什么问题,只要您知道正在做什么就行了,即,坚持使用一种过时的编程模型。

随着时间的推移,Recordset 对象发生了很大变化。最初,它只是 COM 版本的 ODBC resultset 而已,并增加了一些非常有用的功能(例如,书签、筛选和排序)。从 ADO 2.6 起,Recordset 支持流、XML 持久性、批处理更新、数据断开、手动构造和数据构形等等。

尽管提供了这么多功能,Recordset 并未提供处理多个数据表的功能,或者使用存储过程和自定义命令来批处理更新数据源。此外,Recordset 是一个 COM 对象,它很难与其他在非 Windows 平台上运行的模块进行交换。再者,如果您要将记录集与其他在基于 Windows 的平台上运行的不同模块进行交换,您必须在 COM 封送和类型转换层完成大量的工作。

为提高整个数据处理子系统的互操作性和可伸缩性,.NET 推出了一种以数据为中心的新数据模型,它与 ADO 和 OLE DB 以数据库为中心的标准模型相反。从以下三个重要变化就可以清楚地看到这一点:

将 ADO Recordset 的功能分成不同的且更加简单的对象。

引入了通用的数据容器对象,即DataSet

DataSet 对象中嵌入了 XML 数据表示形式,从基本上讲,就是合并了两种编程接口(关系型和分层型)。

套用爱因斯坦的话说,.NET 试图使数据访问尽可能简单(和轻便),但同时又具有足够高的可靠性和强大的功能以满足最苛刻的要求。与 ADO 相比,ADO.NET 的对象模型设计是一个重大的转变。ADO.NET 并不是像 Recordset 那样庞大且相当单一的对象,它是一组更简单、更加专用的对象。“专用与多功能性”就是软件在日常生活中遇到的另一个双重矛盾。

可以在 DataTable 对象中找到 .NET 版本的 Recordset 对象。即使 DataTable 仅实现了 Recordset 的基本功能(必须处理数据读取和写入的功能),这种说法也站得住脚。

在 .NET 中,目前的 ADO 代码使用的 Recordset 所遵循的原则不再有效。这意味着,很难将 Recordset 与典型 .NET 应用程序的其他元素集成在一起。例如,您不能使用 Recordset 填充 ASP.NET 或 Windows 窗体数据网格。

而您能做的就是将 Recordset 转换为 .NET 数据容器类。以下代码片段使用先前生成的 Recordset,并建立等效的 DataTable

DataTable dt = new DataTable("AdaptedFromRecordset");
dt.Columns.Add ("EmployeeName", System.Type.GetType("System.String"));
while (!adoRS.EOF) {
DataRow dr;
   dr = dt.NewRow();
   dr["EmployeeName"] = adoRS.Fields["lastname"].Value + 
", " + 
adoRS.Fields["firstname"].Value;

   dt.Rows.Add (dr); 
   adoRS.MoveNext();         
}
dataGrid1.DataSource = dt.DefaultView;

正如以下函数所显示的那样,可以将此代码方便地推广到任何记录集:

DataTable RecordsetToDataTable(ADODB.Recordset adoRS, String strTable)
{
// Assumes the recordset is open and moves on the first record
   adoRS.MoveFirst();
   DataTable dt = new DataTable(strTable);

   // Loops through the Recordset's fields
for(int i=0; i < adoRS.Fields.Count; i++) {
      String strColName = adoRS.Fields[i].Name;
   Type t = adoRS.Fields[i].Value.GetType();
   dt.Columns.Add (strColName, t);       
}

   // Loops through records and columns
   while (!adoRS.EOF) {
      DataRow dr = dt.NewRow();
      for(int i=0; i < adoRS.Fields.Count; i++) 
         dr[i] = adoRS.Fields[i].Value;
      
      dt.Rows.Add (dr); 
      adoRS.MoveNext();         
}

   // Leaves the recordset on the last record
   return dt;
}

该代码首先滚动 Recordset 字段集合,然后将列添加到新创建的 DataTable 对象中。新列保留了 ADO 字段的名称,并且系统给其指定了等效的 .NET 类型。

Type t = adoRS.Fields[i].Value.GetType();

注意,RCW 引擎对 RecordsetField 对象的原始接口进行了一定的修改。它添加了返回 .NET System.Type 对象的 GetType 方法。ADO Field 对象中没有此类方法。

下一步,该函数遍历记录并填充 DataTable 行集合。

您可以按以下方式使用此 DataTable 对象:

DataTable dt = RecordsetToDataTable(adoRS, "AdaptedFromRecordset");
dataGrid1.DataSource = dt.DefaultView;

如果您打算搭建一座桥梁,使现有 ADO 代码无缝地流入您的 .NET 应用程序中,则做好准备将这座桥梁向前延伸,从 ADO 对象一直连接到类似的 ADO.NET 对象。

使用函数来隐藏将 ADO 和 ADO.NET 对象无缝地集成在一起所需的额外代码简直就是面向对象的工作。一种更为完善的解决方案是,设置一种从 DataTable 继承并添加了两种新的构造函数的 AdoDataTable 类。此外:

public DataTable();
public DataTable(String);

它还具有以下优点:

public DataTable(ADODB.Recordset);
public DataTable(ADODB.Recordset, String);

前者将使用默认的表名称,而后者将使用指定的名称。该类的源代码类似于:

using System;
using System.Data;
public class AdoDataTable : System.Data.DataTable
{
public AdoDataTable(ADODB.Recordset adoRS)
   { RecordsetToDataTable(adoRS, "MyNewTable"); }

public AdoDataTable(ADODB.Recordset adoRS, String strTableName)   
{ RecordsetToDataTable(adoRS, strTableName);   }

private void RecordsetToDataTable(ADODB.Recordset adoRS, 
String strTable)
{
      // Assumes the recordset is open
   adoRS.MoveFirst();

      // Loops through the Recordset's fields
   for(int i=0; i < adoRS.Fields.Count; i++)   {
         String strColName = adoRS.Fields[i].Name;
         Type t = adoRS.Fields[i].Value.GetType();
      Columns.Add (strColName, t);       
      }
         
      // Loops through the Recordset's records to populate the DataTable
      while (!adoRS.EOF)   {
         DataRow dr;
         dr = NewRow();

         for(int i=0; i < adoRS.Fields.Count; i++)   
            dr[i] = adoRS.Fields[i].Value;
            
         Rows.Add (dr); 
         adoRS.MoveNext();         
      }

      // Leaves the recordset on the last record
   }
}

.NET 应用程序只需在项目中引用此类,并使用以下极其简单的代码便可获取与以前相同的结果:

AdoDataTable adt = new AdoDataTable(adoRS, "AdaptedFromRecordset"); 
dataGrid1.DataSource = adt.DefaultView;

在编写该类时,要在每种方法之前添加此特殊的注释:

/// <summary>
///    Comment here
/// </summary>

Visual Studio .NET 将使用此文本来提供免费的 IntelliSense 支持。

一般来说,Recordset 可帮助您逐步迁移到 .NET,但您越早迁移到 ADO.NET,您的迁移过程的效果就会越好。正如我在上一期专栏中所说的一样,一旦您选择了 .NET,您便没有两全的办法。要么保持系统不变,要么从头开始重新考虑该系统,并制订中期或长期的迁移计划。

服务器游标

从 Beta 1 起,ADO.NET 不再直接支持以下数据库编程功能:服务器游标。如果您需要在代码中使用服务器游标,则必须借助于 ADO 功能来实现。

ADO.NET 是设计用来满足大多数要求的。此原则要求小组将设计重点放在中断连接的数据访问和客户端游标上,而不是放在可伸缩性差的(但有时是必需的)服务器端游标上。

服务器游标始终需要打开的连接,它代表了源于过去客户机/服务器计算的设计方法。虽然现在仍存在许多只能使用服务器游标的应用程序,但基于 Web 的系统根本不需要它们。

因此,如果当前代码使用服务器游标,您应该怎么办呢?要做的第一件事就是,慎重考虑是否选择放弃动态的服务器端游标而使用静态的客户端游标,静态的客户端游标是 ADO.NET 编程接口中首选和推荐的游标。

如果您不能更改代码以使用客户端游标,请继续使用 ADO。

它是否会挥洒自如?

在 .NET 应用程序中使用 ADO 并不是非常困难的事。但是,这是一种短期方法,因为它破坏了 .NET 类的完整性。它使您(勇敢的 .NET 开发人员)被迫使用非常规的编程方法,更为重要的是,在将数据与编程接口的其他部分合并时,它可能会引发某些问题。要一劳永逸地解决这一问题,您现在可以做一些重新编写工作以期将来提供长期的 ADO.NET 收益。正如任何一般规则一样,总是会有一些例外情况。在这种情况下,服务器游标是最显著的一个。.NET 中的 ADO 代码可能像石头一样坚硬,但从设计的角度看,维护和代码过时也可能会使您的代码僵化死板。

Developer’s Network Journal 2001 年 2 月刊中刊登了另一篇很好的 ADO.NET 文章。要阅读这篇文章,请单击以下链接:http://www.dnjonline.com/articles/essentials/iss22_essentials.html

对话栏:您是否(真的)准备好进行迁移?

Dino,您好!感谢您提供了非常精彩的 .NET 迁移文章。但是,如果我即将开始一个新项目,我不知道是否来得及使用 .NET。

要牢记的四点是:

我将向我在 Microsoft 的联系人了解有关发行时间表的最新新闻。我并不在意像 Visual Studio .NET 之类的开发工具的可用性问题。我关心更多的是平台二元性问题和好的文档。在发行前三个月内进行准备就可以了,而不必在设计级别采取太多的预防措施。否则,我采取 50% 对 50% 的策略,因为您做两手准备总不会有什么损失。实际上,我在在适当的时间进行迁移中介绍了如何进行规划。

项目性质也是一个考虑事项。ASP.NET 与 Beta 2 很接近,我认为它在此时已非常可靠并且设计非常完善。我预计 API 不会发生很大的变化,而只是一些较小的更改和增加新的功能而已。当然,我预计在内存管理和总体性能方面还会有所提高。我认为 ADO.NET 也不会有什么变化。这包括简单的读取功能和更新。有关更复杂的需要,我只好等待 Beta 2 了。顺便提一下,预计 Beta 2 是RTM 之前的最终测试阶段。这应该给您提供了我做事情的思路:一半 ASP,一半 ASP.NET。

另一个考虑事项是最终期限 — 越循序渐进,效果越好。如果要我给上述问题做出一个二元性的解答(顺便说一下,这根本无关紧要)的话,我要说的是:“我还没有准备好使用 100% 纯粹、真正的 .NET 系统。”我刚刚将我的 Intranet 作为 ASP.NET 应用程序进行了重新编写,但与真实的系统相比,它看起来有点过于简单了。但是,您不费力气或方便地进行编码就可获取的功能达到的水平是非常令人吃惊的。如果将它与现实情况结合起来,那么,它具有的潜在优点无疑是会非常诱人和令人振奋的。我敢打赌,现在就迁移到 .NET 可赢得非常大的先机。我喜欢打赌,但我会确保了解尽可能多的游戏规则。

我的所有客户都对 .NET 情有独钟。虽然只有一个客户已采取实实在在的行动,但我们大家都在按照本文中所描述的原则稳步前行。总而言之,我认为从事研究工作并给您们提供正确的指导是一件令我非常开心的事情。这就是我现在正在做的事情,并且我建议您也这样做。

Dino EspositoWintellect 的 ADO.NET 专家兼培训教员和顾问,工作地点位于意大利的罗马。Dino 是 MSDN Magazine 的特约编辑,是 Cutting Edge 专栏的撰稿人。他还经常向 Developer Network Journal 和 MSDN News 投稿。Dino 是即将由 Microsoft Press 推出的《Building Web Solutions with ASP.NET and ADO.NET》一书的作者,也是 http://www.vb2themax.com/ 的创始人之一。如果希望与 Dino 联系,可发送电子邮件至 dinoe@wintellect.com

转入原英文页面

分享到:
评论

相关推荐

    scrapy练习 获取喜欢的书籍

    主要是根据网上大神做的 项目一 https://zhuanlan.zhihu.com/p/687522335

    基于PyTorch的Embedding和LSTM的自动写诗实验.zip

    基于PyTorch的Embedding和LSTM的自动写诗实验LSTM (Long Short-Term Memory) 是一种特殊的循环神经网络(RNN)架构,用于处理具有长期依赖关系的序列数据。传统的RNN在处理长序列时往往会遇到梯度消失或梯度爆炸的问题,导致无法有效地捕捉长期依赖。LSTM通过引入门控机制(Gating Mechanism)和记忆单元(Memory Cell)来克服这些问题。 以下是LSTM的基本结构和主要组件: 记忆单元(Memory Cell):记忆单元是LSTM的核心,用于存储长期信息。它像一个传送带一样,在整个链上运行,只有一些小的线性交互。信息很容易地在其上保持不变。 输入门(Input Gate):输入门决定了哪些新的信息会被加入到记忆单元中。它由当前时刻的输入和上一时刻的隐藏状态共同决定。 遗忘门(Forget Gate):遗忘门决定了哪些信息会从记忆单元中被丢弃或遗忘。它也由当前时刻的输入和上一时刻的隐藏状态共同决定。 输出门(Output Gate):输出门决定了哪些信息会从记忆单元中输出到当前时刻的隐藏状态中。同样地,它也由当前时刻的输入和上一时刻的隐藏状态共同决定。 LSTM的计算过程可以大致描述为: 通过遗忘门决定从记忆单元中丢弃哪些信息。 通过输入门决定哪些新的信息会被加入到记忆单元中。 更新记忆单元的状态。 通过输出门决定哪些信息会从记忆单元中输出到当前时刻的隐藏状态中。 由于LSTM能够有效地处理长期依赖关系,它在许多序列建模任务中都取得了很好的效果,如语音识别、文本生成、机器翻译、时序预测等。

    基于Java的云计算平台设计源码

    云计算平台设计源码:该项目基于Java开发,包含126个文件,主要使用Java、JavaScript、HTML和CSS语言。该项目是一个云计算平台,旨在为用户提供一个高效、灵活的云计算服务,包括资源管理、虚拟化技术、分布式存储等功能,以满足不同用户的计算和存储需求。

    grpcio-1.41.0-cp38-cp38-linux_armv7l.whl

    Python库是一组预先编写的代码模块,旨在帮助开发者实现特定的编程任务,无需从零开始编写代码。这些库可以包括各种功能,如数学运算、文件操作、数据分析和网络编程等。Python社区提供了大量的第三方库,如NumPy、Pandas和Requests,极大地丰富了Python的应用领域,从数据科学到Web开发。Python库的丰富性是Python成为最受欢迎的编程语言之一的关键原因之一。这些库不仅为初学者提供了快速入门的途径,而且为经验丰富的开发者提供了强大的工具,以高效率、高质量地完成复杂任务。例如,Matplotlib和Seaborn库在数据可视化领域内非常受欢迎,它们提供了广泛的工具和技术,可以创建高度定制化的图表和图形,帮助数据科学家和分析师在数据探索和结果展示中更有效地传达信息。

    grpcio-1.44.0-cp310-cp310-linux_armv7l.whl

    Python库是一组预先编写的代码模块,旨在帮助开发者实现特定的编程任务,无需从零开始编写代码。这些库可以包括各种功能,如数学运算、文件操作、数据分析和网络编程等。Python社区提供了大量的第三方库,如NumPy、Pandas和Requests,极大地丰富了Python的应用领域,从数据科学到Web开发。Python库的丰富性是Python成为最受欢迎的编程语言之一的关键原因之一。这些库不仅为初学者提供了快速入门的途径,而且为经验丰富的开发者提供了强大的工具,以高效率、高质量地完成复杂任务。例如,Matplotlib和Seaborn库在数据可视化领域内非常受欢迎,它们提供了广泛的工具和技术,可以创建高度定制化的图表和图形,帮助数据科学家和分析师在数据探索和结果展示中更有效地传达信息。

    基于MATLAB实现的手写数字的识别效率,用卷积神经网络算法来实现,能够显现百分之九十以上的识别率+使用说明文档

    CSDN IT狂飙上传的代码均可运行,功能ok的情况下才上传的,直接替换数据即可使用,小白也能轻松上手 【资源说明】 基于MATLAB实现的这个代码主要是研究手写数字的识别效率,用卷积神经网络算法来实现,用的是官方手写字体数据,能够显现百分之九十以上的识别率+使用说明文档 1、代码压缩包内容 主函数:main.m; 调用函数:其他m文件;无需运行 运行结果效果图; 2、代码运行版本 Matlab 2020b;若运行有误,根据提示GPT修改;若不会,私信博主(问题描述要详细); 3、运行操作步骤 步骤一:将所有文件放到Matlab的当前文件夹中; 步骤二:双击打开main.m文件; 步骤三:点击运行,等程序运行完得到结果; 4、仿真咨询 如需其他服务,可后台私信博主; 4.1 期刊或参考文献复现 4.2 Matlab程序定制 4.3 科研合作 功率谱估计: 故障诊断分析: 雷达通信:雷达LFM、MIMO、成像、定位、干扰、检测、信号分析、脉冲压缩 滤波估计:SOC估计 目标定位:WSN定位、滤波跟踪、目标定位 生物电信号:肌电信号EMG、脑电信号EEG、心电信号ECG 通信系统:DOA估计、编码译码、变分模态分解、管道泄漏、滤波器、数字信号处理+传输+分析+去噪、数字信号调制、误码率、信号估计、DTMF、信号检测识别融合、LEACH协议、信号检测、水声通信 5、欢迎下载,沟通交流,互相学习,共同进步!

    大学生毕业答辨ppt免费模板【不要积分】下载可编辑可用(110).zip

    大学生毕业答辨ppt免费模板【不要积分】下载可编辑可用(110).zip

    基于LSTM+CNN的自然语言处理,基于单维LSTM、多维LSTM时序预测算法和多元线性回归算法的预测模型.zip

    基于LSTM+CNN的自然语言处理,基于单维LSTM、多维LSTM时序预测算法和多元线性回归算法的预测模型LSTM (Long Short-Term Memory) 是一种特殊的循环神经网络(RNN)架构,用于处理具有长期依赖关系的序列数据。传统的RNN在处理长序列时往往会遇到梯度消失或梯度爆炸的问题,导致无法有效地捕捉长期依赖。LSTM通过引入门控机制(Gating Mechanism)和记忆单元(Memory Cell)来克服这些问题。 以下是LSTM的基本结构和主要组件: 记忆单元(Memory Cell):记忆单元是LSTM的核心,用于存储长期信息。它像一个传送带一样,在整个链上运行,只有一些小的线性交互。信息很容易地在其上保持不变。 输入门(Input Gate):输入门决定了哪些新的信息会被加入到记忆单元中。它由当前时刻的输入和上一时刻的隐藏状态共同决定。 遗忘门(Forget Gate):遗忘门决定了哪些信息会从记忆单元中被丢弃或遗忘。它也由当前时刻的输入和上一时刻的隐藏状态共同决定。 输出门(Output Gate):输出门决定了哪些信息会从记忆单元中输出到当前时刻的隐藏状态中。同样地,它也由当前时刻的输入和上一时刻的隐藏状态共同决定。 LSTM的计算过程可以大致描述为: 通过遗忘门决定从记忆单元中丢弃哪些信息。 通过输入门决定哪些新的信息会被加入到记忆单元中。 更新记忆单元的状态。 通过输出门决定哪些信息会从记忆单元中输出到当前时刻的隐藏状态中。 由于LSTM能够有效地处理长期依赖关系,它在许多序列建模任务中都取得了很好的效果,如语音识别、文本生成、机器翻译、时序预测等。

    基于MATLAB实现的自适应稳健波束形成对角加载算法,其与输入信噪比的关系+使用说明文档.zip

    CSDN IT狂飙上传的代码均可运行,功能ok的情况下才上传的,直接替换数据即可使用,小白也能轻松上手 【资源说明】 基于MATLAB实现的自适应稳健波束形成对角加载算法,其与输入信噪比的关系+使用说明文档.zip 1、代码压缩包内容 主函数:main.m; 调用函数:其他m文件;无需运行 运行结果效果图; 2、代码运行版本 Matlab 2020b;若运行有误,根据提示GPT修改;若不会,私信博主(问题描述要详细); 3、运行操作步骤 步骤一:将所有文件放到Matlab的当前文件夹中; 步骤二:双击打开main.m文件; 步骤三:点击运行,等程序运行完得到结果; 4、仿真咨询 如需其他服务,可后台私信博主; 4.1 期刊或参考文献复现 4.2 Matlab程序定制 4.3 科研合作 功率谱估计: 故障诊断分析: 雷达通信:雷达LFM、MIMO、成像、定位、干扰、检测、信号分析、脉冲压缩 滤波估计:SOC估计 目标定位:WSN定位、滤波跟踪、目标定位 生物电信号:肌电信号EMG、脑电信号EEG、心电信号ECG 通信系统:DOA估计、编码译码、变分模态分解、管道泄漏、滤波器、数字信号处理+传输+分析+去噪、数字信号调制、误码率、信号估计、DTMF、信号检测识别融合、LEACH协议、信号检测、水声通信 5、欢迎下载,沟通交流,互相学习,共同进步!

    Java_Springstartupanalyzer生成一个交互式的spring应用程序启动报告,让您了解是什么因素导.zip

    Java_Springstartupanalyzer生成一个交互式的spring应用程序启动报告,让您了解是什么因素导

    基于MATLAB实现的LTE链路层仿真程序,根据LTE标准协议实现的,很容易看懂+使用说明文档.rar

    CSDN IT狂飙上传的代码均可运行,功能ok的情况下才上传的,直接替换数据即可使用,小白也能轻松上手 【资源说明】 基于MATLAB实现的LTE链路层仿真程序,根据LTE标准协议实现的,很容易看懂+使用说明文档.rar 1、代码压缩包内容 主函数:main.m; 调用函数:其他m文件;无需运行 运行结果效果图; 2、代码运行版本 Matlab 2020b;若运行有误,根据提示GPT修改;若不会,私信博主(问题描述要详细); 3、运行操作步骤 步骤一:将所有文件放到Matlab的当前文件夹中; 步骤二:双击打开main.m文件; 步骤三:点击运行,等程序运行完得到结果; 4、仿真咨询 如需其他服务,可后台私信博主; 4.1 期刊或参考文献复现 4.2 Matlab程序定制 4.3 科研合作 功率谱估计: 故障诊断分析: 雷达通信:雷达LFM、MIMO、成像、定位、干扰、检测、信号分析、脉冲压缩 滤波估计:SOC估计 目标定位:WSN定位、滤波跟踪、目标定位 生物电信号:肌电信号EMG、脑电信号EEG、心电信号ECG 通信系统:DOA估计、编码译码、变分模态分解、管道泄漏、滤波器、数字信号处理+传输+分析+去噪、数字信号调制、误码率、信号估计、DTMF、信号检测识别融合、LEACH协议、信号检测、水声通信 5、欢迎下载,沟通交流,互相学习,共同进步!

    中国轨道交通连接器行业市场规模测算逻辑模型 头豹词条报告系列-14页.pdf.zip

    中国轨道交通连接器行业市场规模测算逻辑模型 头豹词条报告系列-14页.pdf.zip

    重点白酒品牌价格跟踪飞天整箱散瓶微跌梦之蓝企稳回升-12页.pdf.zip

    重点白酒品牌价格跟踪飞天整箱散瓶微跌梦之蓝企稳回升-12页.pdf.zip

    grpcio-1.47.0-cp36-cp36m-linux_armv7l.whl

    Python库是一组预先编写的代码模块,旨在帮助开发者实现特定的编程任务,无需从零开始编写代码。这些库可以包括各种功能,如数学运算、文件操作、数据分析和网络编程等。Python社区提供了大量的第三方库,如NumPy、Pandas和Requests,极大地丰富了Python的应用领域,从数据科学到Web开发。Python库的丰富性是Python成为最受欢迎的编程语言之一的关键原因之一。这些库不仅为初学者提供了快速入门的途径,而且为经验丰富的开发者提供了强大的工具,以高效率、高质量地完成复杂任务。例如,Matplotlib和Seaborn库在数据可视化领域内非常受欢迎,它们提供了广泛的工具和技术,可以创建高度定制化的图表和图形,帮助数据科学家和分析师在数据探索和结果展示中更有效地传达信息。

    有色能源金属行业周报本周锂盐价格继续下跌锂价企稳关键在于下游需求-25页.pdf.zip

    有色能源金属行业周报本周锂盐价格继续下跌锂价企稳关键在于下游需求-25页.pdf.zip

    有色基本金属行业周报美失业率增长而薪资增速放缓令加息有望暂停消费端发力或将带动铜铝价格-19页.pdf.zip

    有色基本金属行业周报美失业率增长而薪资增速放缓令加息有望暂停消费端发力或将带动铜铝价格-19页.pdf

    grpcio-1.48.2-cp310-cp310-manylinux_2_17_aarch64.whl

    Python库是一组预先编写的代码模块,旨在帮助开发者实现特定的编程任务,无需从零开始编写代码。这些库可以包括各种功能,如数学运算、文件操作、数据分析和网络编程等。Python社区提供了大量的第三方库,如NumPy、Pandas和Requests,极大地丰富了Python的应用领域,从数据科学到Web开发。Python库的丰富性是Python成为最受欢迎的编程语言之一的关键原因之一。这些库不仅为初学者提供了快速入门的途径,而且为经验丰富的开发者提供了强大的工具,以高效率、高质量地完成复杂任务。例如,Matplotlib和Seaborn库在数据可视化领域内非常受欢迎,它们提供了广泛的工具和技术,可以创建高度定制化的图表和图形,帮助数据科学家和分析师在数据探索和结果展示中更有效地传达信息。

    203365707854574CDR22和23和2024通用教程.zip

    203365707854574CDR22和23和2024通用教程.zip

    堆排序 Java代码示例

    附件是堆排序Java代码示例,文件绿色安全,请大家放心下载,仅供交流学习使用,无任何商业目的! 堆排序是一种高效的比较类排序算法,它利用了二叉堆的数据结构来实现排序。堆排序可以分为两个主要步骤:建堆(将无序的元素构建成一个堆)和排序(利用堆的性质进行排序)。 代码首先定义了一个HeapSort类,其中包含了sort方法用于执行堆排序,heapify方法用于维护堆的性质。main方法用于测试堆排序算法,它创建了一个整数数组并调用sort方法对其进行排序,最后打印出排序后的数组。

    USB转TTL CH340驱动程序win7 蓝德控制器线刷驱动

    USB转TTL CH340驱动程序win7 蓝德控制器线刷驱动

Global site tag (gtag.js) - Google Analytics