.NET:从第三方组件对象序列化到一个文件(使硒的webdriver的更快)更快、第三方、组件、对象

2023-09-04 02:11:04 作者:神经质的小阔耐

的最终目标序列化FirefoxDriver(我的问题在这里)=使得webdriver的更快!

下面是介绍如何序列化对象的链接。但是,它需要你ISerializable的实施为要序列化对象。我想要做的是序列化一个对象,我没有界定 - 基于一类的第三方组件(从项目引用)一个对象,它是不实施了ISerializable 。那可能吗?如何才能做到这一点?

的http://www.switchonthe$c$c.com/tutorials/csharp-tutorial-serialize-objects-to-a-file

属性(IWebDriver =接口类型):

 私人IWebDriver驱动程序;
 

对象实例(FireFoxDriver是一个类类型):

 驱动程序=新FirefoxDriver(firefoxProfile);
 

=====

答案后,

2012/3/21更新发布

为什么会这样抛出一个错误?它不喜欢这一行:

  serializedObject.DriverInstance =(FirefoxDriver)驱动程序;
 
.NET面向对象基础

...

错误:

 无法隐式转换类型'OpenQA.Selenium.IWebDriver'到'OpenQA.Selenium.Firefox.FirefoxDriver。一个显式转换存在(是否缺少强制转换?)
 

下面是code:

  FirefoxDriverSerialized serializedObject =新FirefoxDriverSerialized();
    串行器串行=新的串行器();
    serializedObject = serializer.DeSerializeObject(@C:\ firefoxDriver.qa);
    司机= serializedObject.DriverInstance;

    如果(司机== NULL)
    {
        驱动程序=新FirefoxDriver(firefoxProfile);
        serializedObject.DriverInstance =(FirefoxDriverSerialized)驱动程序;
        serializer.SerializeObject(@C:\ firefoxDriver.qa,serializedObject);
    }
 

下面是两种串行班我建:

 公共类串行器
{
   公共串行器()
   {
   }

   公共无效SerializeObject(字符串文件名,FirefoxDriverSerialized objectToSerialize)
   {
      流流= File.open方法(文件名,FileMode.Create);
      BinaryFormatter的bFormatter =新的BinaryFormatter();
      bFormatter.Serialize(流objectToSerialize);
      stream.Close();
   }

   公共FirefoxDriverSerialized DeSerializeObject(字符串文件名)
   {
      FirefoxDriverSerialized objectToSerialize;
      流流= File.open方法(文件名,FileMode.Open);
      BinaryFormatter的bFormatter =新的BinaryFormatter();
      objectToSerialize =(FirefoxDriverSerialized)bFormatter.Deserialize(流);
      stream.Close();
      返回objectToSerialize;
   }
}

[序列化()]
公共类FirefoxDriverSerialized:FirefoxDriver,ISerializable的
{
    私人FirefoxDriver driverInstance;
    公共FirefoxDriver DriverInstance
    {
        {返回this.driverInstance; }
        集合{this.driverInstance =价值; }
    }

    公共FirefoxDriverSerialized()
    {
    }

    公共FirefoxDriverSerialized(SerializationInfo中的信息,的StreamingContext ctxt)
    {
        this.driverInstance =(FirefoxDriver)info.GetValue(DriverInstance的typeof(FirefoxDriver));
    }

    公共无效GetObjectData使用(SerializationInfo中的信息,的StreamingContext ctxt)
    {
        info.AddValue(DriverInstance,this.driverInstance);
    }
}
 

=================

2012/3/23更新#2 - 固定的序列化/反序列化,但有另一个问题

这个固定的调用code。因为我们删除* .qa文件时,我们调用WebDriver.Quit(),因为,当我们选择了关闭浏览器。这将杀死我们的缓存驱动器为好。因此,如果我们从一个新的浏览器窗口中,我们会打catch块,并创建一个新的实例,并把它保存到我们的* .qa文件(在序列化形式)。

  FirefoxDriverSerialized serializedObject =新FirefoxDriverSerialized();
    串行器串行=新的串行器();

    尝试
    {
        serializedObject = serializer.DeSerializeObject(@C:\ firefoxDriver.qa);
        司机= serializedObject.DriverInstance;
    }
    抓住
    {
        驱动程序=新FirefoxDriver(firefoxProfile);
        serializedObject =新FirefoxDriverSerialized();
        serializedObject.DriverInstance =(FirefoxDriver)驱动程序;
        serializer.SerializeObject(@C:\ firefoxDriver.qa,serializedObject);
    }
 

