在通用 C# 类中链接隐式运算符

问题描述 投票:0回答:4

对于以下通用 C# 类,我想将 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问题我之前提出过。

c# operator-overloading abstract-class
4个回答
18
投票

实现您自己的隐式转换逻辑的规则非常严格,您可能应该非常熟悉第 6.4.4 节(转换:用户定义的隐式转换,对于 C# 8 第 10.2 节)和 10.10.3(类:转换运算符,对于 C# 8 规范第 15.10.4 节),如果您要执行像这样特别复杂的操作。

简单来说,您应该了解的一些关键规则是:

  • 您定义转换的类型必须出现在用户定义转换的“to”或“from”部分中。你不能创建一个类 C 来定义从 E 到 F 的转换; C 一定在某个地方。
  • 永远不可能用您自己的隐式转换来替换内置的隐式转换;例如,当从 C 转换为对象时,您不能使特殊行为发生。
  • 用户定义的隐式转换将与最多两个内置隐式转换“链接”,但不会与任何其他用户定义的转换“链接”。例如,如果您有一个从 C 到 D 的用户定义隐式转换,以及一个从 D 到 IFoo 的内置隐式转换,那么您将获得从 C 到 IFoo 的隐式转换。但是,如果 D 有一个用户定义的到 E 的隐式转换,那么您就无法免费获得从 C 到 E 的隐式转换。

2
投票

编译器不会链接转换,因此解决问题的方法不起作用。

隐式转换在类型检查方面相当严格。如果编译器

知道
类型,你的第一个代码片段和Testdo就可以工作:

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

问题在于,从类型系统的角度来看,您的

ValueType<int, Test>
并不总是
Test
,因此隐式转换不适用于此处。

Eric Lippert 写了一篇关于这种通用自引用的博客文章顺便说一句 - 值得一读!


0
投票

据我所知,我不认为你可以将演员表链接在一起,对此感到抱歉。

我一直在研究如何创建解析器,如果这是可能的,那么就必须有一个无限循环来找到从

T
K
的连接。我不确定 C# 解析器会尝试这样做,但不幸的是,我的钱是不会的!


0
投票

这就是我的想法。这不是 OP 问题的答案,但据我所知,从 C# 规则来看,无论如何这是不可能的。 所以我所做的就是在具体类中实现依赖于抽象类中定义的转换算法的隐式运算符。

我的课程:

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());
最新问题
© www.soinside.com 2019 - 2024. All rights reserved.