INT32和INT之间的通用方法差异

发布于 2025-01-25 07:35:55 字数 1334 浏览 3 评论 0原文

我在接口中理解通用方法时有问题。我将.NET Framework 4.8与自动C#版本一起使用,因此应该是C#7.3。下面的示例

接口是:

public interface IRegister
{
  Nullable<T> Read<T>() where T: struct;
  void Write<T>(T value) where T : struct;
}

现在一些从接口继承的类:

public abstract class AbstractRegister : IRegister
{
  protected ModbusClient client;
  protected int Address;
  public abstract Nullable<T> Read<T>() where T : struct;
  public virtual void Write<T>(T value) where T : struct
  {
    return;
  }
  public AbstractRegister(int address, ModbusClient client)
  {
    this.client = client;
    this.Address = address;
  }
}

现在我有一些从asstractregister继承的类:

class InputRegister_int : AbstractRegister
{
  public InputRegister_int(int address, ModbusClient client) : base(address, client) { }

  public override int? Read<int>()
  {
    if (client == null)
      return null;
    return this.client.ReadInputRegisters(this.Address, 1)[0] as int?;
  }
}

public public offride int中?读取&lt; int&gt;()我有错误:

CS1001:预期标识符
CS1003:语法错误,'&gt;'预期
CS1003:语法错误,'('预期

我正在使用Visual Studio Community 2022

当我使用INT32而代替INT时,一切正常,它几乎可以解决我的问题,但是键入float(对我来说是必要的),没有float 。

我对解决这个问题的想法没有

I have problem with understanding generic method in interface. I'm using .NET framework 4.8 with auto C# version so it should be C# 7.3. Example below

Interface is:

public interface IRegister
{
  Nullable<T> Read<T>() where T: struct;
  void Write<T>(T value) where T : struct;
}

Now some class inherit from interface:

public abstract class AbstractRegister : IRegister
{
  protected ModbusClient client;
  protected int Address;
  public abstract Nullable<T> Read<T>() where T : struct;
  public virtual void Write<T>(T value) where T : struct
  {
    return;
  }
  public AbstractRegister(int address, ModbusClient client)
  {
    this.client = client;
    this.Address = address;
  }
}

Now I have some class inherited from AbstractRegister:

class InputRegister_int : AbstractRegister
{
  public InputRegister_int(int address, ModbusClient client) : base(address, client) { }

  public override int? Read<int>()
  {
    if (client == null)
      return null;
    return this.client.ReadInputRegisters(this.Address, 1)[0] as int?;
  }
}

and in line public override int? Read<int>() I have errors:

CS1001: Identifier expected
CS1003: Syntax error, '>' expected
CS1003: Syntax error, '(' expected

I'm using Visual Studio Community 2022

When I use Int32 instead int, everything works ok, and it almost resolve my problem, but type float (which is necessary for me) doesn't have Float representation.

I have no ideas for solving this problem anymore. Can someone explain it to me?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

小嗲 2025-02-01 07:35:55

也许尝试将界面更改为通用,这样,通用类型的引用被限制为相同类型的类型,而不仅仅是任意任何类型:

public interface IRegister<T> 
    where T : struct
{
    Nullable<T> Read();
    void Write(T value);
}

public abstract class AbstractRegister<T> : IRegister<T>
    where T : struct
{
    protected ModbusClient client;
    protected int Address;
    public abstract Nullable<T> Read();
    public virtual void Write(T value)
    {
        return;
    }
    public AbstractRegister(int address, ModbusClient client)
    {
        this.client = client;
        this.Address = address;
    }
}

class InputRegister_int : AbstractRegister<int>
{
    public InputRegister_int(int address, ModbusClient client) : base(address, client) { }

    public override int? Read()
    {
        if (client == null)
          return null;
          return this.client.ReadInputRegisters(this.Address, 1)[0] as int?;
    }
}

class InputRegister_float : AbstractRegister<float>
{
    public InputRegister_float(int address, ModbusClient client) : base(address, client) { }

    public override float? Read()
    {
        if (client == null)
          return null;
          return this.client.ReadInputRegisters(this.Address, 1)[0] as float?;
    }
}

此处的功能差异是在类级别指定通用类型,基本类中的所有T都必须相同,因此对于inputegrregister_int所有T a a a a re re re Now re Now re Now re now code> int int < /代码>。

从语法的角度来看,请注意,该方法没有其原型上的后缀,这是因为它们根本不是通用方法,它们被专门键入相同的类型参数时指定的时创建了实例。

如果您确实有这样的方法:

Nullable<T> Read<T>() where T: struct;

即使到inputregister_int类,我们可以通过 任何 struct类型的struct类型,并期望它返回值,以下值期望在运行时有效:

var intRegister = new InputRegister_int();
int intValue = intRegister.Read<int>();
DateTime dtValue = intRegister.Read<DateTime>();

如果您确实希望您的寄存器是任何任意类型,那么我们真的不需要摘要注册:

public class GenericRegister : IRegister
{
    protected ModbusClient client;
    protected int Address;
    public virtual Nullable<T> Read<T>() where T : struct
    {
        if (client == null)
            return null;
            return this.client.ReadInputRegisters(this.Address, 1)[0] as T?;        
    }
    public virtual void Write<T>(T value) where T : struct
    {
        // TODO: implement generic write logic
        return;
    }
    public AbstractRegister(int address, ModbusClient client)
    {
        this.client = client;
        this.Address = address;
    }
}