不过,仍然收到此异常:

  Acu.QA.Main.Test_0055_GiftCertificate_UserCheckout:
设置:System.Runtime.Serialization.SerializationException:键入OpenQA.Selenium.Firefox.FirefoxDriver汇编webdriver的,版本= 2.16.0.0,文化=中性公钥= 1c2bd1631853048f'未标记为可序列化。
TearDown中:System.NullReferenceException:对象不设置到对象的实例。
 

在此code座第三行是抛出异常:

 公共无效SerializeObject(字符串文件名,FirefoxDriverSerialized objectToSerialize)
   {
      流流= File.open方法(文件名,FileMode.Create);
      BinaryFormatter的bFormatter =新的BinaryFormatter();
      bFormatter.Serialize(流objectToSerialize); //< ===这条线
      stream.Close();
   }
 

====================

更新#3 - 2012年3月24日 - 简化FirefoxDriver通过不通过任何构造函数实例。我会让它更通过传递FirefoxProfile到构造后复杂。我仍然得到同样的例外,更新#2。

调用code:

  FirefoxDriverSerialized serializedObject =新FirefoxDriverSerialized();
串行器串行=新的串行器();
尝试
{
    serializedObject = serializer.DeSerializeObject(@C:\ firefoxDriver.qa);
    司机= serializedObject.DriverInstance;
}
抓住
{
    //驱动程序=新FirefoxDriver(firefoxProfile);
    驱动程序=新FirefoxDriver();
    serializedObject.DriverInstance =(FirefoxDriver)驱动程序;
    serializer.SerializeObject(@C:\ firefoxDriver.qa,serializedObject);
}
 

也不得不加上:基地()我的构造函数在我的序列化对象类:

  [序列化()]
公共类FirefoxDriverSerialized:FirefoxDriver,ISerializable的
{
    私人FirefoxDriver driverInstance;
    公共FirefoxDriver DriverInstance
    {
        {返回this.driverInstance; }
        集合{this.driverInstance =价值; }
    }

    公共FirefoxDriverSerialized():基地()
    {
    }

    公共FirefoxDriverSerialized(SerializationInfo中的信息,的StreamingContext ctxt)
    {
        this.driverInstance =(FirefoxDriver)info.GetValue(DriverInstance的typeof(FirefoxDriver));
    }

    公共无效GetObjectData使用(SerializationInfo中的信息,的StreamingContext ctxt)
    {
        info.AddValue(DriverInstance,this.driverInstance);
    }
}
 

=============

更新#4 - 只记录存根签名OpenQA.Selenium.Firefox.FirefoxDriver类

 使用OpenQA.Selenium;
使用OpenQA.Selenium.Remote;
使用系统;

命名空间OpenQA.Selenium.Firefox
{
    公共类FirefoxDriver:RemoteWebDriver,ITakesScreenshot
    {
        //类的数据成员

        //公共静态只读布尔AcceptUntrustedCertificates;
        //公共静态只读字符串BinaryCapabilityName;
        //公共静态只读布尔DefaultEnableNativeEvents;
        //公共静态只读INT DefaultPort;
        //公共静态只读字符串ProfileCapabilityName;

        // CONSTRUCTORS

        //公共FirefoxDriver();
        //公共FirefoxDriver(FirefoxProfile个人资料);
        //公共FirefoxDriver(ICapabilities能力);
        //公共FirefoxDriver(FirefoxBinary二进制,FirefoxProfile简介);
        //公共FirefoxDriver(FirefoxBinary二进制,FirefoxProfile个人资料,时间跨度的CommandTimeout);

        //性能

        保护FirefoxBinary二进制{获得; }
        保护FirefoxProfile简介{获得; }

        //方法

        //保护覆盖RemoteWebElement的createElement(字符串elementId);
        //公众截图GetScreenshot();
        //保护无效prepareEnvironment();
        //保护覆盖无效StartClient();
        //保护覆盖无效StopClient();
    }
}
 

解决方案

