对于以下通用 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问题我之前提出过。
实现您自己的隐式转换逻辑的规则非常严格,您可能应该非常熟悉第 6.4.4 节(转换:用户定义的隐式转换,对于 C# 8 第 10.2 节)和 10.10.3(类:转换运算符,对于 C# 8 规范第 15.10.4 节),如果您要执行像这样特别复杂的操作。
简单来说,您应该了解的一些关键规则是:
编译器不会链接转换,因此解决问题的方法不起作用。
隐式转换在类型检查方面相当严格。如果编译器
知道类型,你的第一个代码片段和
Test
类do就可以工作:
ValueType<int, Test> t = 6;
Console.WriteLine(t.Value);
问题在于,从类型系统的角度来看,您的
ValueType<int, Test>
并不总是 Test
,因此隐式转换不适用于此处。
Eric Lippert 写了一篇关于这种通用自引用的博客文章顺便说一句 - 值得一读!
据我所知,我不认为你可以将演员表链接在一起,对此感到抱歉。
我一直在研究如何创建解析器,如果这是可能的,那么就必须有一个无限循环来找到从
T
到 K
的连接。我不确定 C# 解析器会尝试这样做,但不幸的是,我的钱是不会的!
这就是我的想法。这不是 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());