C# 当存在默认构造函数时,没有默认构造函数错误

C# 当存在默认构造函数时,没有默认构造函数错误,c#,fakeiteasy,C#,Fakeiteasy,编辑:将公开生产代码!希望没有人窃取我的秘密 我有一个控制器类,用于使用Modbus协议通过TCP与设备通信。我使用NModbus库 以下是控制器类实现的接口: public interface CoilReader { bool[] Read(ushort startAddress, ushort numberOfCoils); } public interface CoilWriter { void WriteSingle(ushort address, bool valu

编辑:将公开生产代码!希望没有人窃取我的秘密

我有一个控制器类,用于使用Modbus协议通过TCP与设备通信。我使用NModbus库

以下是控制器类实现的接口:

public interface CoilReader
{
    bool[] Read(ushort startAddress, ushort numberOfCoils);
}

public interface CoilWriter
{
    void WriteSingle(ushort address, bool value);

    void WriteMultiple(ushort startAddress, bool[] values);
}

public interface HoldingRegisterReader
{
    ushort[] Read(ushort startAddress, ushort numberOfRegisters);
}

public interface HoldingRegisterWriter
{
    void WriteSingle(ushort address, ushort value);

    void WriteMultiple(ushort startAddress, ushort[] values);
}

public interface InputReader
{
    bool[] Read(ushort startAddress, ushort numberOfCoils);
}

public interface InputRegisterReader
{
    ushort[] Read(ushort startAddress, ushort numberOfRegisters);
}

public interface ConnectionInfo
{
    string IP { get; set; }
}
这是控制器类

using System;
using System.Net.Sockets;
using System.Reflection;
using global::Modbus.Device;

public class Controller
    : ConnectionInfo,
      HoldingRegisterReader,
      InputRegisterReader,
      CoilReader,
      InputReader,
      CoilWriter,
      HoldingRegisterWriter
{
    static Controller()
    {
        AppDomain.CurrentDomain.AssemblyResolve += (sender, e) => loadEmbeddedAssembly(e.Name);
    }

    public virtual string IP
    {
        get
        {
            return this.ip;
        }

        set
        {
            this.ip = value;
        }
    }

    public virtual ushort[] ReadHoldingRegisters(ushort startAddress, ushort numberOfRegisters)
    {
        using (var connection = this.createDeviceConnection())
        {
            return connection.ReadHoldingRegisters(startAddress, numberOfRegisters);
        }
    }

    public virtual ushort[] ReadInputRegisters(ushort startAddress, ushort numberOfRegisters)
    {
        using (var connection = this.createDeviceConnection())
        {
            return connection.ReadInputRegisters(startAddress, numberOfRegisters);
        }
    }

    public virtual bool[] ReadCoils(ushort startAddress, ushort numberOfCoils)
    {
        using (var connection = this.createDeviceConnection())
        {
            return connection.ReadCoils(startAddress, numberOfCoils);
        }
    }

    public virtual bool[] ReadInputs(ushort startAddress, ushort numberOfInputs)
    {
        using (var connection = this.createDeviceConnection())
        {
            return connection.ReadInputs(startAddress, numberOfInputs);
        }
    }

    public virtual void WriteSingleCoil(ushort address, bool value)
    {
        using (var connection = this.createDeviceConnection())
        {
            connection.WriteSingleCoil(address, value);
        }
    }

    public virtual void WriteMultipleCoils(ushort startAddress, bool[] values)
    {
        using (var connection = this.createDeviceConnection())
        {
            connection.WriteMultipleCoils(startAddress, values);
        }
    }

    public virtual void WriteSingleHoldingRegister(ushort address, ushort value)
    {
        using (var connection = this.createDeviceConnection())
        {
            connection.WriteSingleRegister(address, value);
        }
    }

    public virtual void WriteMultipleHoldingRegisters(ushort startAddress, ushort[] values)
    {
        using (var connection = this.createDeviceConnection())
        {
            connection.WriteMultipleRegisters(startAddress, values);
        }
    }

    string ConnectionInfo.IP
    {
        get
        {
            return this.IP;
        }

        set
        {
            this.IP = value;
        }
    }

    ushort[] HoldingRegisterReader.Read(ushort startAddress, ushort numberOfRegisters)
    {
        return this.ReadHoldingRegisters(startAddress, numberOfRegisters);
    }

    ushort[] InputRegisterReader.Read(ushort startAddress, ushort numberOfRegisters)
    {
        return this.ReadInputRegisters(startAddress, numberOfRegisters);
    }

    bool[] CoilReader.Read(ushort startAddress, ushort numberOfCoils)
    {
        return this.ReadCoils(startAddress, numberOfCoils);
    }

    bool[] InputReader.Read(ushort startAddress, ushort numberOfInputs)
    {
        return this.ReadInputs(startAddress, numberOfInputs);
    }

    void CoilWriter.WriteSingle(ushort address, bool value)
    {
        this.WriteSingleCoil(address, value);
    }

    void CoilWriter.WriteMultiple(ushort startAddress, bool[] values)
    {
        this.WriteMultipleCoils(startAddress, values);
    }

    void HoldingRegisterWriter.WriteSingle(ushort address, ushort value)
    {
        this.WriteSingleHoldingRegister(address, value);
    }

    void HoldingRegisterWriter.WriteMultiple(ushort startAddress, ushort[] values)
    {
        this.WriteMultipleHoldingRegisters(startAddress, values);
    }

    private ModbusIpMaster createDeviceConnection()
    {
        const int port = 502;
        var client = new TcpClient();
        client.BeginConnect(this.ip, port, null, null).AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(2));
        if (!client.Connected)
        {
            throw new Exception("Cannot connect to " + this.ip + ":" + port);
        }

        return ModbusIpMaster.CreateIp(client);
    }

    private static Assembly loadEmbeddedAssembly(string name)
    {
        if (name.EndsWith("Retargetable=Yes"))
        {
            return Assembly.Load(new AssemblyName(name));
        }

        var container = Assembly.GetExecutingAssembly();
        var path = new AssemblyName(name).Name + ".dll";

        using (var stream = container.GetManifestResourceStream(path))
        {
            if (stream == null)
            {
                return null;
            }

            var bytes = new byte[stream.Length];
            stream.Read(bytes, 0, bytes.Length);
            return Assembly.Load(bytes);
        }
    }

    private string ip;
}
在与包含此类及其接口的库相同的解决方案中,在测试项目中创建的测试不会导致以下错误。但是,在使用库的不同解决方案中的项目中,我得到以下结果:

