我在理解介面中的通用方法時遇到問題。我正在使用帶有自動 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;
}
現在一些類從介面繼承:
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;
}
}
現在我有一些從 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:識別符號預期
CS1003:語法錯誤,'>'預期
CS1003:語法錯誤,'('預期
我正在使用 Visual Studio 社區 2022
當我使用 Int32 而不是 int 時,一切正常,它幾乎解決了我的問題,但是型別 float(這對我來說是必需的)沒有 Float 表示。
我沒有解決這個問題的想法了。有人可以向我解釋嗎?
uj5u.com熱心網友回復:
也許嘗試將介面更改為泛型,這樣泛型型別參考被限制為相同型別,而不僅僅是任意型別:
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 必須相同,因此對于InputRegister_int所有 T 都是 a re now int。
從語法的角度來看,請注意這些方法的原型上沒有后綴,這是因為它們根本不是泛型方法,它們專門針對創建實體時指定的相同型別引數進行型別化。
如果您確實有這樣的方法:
Nullable<T> Read<T>() where T: struct;
然后即使是InputRegister_int類,我們也可以通過任何型別的結構傳遞給該方法并期望它回傳值,以下內容在運行時應該是有效的:
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允許您在需要時對來自客戶端的回應進行特定的值和型別檢查,這有助于指導開發人員以后做出合理的決定。
uj5u.com熱心網友回復:
該答案專門針對“Int32”與int部分問題。
Int32在代碼中用作“this works”的示例實際上并不是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>(...)。
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/426087.html