要序列化和序列化的自定义创建自己的自定义对象派生自 ISerializable的和对象目的。这种特殊的例子就不会工作,如果第三方对象是密封(有它仍然可以使用 ISerializable的使用其他方式)。

每秒更新请求

更新每题更新

 公共类MyFirefoxDriver:FirefoxDriver,ISerializable的
{
  公共MyFirefoxDriver(小于接口/类> firefoxProfile)
    :基地(firefoxProfile)
  {
  }

  无效GetObjectData使用(SerializationInfo中的信息,的StreamingContext上下文)
  {
    //属性需要被序列化
    info.AddValue(SomeProperty,base.SomeProperty);
  }
}
 

更新2

您新的code是混淆了我。我想,你正在寻找。

  serializedObject = serializer.DeSerializeObject(@C:\ firefoxDriver.qa);
司机= serializedObject;
 

这是因为 FirefoxDriverSerialized FireFoxDriver

更新3

需要注意的是构造不叫当一个对象进行反序列化的是非常重要的。这意味着,在构造函数中设置的东西,通常constucted /不会在反序列化,这通常会导致一个的NullReferenceException 。围绕这个问题的方法是实施 ISerializable的,并明确地设置为工作(无论是GetObjectData使用和特殊解串器的构造函数)所需的类的对象。如果有问题的对象的理解并不简单这可能是最困难的,也没有,如果我们没有它的源代码。

的重要的是,你需要同时实现GetObjectData使用作为重要的是要强调以及当ISerializable的被加入到一类特殊的构造。编译器会警告你,如果GetObjectData使用是失踪,但因为它是无法执行构造函数的执行,没有任何警告将给予如果构造不存在,当试图反序列化类没有异常将被抛出构造函数。的

 公共类的MyObject
{
  公众为MyObject()
  {
    this.SomeOtherObject =新MyObject2();
  }
  公共字符串名称{;组; }
  公共MyObject2 SomeOtherObject {获得;组; }
}

公共类MyObjectSerializable:MyObject来,ISerializable的
{
  保护MyObjectSerializable(SerializationInfo中SI,的StreamingContext上下文)
  {
    //基地()反序列化过程中不会被调用
    //所以使用特殊ISerializable的构造函数来设置对象的值
    //为什么不将它添加到si.AddValue?
    //因为,最有可能在这个问题上,它不是一个[序列化]对象任
    //所以我们要区别对待它,以及
    this.SomeOtherObject =新MyObject2();
  }

  公众覆盖无效GetObjectData使用(SerializationInfo中SI,的StreamingContext上下文)
  {
    si.AddValue(姓名,姓名);
  }
}
 

End Goal for serializing FirefoxDriver (my question here) = making WebDriver faster!!

Below is a link that describes how to serialize an object. But it requires you implement from ISerializable for the object you are serializing. What I'd like to do is serialize an object that I did not define--an object based on a class in a 3rd party assembly (from a project reference) that is not implementing ISerializable. Is that possible? How can this be done?

http://www.switchonthecode.com/tutorials/csharp-tutorial-serialize-objects-to-a-file

Property (IWebDriver = interface type):

private IWebDriver driver;

Object Instance (FireFoxDriver is a class type):

driver = new FirefoxDriver(firefoxProfile);

================

3/21/2012 update after answer posted

Why would this throw an error? It doesn't like this line:

serializedObject.DriverInstance = (FirefoxDriver)driver;

...

Error:

Cannot implicitly convert type 'OpenQA.Selenium.IWebDriver' to 'OpenQA.Selenium.Firefox.FirefoxDriver'. An explicit conversion exists (are you missing a cast?)

Here is the code:

    FirefoxDriverSerialized serializedObject = new FirefoxDriverSerialized();
    Serializer serializer = new Serializer();
    serializedObject = serializer.DeSerializeObject(@"C:\firefoxDriver.qa");
    driver = serializedObject.DriverInstance;

    if (driver == null)
    {
        driver = new FirefoxDriver(firefoxProfile);
        serializedObject.DriverInstance = (FirefoxDriverSerialized)driver;
        serializer.SerializeObject(@"C:\firefoxDriver.qa", serializedObject);
    }

Here are the two Serializer classes I built:

public class Serializer
{
   public Serializer()
   {
   }

