繁体   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