90501


Microsoft Visual Studio Community 2022 (64 ビット) - Current  
Version 17.1.6

C# 8.0  
netcoreapp3.1ターゲットのクラスライブラリ  
WPF使用

下記のコードに於いて、OR短絡評価をして欲しいところが、思ったように動いていません。

[code]

        public class PlcMapV2ViewModel : ViewModelBase
        {
            public RegisterCollectionV2ViewModel[] Collections { get; }
    
            public PlcMapV2ViewModel()
            {
                // For design
                Collections = new RegisterCollectionV2ViewModel[]
                {
                    new RegisterCollectionV2ViewModel(),
                    new RegisterCollectionV2ViewModel(),
                };
            }
    
            public PlcMapV2ViewModel(PlcMapV2 map, string tabGroup)
            {
                Collections =
                        map
                        .GetType()
                        .GetProperties()
                        .Where(x =>
                            (x.PropertyType == typeof(RegisterCollectionV2) || x.PropertyType.IsSubclassOf(typeof(RegisterCollectionV2))) &&
                            x.IsDefined(typeof(RegisterCollectionAttribute), true))
                        .Select(x =>
                            new {
                                collection = x.GetValue(map) as RegisterCollectionV2,
                                tabName =
                                    x.GetCustomAttributes(typeof(TabGroupAttribute), true).FirstOrDefault() is TabGroupAttribute tabAttr ?
                                        tabAttr.TabName :
                                        null,
                            })
                        .Where(x =>
                            x.collection.IsDefinedTabGroupInRegisters(tabGroup) ||
                            string.IsNullOrEmpty(tabGroup) ?
                                string.IsNullOrEmpty(x.tabName) :
                                tabGroup == x.tabName)
                        .Select(x => new RegisterCollectionV2ViewModel(x.collection, tabGroup, x.tabName))
                        .ToArray();
            }
        }
    
        internal static class RegisterCollectionExtensions
        {
            public static bool IsDefinedTabGroupInRegisters(this RegisterCollectionV2 collection, string tabGroup)
            {
                return
                    collection
                    .GetType()
                    .GetProperties()
                    .Where(x => x.IsDefined(typeof(TabGroupAttribute), true))
                    .Select(x => x.GetCustomAttributes<TabGroupAttribute>(true).First().TabName)
                    .Any(x => string.IsNullOrEmpty(tabGroup) ? string.IsNullOrEmpty(x) : tabGroup == x);
            }
        }
    
[/code]

問題の部分はPlcMapV2ViewModelのコンストラクタ内の以下の部分です。

[code]

    .Where(x =>
        x.collection.IsDefinedTabGroupInRegisters(tabGroup) ||
        string.IsNullOrEmpty(tabGroup) ?
            string.IsNullOrEmpty(x.tabName) :
            tabGroup == x.tabName)
    
[/code]

想定している動きは、`x.collection.IsDefinedTabGroupInRegisters(tabGroup)`の部分でtrueが返るとその下の3項演算は評価されず、.Whereに対してtrueが返るものと思っています。  
しかし実際は`x.collection.IsDefinedTabGroupInRegisters(tabGroup)`の部分がtrueを返しても.Whereにfalseが返されるようで、続きの`.Select(x
=> new RegisterCollectionV2ViewModel(x.collection, tabGroup,
x.tabName))`が実行されません。

そこで、以下のように修正すると想定通りの動きをします。

[code]

    .Where(x =>
        x.collection.IsDefinedTabGroupInRegisters(tabGroup) ||
        (string.IsNullOrEmpty(tabGroup) ?       // <- 3項演算部分を()で括る
            string.IsNullOrEmpty(x.tabName) :
            tabGroup == x.tabName))
    
[/code]

または

[code]

    .Where(x =>
    {
        // 一度変数に格納して最後にOR評価
        bool b1 = x.collection.IsDefinedTabGroupInRegisters(tabGroup);
        bool b2 = string.IsNullOrEmpty(tabGroup) ?
                      string.IsNullOrEmpty(x.tabName) :
                      tabGroup == x.tabName);
        return b1 || b2;
    }
    
[/code]

これはどういったことが原因で発生しているのかご教示頂きたいです。  
不足情報があれば追記致します。


CC BY-SA 4.0
2022-08-10T13:08:06.770
90500
2022-08-10T13:17:16.677
2022-08-10T13:17:16.677
4236
53943
question
c#
or短絡評価が正しく評価されない


[C# 演算子の優先順位と結合規則](https://docs.microsoft.com/ja-jp/cpp/c-language/precedence-
and-order-of-evaluation?view=msvc-170)にあるように、`?:`よりも先に`||`が結合されます。  
つまり、`a || b ? c : d` は `(a || b) ? c : d`
と評価されます。これが意図しないのであれば既に質問文にあげられているように `a || (b ? c : d)` とカッコで括ることです。


CC BY-SA 4.0
2022-08-10T13:15:07.423
90501
2022-08-10T13:15:07.423
4236
90500
answer