Int32 和 int 之间的泛型方法区别
Generic method difference between Int32 and int
我无法理解接口中的泛型方法。我正在使用带有自动 C# 版本的 .NET 框架 4.8,因此它应该是 C# 7.3。下面的例子
接口是:
public interface IRegister
{
Nullable<T> Read<T>() where T: struct;
void Write<T>(T value) where T : struct;
}
现在一些class继承自接口:
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;
}
}
现在我有一些 class 继承自 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?;
}
}
在行 public override int? Read<int>()
我有错误:
CS1001: Identifier expected
CS1003: Syntax error, '>' expected
CS1003: Syntax error, '(' expected
我正在使用 Visual Studio 社区 2022
当我使用 Int32 而不是 int 时,一切正常,它几乎解决了我的问题,但是 float 类型(这对我来说是必需的)没有 Float 表示。
我没有解决这个问题的想法了。有人可以给我解释一下吗?
也许尝试将接口更改为泛型,这样泛型类型引用就被限制为 相同 类型,而不是任意 any 类型:
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?;
}
}
这里的功能区别在于,在 class 级别指定 通用类型 ,基础 class 中的所有 T 必须相同所以 InputRegister_int
所有的 T 现在都是 int
.
从语法的角度来看,请注意这些方法的原型上没有后缀,这是因为它们根本不是泛型方法,它们被专门指定为相同的类型参数 创建实例时指定的。
如果你有这样的方法:
Nullable<T> Read<T>() where T: struct;
然后甚至 InputRegister_int
class 我们可以通过 ANY 类型的结构传递给该方法并期望它 return值,以下内容预计在运行时有效:
var intRegister = new InputRegister_int();
int intValue = intRegister.Read<int>();
DateTime dtValue = intRegister.Read<DateTime>();
如果你真的希望你的寄存器是 any 任意类型,那么我们根本不需要 abstract 寄存器:
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
允许您在需要时对来自客户端的响应进行特定值和类型检查,这有助于指导开发人员稍后做出合理的决定。
这个答案专门针对“Int32”与问题的 int
部分。
Int32
在代码中用作“这个作品”的例子实际上并不是 System.Int32
(这正是 int
是什么)而只是 恰好匹配某种系统类型的名称。
下面的代码显示了更简单的示例 - 您可以看到“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<AnythingThatIsNotType>(...)
.
我无法理解接口中的泛型方法。我正在使用带有自动 C# 版本的 .NET 框架 4.8,因此它应该是 C# 7.3。下面的例子
接口是:
public interface IRegister
{
Nullable<T> Read<T>() where T: struct;
void Write<T>(T value) where T : struct;
}
现在一些class继承自接口:
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;
}
}
现在我有一些 class 继承自 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?;
}
}
在行 public override int? Read<int>()
我有错误:
CS1001: Identifier expected
CS1003: Syntax error, '>' expected
CS1003: Syntax error, '(' expected
我正在使用 Visual Studio 社区 2022
当我使用 Int32 而不是 int 时,一切正常,它几乎解决了我的问题,但是 float 类型(这对我来说是必需的)没有 Float 表示。
我没有解决这个问题的想法了。有人可以给我解释一下吗?
也许尝试将接口更改为泛型,这样泛型类型引用就被限制为 相同 类型,而不是任意 any 类型:
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?;
}
}
这里的功能区别在于,在 class 级别指定 通用类型 ,基础 class 中的所有 T 必须相同所以 InputRegister_int
所有的 T 现在都是 int
.
从语法的角度来看,请注意这些方法的原型上没有后缀,这是因为它们根本不是泛型方法,它们被专门指定为相同的类型参数 创建实例时指定的。
如果你有这样的方法:
Nullable<T> Read<T>() where T: struct;
然后甚至 InputRegister_int
class 我们可以通过 ANY 类型的结构传递给该方法并期望它 return值,以下内容预计在运行时有效:
var intRegister = new InputRegister_int();
int intValue = intRegister.Read<int>();
DateTime dtValue = intRegister.Read<DateTime>();
如果你真的希望你的寄存器是 any 任意类型,那么我们根本不需要 abstract 寄存器:
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
允许您在需要时对来自客户端的响应进行特定值和类型检查,这有助于指导开发人员稍后做出合理的决定。
这个答案专门针对“Int32”与问题的 int
部分。
Int32
在代码中用作“这个作品”的例子实际上并不是 System.Int32
(这正是 int
是什么)而只是 恰好匹配某种系统类型的名称。
下面的代码显示了更简单的示例 - 您可以看到“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<AnythingThatIsNotType>(...)
.