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

发布于 2024-11-07 01:44:03 字数 908 浏览 0 评论 0原文

对于以下通用 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;    
    }
}

如果我要实现直接运算符隐式运算符 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);

如果可能的话,我真的想避免显式转换。

这个问题扩展了我之前提出的另一个问题

For the following generic c# class, I'd like to convert T to 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;    
    }
}

If I were to implement a direct operator implicit operator K(T val) it would result in a compile-time error (CS0556).

I thought I could try chaining implicit operators:

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

but the following example still complains that it can't be converted:

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);

I really want to avoid explicitly casting if possible.

This question extends upon another SO question I've previously raised.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

享受孤独 2024-11-14 01:44:03

实现您自己的隐式转换逻辑的规则非常严格,您可能应该非常熟悉第 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 的隐式转换。

The rules for implementing your own implicit conversion logic are quite strict and you should probably become very familiar with sections 6.4.4 (Conversions:User-defined implicit conversions, for C# 8 section 10.2) and 10.10.3 (Classes:Conversion operators, for C# 8 section 15.10.4) of the specification if you're going to do particularly complicated ones like this.

Briefly, a few key rules you should know are:

  • The type that you are defining the conversion in has to appear in either the "to" or "from" portion of the user-defined conversion. You can't make a class C that defines a conversion from E to F; C has got to be in there somewhere.
  • It is never possible to replace a built-in implicit conversion with one of your own; you can't make special behaviour happen when converting from C to object, for example.
  • User-defined implicit conversions will be "chained" with up to two built-in implicit conversions, but not with any other user-defined conversions. So for example, if you have a user-defined implicit conversion from C to D, and a built-in implicit conversion from D to IFoo, then you get an implicit conversion from C to IFoo. But if D has a user-defined implicit conversion to E, then you don't get an implicit conversion from C to E for free.
何以笙箫默 2024-11-14 01:44:03

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

隐式强制转换在类型检查方面相当严格。如果编译器知道类型,您的第一个代码段和Test就会工作:

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

问题是您的ValueType - 从类型系统的角度来看 - 并不总是 Test,因此隐式转换不适用于此处。

Eric Lippert 写了一篇关于这种通用自我的博客文章顺便说一下参考——值得一读!

Casts are not chained by the compiler, so that way of solving the issue doesn't work.

Implicit casts are quite strict in the type checking. Your very first snippet and the Test class do work if the compiler knows the type:

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

The problem is that your ValueType<int, Test> - from the type system point of view - is not always a Test, so that the implicit conversion doesn't apply there.

Eric Lippert wrote a blog post on this kind of generic self-referencing by the way - worth a read!

酒废 2024-11-14 01:44:03

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

我一直在研究如何创建解析器,如果可能的话,就必须有一个无限循环来找到从 TK 的连接。我不确定 C# 解析器会尝试这样做,但不幸的是,我的钱是不会的!

As far as I know, I don't think that you can chain casts together, sorry about that.

I've been studying how to create parsers, and if this was possible, there would have to be an indefinite loop to find the connection from T to K. I'm not sure that the C# parser would try doing that, but my money is on no, unfortunately!

故事和酒 2024-11-14 01:44:03

这就是我的想法。这不是 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());

Here is what I came up to. Not an answer to the OP question, but as far as I look for, from C# rules it is not possible anyway.
So what I did it to implement the implicit operator in concrete class that rely on the conversion algorithm defined in the abstract class.

My classes :

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);        
}

Usage :

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());
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文