   public void SerializeObject(string filename, FirefoxDriverSerialized objectToSerialize)
   {
      Stream stream = File.Open(filename, FileMode.Create);
      BinaryFormatter bFormatter = new BinaryFormatter();
      bFormatter.Serialize(stream, objectToSerialize);
      stream.Close();
   }

   public FirefoxDriverSerialized DeSerializeObject(string filename)
   {
      FirefoxDriverSerialized objectToSerialize;
      Stream stream = File.Open(filename, FileMode.Open);
      BinaryFormatter bFormatter = new BinaryFormatter();
      objectToSerialize = (FirefoxDriverSerialized)bFormatter.Deserialize(stream);
      stream.Close();
      return objectToSerialize;
   }
}

[Serializable()]
public class FirefoxDriverSerialized : FirefoxDriver, ISerializable
{
    private FirefoxDriver driverInstance;
    public FirefoxDriver DriverInstance
    {
        get { return this.driverInstance; }
        set { this.driverInstance = value; }
    }

    public FirefoxDriverSerialized()
    {
    }

    public FirefoxDriverSerialized(SerializationInfo info, StreamingContext ctxt)
    {
        this.driverInstance = (FirefoxDriver)info.GetValue("DriverInstance", typeof(FirefoxDriver));
    }

    public void GetObjectData(SerializationInfo info, StreamingContext ctxt)
    {
        info.AddValue("DriverInstance", this.driverInstance);
    }
}

=================

3/23/2012 update #2 - fixed serialization/de-serialization, but having another issue

This fixed the calling code. Because we're deleting the *.qa file when we call the WebDriver.Quit() because that's when we chose to close the browser. This will kill off our cached driver as well. So if we start with a new browser window, we'll hit the catch block and create a new instance and save it to our *.qa file (in the serialized form).

    FirefoxDriverSerialized serializedObject = new FirefoxDriverSerialized();
    Serializer serializer = new Serializer();

    try
    {
        serializedObject = serializer.DeSerializeObject(@"C:\firefoxDriver.qa");
        driver = serializedObject.DriverInstance;
    }
    catch
    {
        driver = new FirefoxDriver(firefoxProfile);
        serializedObject = new FirefoxDriverSerialized();
        serializedObject.DriverInstance = (FirefoxDriver)driver;
        serializer.SerializeObject(@"C:\firefoxDriver.qa", serializedObject);
    }

However, still getting this exception:

Acu.QA.Main.Test_0055_GiftCertificate_UserCheckout:
SetUp : System.Runtime.Serialization.SerializationException : Type 'OpenQA.Selenium.Firefox.FirefoxDriver' in Assembly 'WebDriver, Version=2.16.0.0, Culture=neutral, PublicKeyToken=1c2bd1631853048f' is not marked as serializable.
TearDown : System.NullReferenceException : Object reference not set to an instance of an object.

The 3rd line in this code block is throwing the exception:

   public void SerializeObject(string filename, FirefoxDriverSerialized objectToSerialize)
   {
      Stream stream = File.Open(filename, FileMode.Create);
      BinaryFormatter bFormatter = new BinaryFormatter();
      bFormatter.Serialize(stream, objectToSerialize);  // <=== this line 
      stream.Close();
   }

====================

update #3 - 3/24/2012 - simplified FirefoxDriver instance by not passing anything to the constructor. I'll make it more complex later by passing in FirefoxProfile into the constructor. I still get the same exception as update #2.

Calling code:

FirefoxDriverSerialized serializedObject = new FirefoxDriverSerialized();
Serializer serializer = new Serializer();
try
{
    serializedObject = serializer.DeSerializeObject(@"C:\firefoxDriver.qa");
    driver = serializedObject.DriverInstance;
}
catch
{
    //driver = new FirefoxDriver(firefoxProfile);
    driver = new FirefoxDriver();
    serializedObject.DriverInstance = (FirefoxDriver)driver;
    serializer.SerializeObject(@"C:\firefoxDriver.qa", serializedObject);
}

Also had to add ": base()" to my constructor in my serialized object class:

[Serializable()]
public class FirefoxDriverSerialized : FirefoxDriver, ISerializable
{
    private FirefoxDriver driverInstance;
    public FirefoxDriver DriverInstance
    {
        get { return this.driverInstance; }
        set { this.driverInstance = value; }
    }

