簡體   English   中英

在通用 c# 類中鏈接隱式運算符

[英]Chaining implicit operators in generic c# classes

對於以下通用 c# class,我想將 T 轉換為 K:

public abstract class ValueType<T,K> : IValueType<T> where K : ValueType<T,K>,new()
{     
    public abstract T Value { get; set; }     

    public static implicit operator ValueType<T,K>(T val) 
    {         
        K k = new K();
        k.Value = val;
        return k;    
    }
}

如果我要實現直接運算符implicit operator K(T val) ,它將導致編譯時錯誤 (CS0556)。

我想我可以嘗試鏈接隱式運算符:

public static implicit operator K(ValueType<T,K> vt){
    return (K)val;
}

但是下面的例子仍然抱怨無法轉換:

public class Test : ValueType<int, Test>
{
    public override int Value{ get; set; }
}

Test t = 6; //complains it's unable to be converted
Console.WriteLine(t.Value);

如果可能的話,我真的想避免顯式轉換。

這個問題延伸到我之前提出的另一個 SO 問題

實現自己的隱式轉換邏輯的規則非常嚴格,如果您要進行此類特別復雜的操作,則應該熟悉本規范的6.4.4和10.10.3節。

簡要地說,您應該了解一些關鍵規則:

  • 您定義轉換所用的類型必須出現在用戶定義的轉換的“到”或“從”部分中。 您不能創建定義從E到F的轉換的C類; C必須在某個地方。
  • 永遠不可能用您自己的一個替換內置的隱式轉換。 例如,當您從C轉換為對象時,就無法發生特殊行為。
  • 用戶定義的隱式轉換將與最多兩個內置的隱式轉換“鏈接”,但不能與任何其他用戶定義的轉換“鏈接”。 因此,例如,如果您具有從C到D的用戶定義的隱式轉換,以及從D到IFoo的內置隱式轉換,那么您將獲得從C到IFoo的隱式轉換。 但是,如果D具有用戶定義的到E的隱式轉換,那么您就不會免費獲得從C到E的隱式轉換。

強制轉換未通過編譯器鏈接,因此無法解決問題。

隱式轉換在類型檢查中非常嚴格。 如果編譯器知道類型,則第一個代碼段和Test都可以工作:

ValueType<int, Test> t = 6;
Console.WriteLine(t.Value);

問題是,從類型系統的角度來看,您的ValueType<int, Test>並不總是Test ,因此隱式轉換不適用於該類。

埃里克·利珀特(Eric Lippert)撰寫了一篇有關這種通用自引用的博客文章 -值得一讀!

據我所知,我認為您不能將演員表捆綁在一起,對此感到抱歉。

我一直在研究如何創建解析器,如果可能的話,必須存在一個不確定的循環才能找到從TK的連接。 我不確定C#解析器是否會嘗試這樣做,但是不幸的是,我的錢沒有用!

這是我想到的。 不是 OP 問題的答案,但據我所知,從 C# 規則來看,無論如何都是不可能的。 所以我做了什么來實現具體 class 中的隱式運算符,它依賴於抽象 class 中定義的轉換算法。

我的課程:

public interface IInjectable<T>
{
    T Value { get; set; }
}

internal abstract class Injectable<T,P> : IInjectable<T>
    where P : Injectable<T,P>, new()
{
    public abstract T Value { get; set; }

    public static implicit operator T(Injectable<T,P> injectable) => injectable.Value;
    
    //public static implicit operator Injectable<T,P>(T value) => new P { Value = value };
    public static P Convert(T value) => new P { Value = value };        
}

internal class InjectableGuid : Injectable<Guid, InjectableGuid>
{
    public override Guid Value { get; set; } = Guid.Empty;

    public override string ToString() => Value.ToString();        

    public static implicit operator InjectableGuid(Guid guid) => Convert(guid);        
}

用法:

Guid id = new InjectableGuid();
Console.WriteLine(id.ToString());

Guid newId = Guid.NewGuid();
Console.WriteLine("Guid.ToString() : "+newId.ToString());
InjectableGuid injected = newId;
Console.WriteLine("InjectableGuid.ToString() : "+injected.ToString());

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM