"" VS地址运算符;类型修饰符优先VS逻辑和操作员(AMP)(安培) [英] "?" type modifer precedence vs logical and operator (&) vs address-of operator (&)

查看:241
本文介绍了"" VS地址运算符;类型修饰符优先VS逻辑和操作员(AMP)(安培)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

更新:
看来,我不是足够清楚的正是我要求(和开发一段时间我也记不清了一下这个问题),所以这里一个 TL;博士版本:

var test1 = a is byte & b;    // compiles
var test2 = a is byte? & b;   // does not compile
var test3 = a is byte? && b;  // compiles

这意味着 - 据我所知 - 的 类型修饰符具有较低的优先级的(因为它不是一个运营商,这可能不是最好的词),比&安培; 运营商,但比&放越高;&安培; 运营商。是这样吗? ?这哪里是在标准中描述

This means - as I understand - that the ? type modifier has lower precedence (as it's not an operator this might not be the best word) than the & operator, but higher than the && operator. Is it so? Where is this described in the standard?

和原来的问题:

虽然试图找出答案,从乔恩斯基特的优秀博文的第二个谜,的的故事的两个谜题的,我面临一个问题:

While trying to figure out the answer to the second puzzle from Jon Skeet's excellent blogpost, A Tale of two puzzles, I faced a problem:

unsafe private void Test<T>(T a, bool b) 
{
    var test1 = a is byte? & b;         // does not compile
    var test2 = a is byte? && b;        // compiles
    var test3 = a is byte ? & b : & b;  // compiles
}



在这里我使用不安全上下文我的实际目标,需要时(如:第三行),但它是没有必要的再现我提出这个问题。 (然而,它可能有一个影响,因为它引入了地址运算符作为&放大器替代; 符号)

Here I am using an unsafe context as my actual goal requires it (e.g.: the third line), but it is not necessary for reproducing the issue I raise. (However it might have an effect, as it introduces the address-of operator as an alternative for the & symbol.)

第一行不编译(别人做的),它提供了以下错误信息:

The first line does not compile (the others do), it gives the following error message:

Syntax error, ':' expected

这意味着,在这种情况下,编译器看到行

This means that in that case the compiler sees the line as

var test1 = (a is byte) ? &b [: missing part that it complains about];



而在第二行它认为它为:

While in the second line it sees it as:

var test2 = (a is byte?) && (b);



我检查运算符优先级(的这里)和顺序(从最高到最低)如下:&放;,&安培;&放大器;,,所以仅此并不能解释为什么而第二支持(或至少不适合我的第一行不编译 - 也许这就是我错了? ..)的编辑:我理解为什么第二编译,所以请不要在你的答案集中在此。

I checked operator precedence (here), and the order (from highest to lowest) is the following: &, &&, ?: , so this alone does not explain why the first line does not compile while the second does (Or at least not for me - maybe this is where I am wrong...) I understand why the second compiles, so please don't concentrate on this in your answers.

我的下一个直觉是莫明的的优先级的(如果有这样的事情)为类型修饰符是介于这两个(或事实上三级)运算符(&安培; &放大器;&安培; )。难道是这样吗?如果没有可能有人请解释一下,我遇到的具体行为?为 的评估顺序键入明确的标准

My next hunch was that somehow the precedence (if there is such thing) for the ? type modifier is somewhere between those two (or in fact three) operators (& and &&). Can it be so? If not could someone please explain the exact behavior that I am experiencing? Is the evaluating order of ? type modifier clearly described somewhere in the standard?

修改的地方描述修改:??我也知道,有一个一元地址运算符(实际上这就是我想使用该解决方案的伎俩......),它在这里扮演一个角色,但我的问题仍然保持不变。

I am also aware that there is an unary address-of operator (actually that's the trick I am trying to use for the solution...), which plays a role here, but my question still stays the same.

在同一个不安全背景下那些愉快编译:

In the same unsafe context those happily compile:

var test1 = true & b;
var test2 = true && b;
// or
var test1 = a is byte & b;
var test2 = a is byte && b;



所以,我认为,必须进行相关的修改/运营商,而不是仅仅以运营商地址服用优先(否则两个测试1 行不会编译)。

So I think it must be related to the ? modifier/operator, and not solely to the address-of operator taking precedence (otherwise the two test1 lines would not compile).

PS:我知道,我可以加括号我的代码,所以它会编译,但我想避免这种情况:

P.S.: I know that I can add parentheses to my code, so it will compile, but I want to avoid that:

var test = (a is byte?) & b;   // compiles



更新:
我罗斯林一个试验很少,我想这可能是附加的AST的的各种报表是一个好主意:

Update: I experimented with Roslyn a little, and I thought it might be a good idea to attach the ASTs for the various statements:

var test1 = a is byte & b;



AST为测试1线

var test2 = a is byte? & b;



AST为test2的行

var test3 = a is byte? && b;



AST为TEST3行

我要强调的是,我的不可以寻找原始的问题链接的文章中的解决方案(当然我找一个,但我请你不要在这里给出一个答案,请,因为我想找到了我自己。)
另外,请不要评论,如果我是一个完全错误的轨道在寻找解决办法,我只提到拼图给我具体的问题的一些背景,并提供写这样的代码一个足够好的借口。

I want to emphasise that I am not looking for a solution for the original problem in the linked article (of course I am looking for one, but I ask you not to give an answer here please, as I would like to find that out on my own.) Also, please don't comment if I am on a completely wrong track in finding the solution, I only mentioned the puzzle to give some context for my specific problem, and to provide a good-enough excuse for writing code like this.

推荐答案

说实话我不太肯定我是否应该张贴此为答案或将此信息添加到 - 已经相当冗长 - 的问题,但我终于找到的为什么的它的行为的方式。 (但我仍然认为这是没有明确的标准中,而且它实际上是在目前执行的编译器的限制。)

To be honest I am not quite sure whether i should post this as an answer or add this information to the - already quite verbose - question, but I finally found why it behaves that way. (But I still think it is not explicitly described in the standard, and that it is in fact a limitation of the current implementation of the compiler.)

另外,我不会接受我自己的答案了一段时间,希望有人也许能够给出更好的答案的选择。

Also, I am not going to accept my own answer for a while, hoping that someone might be able to give a better answer alternative.

我花了一点时间的罗斯林和我在文法和从该代码的各种语句解析调试:

I spent a little time with Roslyn, and I debugged through the lexing and parsing of the various statements from this code:

var test1 = a is byte & b;
var test2 = a is byte? & b;
var test3 = a is byte? && b;

的确切语法树已经加入到这个问题,所以我不打算在这里重复。

The exact syntax trees are already added to the question, so I am not going to repeat them here.

语句之间的差异来自于编译过程的这一部分(从的 LanguageParser.cs ):

The difference between the statements comes from this part of the compiling process (from LanguageParser.cs):

private TypeSyntax ParseTypeCore(
    bool parentIsParameter,
    bool isOrAs,
    bool expectSizes,
    bool isArrayCreation)
{
    var type = this.ParseUnderlyingType(parentIsParameter);

    if (this.CurrentToken.Kind == SyntaxKind.QuestionToken)
    {
        var resetPoint = this.GetResetPoint();
        try
        {
            var question = this.EatToken();

            // Comment added by me
            // This is where the difference occurs 
            // (as for '&' the IsAnyUnaryExpression() returns true)
            if (isOrAs && (IsTerm() || IsPredefinedType(this.CurrentToken.Kind) || SyntaxFacts.IsAnyUnaryExpression(this.CurrentToken.Kind)))
            {
                this.Reset(ref resetPoint);

                Debug.Assert(type != null);
                return type;
            }

            question = CheckFeatureAvailability(question, MessageID.IDS_FeatureNullable);
            type = syntaxFactory.NullableType(type, question);
        }
        finally
        {
            this.Release(ref resetPoint);
        }
    }

    // Check for pointer types (only if pType is NOT an array type)
    type = this.ParsePointerTypeMods(type);

    // Now check for arrays.
    if (this.IsPossibleRankAndDimensionSpecifier())
    {
        var ranks = this.pool.Allocate<ArrayRankSpecifierSyntax>();
        try
        {
            while (this.IsPossibleRankAndDimensionSpecifier())
            {
                bool unused;
                var rank = this.ParseArrayRankSpecifier(isArrayCreation, expectSizes, out unused);
                ranks.Add(rank);
                expectSizes = false;
            }

            type = syntaxFactory.ArrayType(type, ranks);
        }
        finally
        {
            this.pool.Free(ranks);
        }
    }

    Debug.Assert(type != null);
    return type;
}

和产生的效果相同<$ C $后会发生在符号的情况下, ?C>字节一部分的这个函数返回任何东西,但 SyntaxKind.None

And the same result would occur in case of symbols after the byte? part for whose this function returns anything but SyntaxKind.None:

public static SyntaxKind GetPrefixUnaryExpression(SyntaxKind token)
{
    switch (token)
    {
        case SyntaxKind.PlusToken:
            return SyntaxKind.UnaryPlusExpression;
        case SyntaxKind.MinusToken:
            return SyntaxKind.UnaryMinusExpression;
        case SyntaxKind.TildeToken:
            return SyntaxKind.BitwiseNotExpression;
        case SyntaxKind.ExclamationToken:
            return SyntaxKind.LogicalNotExpression;
        case SyntaxKind.PlusPlusToken:
            return SyntaxKind.PreIncrementExpression;
        case SyntaxKind.MinusMinusToken:
            return SyntaxKind.PreDecrementExpression;
        case SyntaxKind.AmpersandToken:
            return SyntaxKind.AddressOfExpression;
        case SyntaxKind.AsteriskToken:
            return SyntaxKind.PointerIndirectionExpression;
        default:
            return SyntaxKind.None;
    }
}



所以问题是,一个<$ C $之后C>是(或)运算符,当我们面对一个标记,然后我们检查,如果下一个标记的可以的解释为一元运算符,如果是这样的:我们不关心的 标记的可能性?作为一个类型修饰,我们简单地收到返回的类型,并相应地解析其余(有需要满足多个条件,但是这是对我的问题的有关信息)。在这具有讽刺意味的​​是,&放大器; 符号甚至不能一元运算符,只能在不安全的上下文,但是这是从来没有考虑到

So the problem is that after an is (or an as) operator, when we face a ? token, then we check if the next token can be interpreted as a unary operator and if so: we don't care about the possibility of the ? token being a type modifier, we simply return the type before it, and will parse the rest accordingly (there are more conditions to be met, but this is the relevant information regarding my question). The irony in that is that the & symbol can't even be a unary operator, only in an unsafe context, but this is never taken into consideration.

正如其他人在评论中所指出的那样,也许这个问题可以,如果我们的解决看着前面一点点的,例如:在特定情况下,我们可以检查如果有匹配的 标记,如果没有,不是忽略了一元的可能性&安培; 运营商和对待 作为类型修饰符?如果我有时间,我会努力实现一种变通方法,并看到它会引起更大的问题:)(幸运的是有很多的解决方案,罗斯林测试...)

As others have pointed out in comments, maybe this issue could be solved if we looked ahead a little bit more, e.g.: in that particular case we could check if there is a matching : for the ? token, and if not, than ignore the possibility of the unary & operator and treat the ? as a type modifier. If I will have the time, I will try to implement a workaround, and see where it will cause even greater problems :) (Luckily there are a lot of tests in the Roslyn solution...)

感谢大家的反馈意见。

这篇关于&QUOT;&QUOT; VS地址运算符;类型修饰符优先VS逻辑和操作员(AMP)(安培)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