    public FirefoxDriverSerialized() : base()
    {
    }

    public FirefoxDriverSerialized(SerializationInfo info, StreamingContext ctxt)
    {
        this.driverInstance = (FirefoxDriver)info.GetValue("DriverInstance", typeof(FirefoxDriver));
    }

    public void GetObjectData(SerializationInfo info, StreamingContext ctxt)
    {
        info.AddValue("DriverInstance", this.driverInstance);
    }
}

=============

Update #4 - just documenting stub signatures for OpenQA.Selenium.Firefox.FirefoxDriver class

using OpenQA.Selenium;
using OpenQA.Selenium.Remote;
using System;

namespace OpenQA.Selenium.Firefox
{
    public class FirefoxDriver : RemoteWebDriver, ITakesScreenshot
    {
        // CLASS DATA MEMBERS 

        //public static readonly bool AcceptUntrustedCertificates;
        //public static readonly string BinaryCapabilityName;
        //public static readonly bool DefaultEnableNativeEvents;
        //public static readonly int DefaultPort;
        //public static readonly string ProfileCapabilityName;

        // CONSTRUCTORS

        //public FirefoxDriver();
        //public FirefoxDriver(FirefoxProfile profile);
        //public FirefoxDriver(ICapabilities capabilities);
        //public FirefoxDriver(FirefoxBinary binary, FirefoxProfile profile);
        //public FirefoxDriver(FirefoxBinary binary, FirefoxProfile profile, TimeSpan commandTimeout);

        // PROPERTIES

        protected FirefoxBinary Binary { get; }
        protected FirefoxProfile Profile { get; }

        // METHODS

        //protected override RemoteWebElement CreateElement(string elementId);
        //public Screenshot GetScreenshot();
        //protected void PrepareEnvironment();
        //protected override void StartClient();
        //protected override void StopClient();
    }
}

解决方案

Create your own custom object that derives from ISerializable and the Object you want to serialize and serialize that custom object. This specific example won't work if the 3rd Party object is Sealed (there are other ways which can still be used with ISerializable).

Updated Per Request

Updated Per Question Update

public class MyFirefoxDriver : FirefoxDriver, ISerializable
{
  public MyFirefoxDriver(<Interface/Class> firefoxProfile)
    :base(firefoxProfile)
  {
  }

  void GetObjectData(SerializationInfo info, StreamingContext context)
  {
    // Properties needing to be serialized
    info.AddValue("SomeProperty", base.SomeProperty);
  }
}

Update 2

Your new code is confusing me. I think you're looking for..

serializedObject = serializer.DeSerializeObject(@"C:\firefoxDriver.qa");
driver = serializedObject;

This is because FirefoxDriverSerialized is a FireFoxDriver.

Update 3

It is important to note that constructors are not called when an object is deserialized. This means that things that are normally constucted/set in the constructor won't be upon deserialization, which usually results in a NullReferenceException. The way around that is to implement ISerializable and explicity set the objects needed for the class to work (both for GetObjectData and the special deserializer constructor). This can be most difficult if the understanding of the object in question is not simple nor if we don't have the source for it.

It is important to stress that you need to implement both GetObjectData as well as the special constructor when ISerializable is added to a class. The compiler will warn you if GetObjectData is missing, but since it is impossible to enforce the implementation of a constructor, no warnings will be given if the constructor is absent and an exception will be thrown when an attempt is made to deserialize a class without the constructor.

public class MyObject
{
  public MyObject()
  {
    this.SomeOtherObject = new MyObject2();
  }
  public string Name { get; set; }
  public MyObject2 SomeOtherObject { get; set; }
}

public class MyObjectSerializable : MyObject, ISerializable
{
  protected MyObjectSerializable(SerializationInfo si, StreamingContext context) 
  {
    // base() is never called during deserialization
    // so use the special ISerializable constructor to set the value of the object
    // why not add it to the si.AddValue?
    // because, most likely in this question, it is not a [Serializable] object either
    // so we have to treat it differently as well
    this.SomeOtherObject = new MyObject2();
  }

  public override void GetObjectData(SerializationInfo si, StreamingContext context)
  {
    si.AddValue("Name", Name);
  }
}