但是这导致了非常懒惰的实现,modbus寄存器中的值类型不会改变,大多数固定在硬件实现中,但是PLC中的内部逻辑会为您避免使用类型。您的固定类型inputRegister_int允许您在需要时进行特定值并输入访问响应的检查,并有助于指导开发人员以后做出合理的决定。

Perhaps try changing the interface to being generic, that way the generic type references are constrained to being of the same type, and not just arbitrarily any type:

public interface IRegister<T> 
    where T : struct
{
    Nullable<T> Read();
    void Write(T value);
}

public abstract class AbstractRegister<T> : IRegister<T>
    where T : struct
{
    protected ModbusClient client;
    protected int Address;
    public abstract Nullable<T> Read();
    public virtual void Write(T value)
    {
        return;
    }
    public AbstractRegister(int address, ModbusClient client)
    {
        this.client = client;
        this.Address = address;
    }
}

class InputRegister_int : AbstractRegister<int>
{
    public InputRegister_int(int address, ModbusClient client) : base(address, client) { }

    public override int? Read()
    {
        if (client == null)
          return null;
          return this.client.ReadInputRegisters(this.Address, 1)[0] as int?;
    }
}

class InputRegister_float : AbstractRegister<float>
{
    public InputRegister_float(int address, ModbusClient client) : base(address, client) { }

    public override float? Read()
    {
        if (client == null)
          return null;
          return this.client.ReadInputRegisters(this.Address, 1)[0] as float?;
    }
}

The functional difference here is that specifying the generic type at the class level, all of the T's in the base class MUST be the same so for InputRegister_int all the T's a re now int.

From a syntax perspective, notice that the methods DO NOT have the suffix on their prototypes, this is because they are not generic methods at all, they are specifically typed to the same type parameter that was specified when the instance was created.

If you did have a method like this:

Nullable<T> Read<T>() where T: struct;

Then even to the InputRegister_int class we could pass through ANY type of struct to that method and expect it to return the value, the following would be expected to be valid at runtime:

var intRegister = new InputRegister_int();
int intValue = intRegister.Read<int>();
DateTime dtValue = intRegister.Read<DateTime>();

If you really do want your register to be any arbitrary type, then we don't really need an abstract register at all:

public class GenericRegister : IRegister
{
    protected ModbusClient client;
    protected int Address;
    public virtual Nullable<T> Read<T>() where T : struct
    {
        if (client == null)
            return null;
            return this.client.ReadInputRegisters(this.Address, 1)[0] as T?;        
    }
    public virtual void Write<T>(T value) where T : struct
    {
        // TODO: implement generic write logic
        return;
    }
    public AbstractRegister(int address, ModbusClient client)
    {
        this.client = client;
        this.Address = address;
    }
}

However this leads to a very lazy implementation, the types of the values in your ModBus registers are not going to change, most are fixed to hardware implementations but the internal logic in the PLC will contrain the types for you. Your fixed type InputRegister_int allows you do to specific value and type checking on the response from the client when you need to and it helps guide the developers to make reasonable decisions later.

只是偏爱你 2025-02-01 07:35:55

此答案是关于“ int32”与int的一部分问题的专门的。

int32在代码中用作“此作品”的示例实际上不是system.int32(这正是int is),而只是只是的名称恰好匹配某些系统类型的名称。

下面的代码显示了更简单的示例 - 您可以看到“ int32”的行为与其他不是类型名称的字符串完全相同。

using System;
public class SomeClass {

    // exactly the same as T X<T>(), just using `Int32` as type parameter name
    Int32 X<Int32>() { return default(Int32); } 
    
    // fails to compile as `System.Int32` and `int` are concrete types
    System.Int32 Y<System.Int32>() { return default(System.Int32); } 
    int X<int>() { return default(int); } 
}

通用方法中类型参数的常规名称以t开始(只有t或以其为前缀 - tresult),但是C#中有规则实施这一点的规范。结果,只要在正确的位置中使用void m&lt; nothythatisnottype&gt;(...),任何不现有类型名称的任何现有类型名称被视为“类型参数的名称”。

This answer is specifically about "Int32" vs. int part of the question.

Int32 used in the code as example of "this works" is not actually System.Int32 (which is exactly what int is) but rather just a name that happen to match name of some system type.

Code below shows simpler example of this - you can see that "Int32" behaves exactly as any other string that is not a type name.

using System;
public class SomeClass {

    // exactly the same as T X<T>(), just using `Int32` as type parameter name
    Int32 X<Int32>() { return default(Int32); } 
    
    // fails to compile as `System.Int32` and `int` are concrete types
    System.Int32 Y<System.Int32>() { return default(System.Int32); } 
    int X<int>() { return default(int); } 
}

Conventionally name of the type parameter in generic method starts with T (just T or prefixed with it - TResult), but there is rule in C# specification that enforces that. As result anything that is not existing type name is considered "name of the type parameter" as long as it is used in the right place void M<AnythingThatIsNotType>(...) .

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文