------ Test started: Assembly: CareControls.IvisHmi.Tests.dll ------

Unknown .NET Framework Version: v4.5.1
Test 'CareControls.IvisHmi.Tests.Presenters.ModbusTcpTogglePresenterTests.FactMethodName' failed:     FakeItEasy.Core.FakeCreationException : 
Failed to create fake of type "CareControls.Modbus.Tcp.Controller".

Below is a list of reasons for failure per attempted constructor:
  No constructor arguments failed:
    No default constructor was found on the type CareControls.Modbus.Tcp.Controller.

If either the type or constructor is internal, try adding the following attribute to the assembly:
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]


at FakeItEasy.Core.DefaultExceptionThrower.ThrowFailedToGenerateProxyWithResolvedConstructors(Type typeOfFake, String reasonForFailureOfUnspecifiedConstructor, IEnumerable`1 resolvedConstructors)
at FakeItEasy.Creation.FakeObjectCreator.TryCreateFakeWithDummyArgumentsForConstructor(Type typeOfFake, FakeOptions fakeOptions, IDummyValueCreationSession session, String failReasonForDefaultConstructor, Boolean throwOnFailure)
at FakeItEasy.Creation.FakeObjectCreator.CreateFake(Type typeOfFake, FakeOptions fakeOptions, IDummyValueCreationSession session, Boolean throwOnFailure)
at FakeItEasy.Creation.DefaultFakeAndDummyManager.CreateFake(Type typeOfFake, FakeOptions options)
at FakeItEasy.Creation.DefaultFakeCreatorFacade.CreateFake[T](Action`1 options)
at FakeItEasy.A.Fake[T]()
Presenters\ModbusTcpTogglePresenterTests.cs(22,0): at CareControls.IvisHmi.Tests.Presenters.ModbusTcpTogglePresenterTests.FactMethodName()

0 passed, 1 failed, 0 skipped, took 0.93 seconds (xUnit.net 1.9.2 build 1705).
这就是测试:

namespace CareControls.IvisHmi.Tests.Presenters
{
    using CareControls.IvisHmi.Framework;
    using CareControls.IvisHmi.Presenters;
    using CareControls.IvisHmi.UI;
    using CareControls.Modbus.Tcp;
    using FakeItEasy;
    using Ploeh.AutoFixture;
    using Xunit;

    public class ModbusTcpTogglePresenterTests
    {
        [Fact]
        public void FactMethodName()
        {
            A.Fake<Controller>();
        }
    }
}
据此:

存在一个错误,可能会给出错误的异常消息。他们说,在这种情况下,仍然应该有一些东西导致抛出异常

我建议:

  • 添加显式默认构造函数是否有帮助
  • 你能正常地成功实例化这个类吗

  • 您能否使用反射或
    Activator.CreateInstance
    成功实例化该类
    • 根据这一点:

      存在一个错误,可能会给出错误的异常消息。他们说,在这种情况下,仍然应该有一些东西导致抛出异常

      我建议:

      • 添加显式默认构造函数是否有帮助
      • 你能正常地成功实例化这个类吗

      • 您能否使用反射或
        Activator.CreateInstance
        成功实例化该类

        • 静态构造函数与公共构造函数不同。您确定编译器在定义静态构造函数时会生成默认的公共构造函数吗?我没想到你两个都能得到。如果你去的话它会出现吗


          静态构造函数很可能被称为“惰性”,因此当FakeiTesy试图通过反射类型来创建一个伪构造函数时,静态构造函数还没有被调用。这可以解释为什么在创建伪构造函数之前实例化类型时它会工作。

          静态构造函数与公共构造函数不同。您确定编译器在定义静态构造函数时会生成默认的公共构造函数吗?我没想到你两个都能得到。如果你去的话它会出现吗


          静态构造函数很可能被称为“惰性”,因此当FakeiTesy试图通过反射类型来创建一个伪构造函数时,静态构造函数还没有被调用。这将解释为什么在创建伪代码之前实例化类型时它会起作用。

          为了总结Sam Pearson使用Fakeitesy 1.18.0以及MSDN文档收集的信息,当无法加载
          Modbus
          程序集时引发异常。这很有趣,因为
          控制器的静态构造函数包含处理此故障的代码,所以它一定没有被执行。静态构造函数被称为

          …在创建第一个实例或引用任何静态成员之前自动初始化类

          然而,Fakeetisy并不是故意做这两件事的。 看起来DynamicProxy也没有

          我的猜测是,访问该类以使其可以伪造会触发Modbus程序集加载,而不会触发静态构造函数

          但是,Fakeitesy的程序集扫描可能会触发程序集加载。
          这可以通过添加一个伪造其他内容的测试来检查,比如
          ICollection
          ,然后运行该测试。
          如果错误仍然发生,则是目录扫描在执行此操作。在这种情况下,您可以使用Fakeitesy 1.18.0中添加的新引导程序来禁用目录扫描。 我们还没有官方文件,因为有一个,但我确实发布了。如果Fakeitesy的扫描触发了加载,并且禁用扫描会将程序集加载延迟到调用静态构造函数之后,那么这可能是最容易做到的事情

          其他可能的解决办法:

        • 首先实例化
          控制器
          是一种解决方法(如前所述)
        • 伪造
          控制器
          实现的众多接口中的一个(或全部),而不是伪造
          控制器
          (我个人的偏好是伪造接口,而不是类,但有时需要)
        • 如果可能的话,也许最好是解决程序集加载失败的原因,但我打赌如果这是一个选项,静态构造函数将不会包含它所包含的代码

        • 为了总结Sam Pearson使用Fakeetisy 1.18.0以及MSDN文档收集的信息,问题源于当无法加载
          Modbus
          程序集时引发的异常。这很有趣,因为
          控制器的静态构造函数包含处理此故障的代码,所以它一定没有被执行。静态构造函数被称为

          …在创建第一个实例或引用任何静态成员之前自动初始化类

          然而,Fakeetisy并不是故意做这两件事的。 看起来DynamicProxy也没有

          我的猜测是,访问该类以使其可以伪造会触发Modbus程序集加载,而不会触发静态构造函数

          但是,Fakeitesy的程序集扫描可能会触发程序集加载。
          这可以通过添加一个伪造其他内容的测试来检查,比如
          ICollection
          ,然后运行该测试。
          如果错误仍然发生,则是目录扫描在执行此操作。在这种情况下,您可以使用Fakeitesy 1.18.0中添加的新引导程序来禁用目录扫描。 我们还没有官方文件,因为有一个,但我确实发布了。如果Fakeitesy的扫描触发加载,并禁用扫描定义
          namespace CareControls.IvisHmi.Tests.Presenters
          {
              using CareControls.IvisHmi.Framework;
              using CareControls.IvisHmi.Presenters;
              using CareControls.IvisHmi.UI;
              using CareControls.Modbus.Tcp;
              using FakeItEasy;
              using Ploeh.AutoFixture;
              using Xunit;
          
              public class ModbusTcpTogglePresenterTests
              {
                  [Fact]
                  public void FactMethodName()
                  {
                      new Controller();
                      A.Fake<Controller>();
                  }
              }
          }
          
          // ---------------------------------------------------------------------------------------------------------------------
          // <copyright file="NModbusDeviceConnection.cs" company="Care Controls">
          //   Copyright (c) Care Controls Inc. All rights reserved.
          // </copyright>
          // ---------------------------------------------------------------------------------------------------------------------
          
          namespace CareControls.Modbus.Tcp.Internal
          {
              using System;
              using System.Net.Sockets;
              using System.Reflection;
              using global::Modbus.Device;
          
              internal sealed class NModbusDeviceConnection : IDisposable
              {
                  static NModbusDeviceConnection()
                  {
                      AppDomain.CurrentDomain.AssemblyResolve += (sender, e) => loadEmbeddedAssembly(e.Name);
                  }
          
                  public NModbusDeviceConnection(string ip)
                  {
                      const int port = 502;
                      var client = new TcpClient();
                      client.BeginConnect(ip, port, null, null).AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(2));
                      if (!client.Connected)
                      {
                          throw new Exception("Cannot connect to " + ip + ":" + port);
                      }
          
                      this.connection = ModbusIpMaster.CreateIp(client);
                  }
          
                  public ushort[] ReadHoldingRegisters(ushort startAddress, ushort numberOfRegisters)
                  {
                      return this.connection.ReadHoldingRegisters(startAddress, numberOfRegisters);
                  }
          
                  public ushort[] ReadInputRegisters(ushort startAddress, ushort numberOfRegisters)
                  {
                      return this.connection.ReadInputRegisters(startAddress, numberOfRegisters);
                  }
          
                  public bool[] ReadCoils(ushort startAddress, ushort numberOfCoils)
                  {
                      return this.connection.ReadCoils(startAddress, numberOfCoils);
                  }
          
                  public bool[] ReadInputs(ushort startAddress, ushort numberOfInputs)
                  {
                      return this.connection.ReadInputs(startAddress, numberOfInputs);
                  }
          
                  public void WriteSingleCoil(ushort address, bool value)
                  {
                      this.connection.WriteSingleCoil(address, value);
                  }
          
                  public void WriteMultipleCoils(ushort startAddress, bool[] values)
                  {
                      this.connection.WriteMultipleCoils(startAddress, values);
                  }
          
                  public void WriteSingleHoldingRegister(ushort address, ushort value)
                  {
                      this.connection.WriteSingleRegister(address, value);
                  }
          
                  public void WriteMultipleHoldingRegisters(ushort address, ushort[] values)
                  {
                      this.connection.WriteMultipleRegisters(address, values);
                  }
          
                  public void Dispose()
                  {
                      if (this.connection != null)
                      {
                          this.connection.Dispose();
                      }
                  }
          
                  private static Assembly loadEmbeddedAssembly(string name)
                  {
                      if (name.EndsWith("Retargetable=Yes"))
                      {
                          return Assembly.Load(new AssemblyName(name));
                      }
          
                      var container = Assembly.GetExecutingAssembly();
                      var path = new AssemblyName(name).Name + ".dll";
          
                      using (var stream = container.GetManifestResourceStream(path))
                      {
                          if (stream == null)
                          {
                              return null;
                          }
          
                          var bytes = new byte[stream.Length];
                          stream.Read(bytes, 0, bytes.Length);
                          return Assembly.Load(bytes);
                      }
                  }
          
                  private readonly ModbusIpMaster connection;
              }
          }
          
          // ---------------------------------------------------------------------------------------------------------------------
          // <copyright file="Controller.cs" company="Care Controls">
          //   Copyright (c) Care Controls Inc. All rights reserved.
          // </copyright>
          // ---------------------------------------------------------------------------------------------------------------------
          
          namespace CareControls.Modbus.Tcp
          {
              using System;
              using CareControls.Modbus.Tcp.Internal;
          
              public class Controller
                  : ConnectionInfo,
                    HoldingRegisterReader,
                    InputRegisterReader,
                    CoilReader,
                    InputReader,
                    CoilWriter,
                    HoldingRegisterWriter
              {
                  public Controller()
                  {
                      this.newDeviceConnection = () => new NModbusDeviceConnection(this.IP);
                  }
          
                  public virtual string IP { get; set; }
          
                  public virtual ushort[] ReadHoldingRegisters(ushort startAddress, ushort numberOfRegisters)
                  {
                      using (var connection = this.newDeviceConnection())
                      {
                          return connection.ReadHoldingRegisters(startAddress, numberOfRegisters);
                      }
                  }
          
                  public virtual ushort[] ReadInputRegisters(ushort startAddress, ushort numberOfRegisters)
                  {
                      using (var connection = this.newDeviceConnection())
                      {
                          return connection.ReadInputRegisters(startAddress, numberOfRegisters);
                      }
                  }
          
                  public virtual bool[] ReadCoils(ushort startAddress, ushort numberOfCoils)
                  {
                      using (var connection = this.newDeviceConnection())
                      {
                          return connection.ReadCoils(startAddress, numberOfCoils);
                      }
                  }
          
                  public virtual bool[] ReadInputs(ushort startAddress, ushort numberOfInputs)
                  {
                      using (var connection = this.newDeviceConnection())
                      {
                          return connection.ReadInputs(startAddress, numberOfInputs);
                      }
                  }
          
                  public virtual void WriteSingleCoil(ushort address, bool value)
                  {
                      using (var connection = this.newDeviceConnection())
                      {
                          connection.WriteSingleCoil(address, value);
                      }
                  }
          
                  public virtual void WriteMultipleCoils(ushort startAddress, bool[] values)
                  {
                      using (var connection = this.newDeviceConnection())
                      {
                          connection.WriteMultipleCoils(startAddress, values);
                      }
                  }
          
                  public virtual void WriteSingleHoldingRegister(ushort address, ushort value)
                  {
                      using (var connection = this.newDeviceConnection())
                      {
                          connection.WriteSingleHoldingRegister(address, value);
                      }
                  }
          
                  public virtual void WriteMultipleHoldingRegisters(ushort startAddress, ushort[] values)
                  {
                      using (var connection = this.newDeviceConnection())
                      {
                          connection.WriteMultipleHoldingRegisters(startAddress, values);
                      }
                  }
          
                  string ConnectionInfo.IP
                  {
                      get
                      {
                          return this.IP;
                      }
          
                      set
                      {
                          this.IP = value;
                      }
                  }
          
                  ushort[] HoldingRegisterReader.Read(ushort startAddress, ushort numberOfRegisters)
                  {
                      return this.ReadHoldingRegisters(startAddress, numberOfRegisters);
                  }
          
                  ushort[] InputRegisterReader.Read(ushort startAddress, ushort numberOfRegisters)
                  {
                      return this.ReadInputRegisters(startAddress, numberOfRegisters);
                  }
          
                  bool[] CoilReader.Read(ushort startAddress, ushort numberOfCoils)
                  {
                      return this.ReadCoils(startAddress, numberOfCoils);
                  }
          
                  bool[] InputReader.Read(ushort startAddress, ushort numberOfInputs)
                  {
                      return this.ReadInputs(startAddress, numberOfInputs);
                  }
          
                  void CoilWriter.WriteSingle(ushort address, bool value)
                  {
                      this.WriteSingleCoil(address, value);
                  }
          
                  void CoilWriter.WriteMultiple(ushort startAddress, bool[] values)
                  {
                      this.WriteMultipleCoils(startAddress, values);
                  }
          
                  void HoldingRegisterWriter.WriteSingle(ushort address, ushort value)
                  {
                      this.WriteSingleHoldingRegister(address, value);
                  }
          
                  void HoldingRegisterWriter.WriteMultiple(ushort startAddress, ushort[] values)
                  {
                      this.WriteMultipleHoldingRegisters(startAddress, values);
                  }
          
                  private readonly Func<NModbusDeviceConnection> newDeviceConnection;
              }
          }