
PVS-Studio静的コードアナライザーの機能を実証するために、さまざまなC#プロジェクトのテストを続けています。 この記事では、InfragisticsのWPFサンプルのテスト結果を調べます。 インフラジスティックス自体は、1989年に設立されたグローバルなソフトウェアプロバイダーです。 同社は、.NETを含むすべてのプラットフォームでサードパーティの開発者向けのユーザーインターフェイスコンポーネントを開発することで名を上げました。
PVS-Studio 6.00では、以前に開発されたC ++アナライザーの経験に基づいて、主に一般的な計画のC#診断を実装しました。 PVS-Studio 6.01から、C#専用の診断の作成を開始しました。 まず、WPFプロジェクトで使用される依存関係プロパティ(DependencyProperty)が選択されました。 依存関係の作成が複雑であるため、DependencyPropertyを選択しました。 難点は、同じコードでタイプミスをするのが非常に簡単であるということです。これは、WPFプロジェクトに引き付けられます。 私たちは多くの診断[ 3044、3045、3046、3047、3048、3049 ]を開発し、そのような特性の分析と検証に特化しています。
ご存じのとおり、DependencyPropertyの機能の1つは、ほとんどの場合、登録中にエラーが発生すると、実行時(実行時)にプログラムがクラッシュすることです。 プログラマーは、プログラムを何度も実行することにより、このようなエラーを修正します。 したがって、DependencyPropertyを作成するためのテンプレートコードでタイプミスを検索するのに貴重な時間を費やし、全体で1時間かかります。 同時に、WPFプロジェクトをテストする方法が示しているように、プログラムの最初の起動後、依存関係プロパティのすべてのエラーが明らかではありません。
これらの診断の最初のテストコードは、 Infragisticsのテストケースコードでした。 アーカイブはここから 02.02.2016にダウンロードされ 、プロジェクトの数は11個に達しますが、それらはすべて1つのアーカイブにダウンロードできます 。
ソースコードの検証は、 PVS-Studio 6.01静的アナライザーを使用して実行されました。
WPFエラー
多くのプロジェクトは、ほとんどのエラーが見つかった共通の再利用可能なコードに基づいて構築されています。
エラーN1
ファイル「LambertConformalConic.cs」のプロジェクト「IGExtensions.Common.WPF」で、次の登録行が「DependencyProperty」で見つかりました。
public static readonly DependencyProperty CentralMeridianProperty = DependencyProperty.Register("CentralMeridianProperty", typeof(double), typeof(LambertConformalConic), new PropertyMetadata(0.0, new PropertyChangedCallback(UpdateConstants)));
V3045 WPF:登録されたプロパティ「CentralMeridianProperty」とプロパティ「CentralMeridian」の名前は、互いに対応していません。 LambertConformalConic.cs 130
ご覧のとおり、DependencyPropertyを登録するときに、「CentralMeridian」ではなく「CentralMeridianProperty」が名前に指定されています。 変数名のコピーが原因でエラーが頻繁に発生しますが、次の危険が伴います。
つまり、C#コードから依存関係プロパティに書き込み/読み取りを行うために、次のレイヤープロパティが作成されます。
public double CentralMeridian { get { return (double)GetValue(CentralMeridianProperty); } set { SetValue(CentralMeridianProperty, value); } }
xamlマークアップからアクセスする場合、「CentralMeridian」プロパティに書き込みをバインドします。 WPFは、CentralMeridianプロパティを見つけてそこから値を読み取るのに十分なほどスマートですが、もちろんCentralMeridianの値への変更は取得されません。
エラーN2
登録された依存関係プロパティの名前のタイプミスのトピックを続けて、IGExtensions.Common.WPFプロジェクトのTransverseMercator.csファイルの次のエラーを考慮してください。
public static readonly DependencyProperty CentralMeridianProperty = DependencyProperty.Register("LongitudeOrigin", typeof(double), typeof(TransverseMercator), new PropertyMetadata(0.0, new PropertyChangedCallback(UpdateConstants))); public double CentralMeridian { .... }
V3045 WPF:登録されたプロパティ「LongitudeOrigin」とプロパティ「CentralMeridian」の名前は、互いに対応していません。 TransverseMercator.cs 95
実践が示すように、1行の複数の複製と後続の編集を使用して、依存関係プロパティが一括で登録されます。 つまり、 Copy-Pasteを使用します。 そして、同じタイプのコードのこのブロックのどこかで、ある変数がスキップされ、リスト内のその隣にある別の名前が割り当てられます。 リスト自体は通常、別のウィンドウの隣のノートブック[Notepad、Notepad ++、Sublime Textなど]のどこかにあるため、目で確認して必要なオブジェクトをすべて作成できます。 次のようなエラーを検出するのは非常に困難です。 コードはかなり機能していますが、真実は半分にすぎません。
エラーN3
登録されたプロパティの名前にエラーがあることはすべて明らかなようですが、DependencyPropertyを作成するときに他にどこを間違えられますか? たとえば、同じプロジェクト「IGExtensions.Common.WPF」のファイル「PropertyBrushColorEditor.cs」のように、たとえば、それらに含まれる値のタイプに含まれます。
public static readonly DependencyProperty BrushColorProperty = DependencyProperty.Register(BrushColorPropertyName, typeof(Brush), typeof(PropertyBrushColorEditor), new PropertyMetadata(null, (sender, e) => {....}) ); public SolidColorBrush BrushColor { get { return (SolidColorBrush)GetValue(BrushColorProperty); } set { SetValue(BrushColorProperty, value); } }
V3046 WPF:DependencyPropertyに登録されたタイプは、アクセスに使用されるプロパティのタイプと一致しません。
登録時に親クラス「Brush」を指定するのが間違っている理由について疑問がなければ、「BrushColor」プロパティで「SolidColorBrush」継承者を参照する場合、これは良いことです。 それ以外の場合は、格納されたタイプを持つそのような「ゲーム」の単純化されたケースを説明します。
たとえば、単純なケースを想像してください。 簡単なWPFプロジェクトを作成し、次の依存関係プロパティをウィンドウクラスに追加しましょう。
public static DependencyProperty MyIndexProperty = DependencyProperty.Register("MyIndex", typeof(int), typeof(MainWindow), new FrameworkPropertyMetadata(1)); int MyIndex { get { return (int)GetValue(MyIndexProperty); } set { SetValue(MyIndexProperty, value); } }
xamlマークアップで、次のように記述します。
....Title="MainWindow" Height="350" Width="525" DataContext="{Binding RelativeSource = {RelativeSource Mode=Self}}"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition Height="Auto" /> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> <TextBlock Grid.Row="0" Text="{Binding Path=MyIndex}"/> <Slider Grid.Row="1" Name="slider1" Value="{Binding Path=MyIndex}" Maximum="100" /> <Button Grid.Row="2" Click="Button_Click"> </Button> </Grid>
そして、ボタンクリックイベントのコードをウィンドウクラスに追加します。
private void Button_Click(object sender, RoutedEventArgs e) { this.Title = this.MyIndex.ToString(); }
それだけです すべてが機能することをどのように確認できますか? スライダーを動かすと、数字が変わります。 ボタンをクリックすると、ウィンドウのタイトルがすぐにスライダーの現在の値に変更されました。 ところで、ご覧のとおり、整数値はTextBlockに表示されます。
そして今、DependencyPropertyを登録するときに、タイプを「int」で一般的なタイプ「object」に置き換えます。
public static DependencyProperty MyIndexProperty = DependencyProperty.Register("MyIndex", typeof(object), typeof(MainWindow), new FrameworkPropertyMetadata(1));
残りは変更せずに、プログラムを再度実行します。
プログラムが開始され、スライダーを動かすと、TextBlockに実際の値が表示されます。 ボタンを押そうとすると、プログラムが単純にクラッシュすることは簡単に推測できます。 MyIndexPropertyの実際の値をMyIndexプロパティの整数に変換することはできません。 それは些細なことのように思えますが、悲しい結果をもたらしました。
エラーN4
ほとんどのプロジェクトに当てはまる上記のエラー(特に悲しいことに、どのプロジェクトでも気づかれたり修正されたことがないため)に加えて、1つのIGEquityTrading.WPFプロジェクトにローカルエラーがあります。
public static readonly DependencyProperty AxisFinancialIndicatorYTemplateProperty = DependencyProperty.Register("AxisFinancialIndicatorYTemplate", typeof(DataTemplate), typeof(DataChartEx), new PropertyMetadata(default(DataTemplate))); public DataTemplate AxisCategoryYTemplate{ get { return (DataTemplate) GetValue(AxisFinancialIndicatorYTemplateProperty); } set { SetValue(AxisFinancialIndicatorYTemplateProperty, value); } }
V3045 WPF:DependencyPropertyに登録されているプロパティの名前と、それにアクセスするために使用されるプロパティの名前が互いに対応していません。 DataChartEx.cs 469
また、Infragisticsは登録名「AxisFinancialIndicatorYTemplate」の代わりに同じレーキを使用して「AxisCategoryYTemplate」というプロパティを作成します。
エラーN5
public static readonly DependencyProperty FinancialIndicatorSeriesTemplateProperty = DependencyProperty.Register("FinancialIndicatorTemplate", typeof(DataTemplate), typeof(DataChartEx), new PropertyMetadata(default(DataTemplate))); public DataTemplate FinancialIndicatorSeriesTemplate { get { return (DataTemplate) GetValue(FinancialIndicatorSeriesTemplateProperty); } set { SetValue(FinancialIndicatorSeriesTemplateProperty, value); } }
V3045 WPF:DependencyPropertyに登録されているプロパティの名前と、それにアクセスするために使用されるプロパティの名前が互いに対応していません。 DataChartEx.cs 344
後者の場合、リファクタリング後に変数を指定し、「FinancialIndicatorTemplate」というフレーズの途中に「Series」という単語を挿入したときに、エラーが発生する可能性が最も高くなりました。 最も興味深いのは、XAMLマークアップや "#region"でさえ、どこでも変更されていることですが、登録されたプロパティ名を忘れていました。
- .... \ Infra \ EquityTrading \ IGEquityTrading.WPF \ App.xaml(123):<DataTemplate x:Key = "FinancialIndicatorSeriesTemplate">
- .... \ Infra \ EquityTrading \ IGEquityTrading.WPF \ App.xaml(214):FinancialIndicatorSeriesTemplate = "{StaticResource FinancialIndicatorSeriesTemplate}"
- .... \ Infra \ EquityTrading \ IGEquityTrading.WPF \ Controls \ DataChartEx.cs(189):var FinancialIndicator = FinancialIndicatorSeriesTemplate.LoadContent()as Series;
- .... \ Infra \ EquityTrading \ IGEquityTrading.WPF \ Controls \ DataChartEx.cs(330):#region FinancialIndicatorSeriesTemplate(DependencyProperty)
- .... \ Infra \ EquityTrading \ IGEquityTrading.WPF \ Controls \ DataChartEx.cs(336):public DataTemplate FinancialIndicatorSeriesTemplate
- .... \ Infra \ EquityTrading \ IGEquityTrading.WPF \ Controls \ DataChartEx.cs(349):#endregion FinancialIndicatorSeriesTemplate(DependencyProperty)
- .... \ Infra \ EquityTrading \ IGEquityTrading.WPF \ Controls \ StockHistoryChart.xaml(646):FinancialIndicatorSeriesTemplate = "{StaticResource FinancialIndicatorSeriesTemplate}"
さらに、登録名「FinancialIndicatorTemplate」はどこでも使用されておらず、この見落としが何につながるかはすでにわかっています。
不特定のC#エラー
InfragisticsからのこれらのビルドにはWPFエラーはありません。 既に述べたように、ほとんどのWPF診断は、プロジェクトをコンパイルして開始する前であっても、予備的なエラーを見つけるために特別に設計されています。 また、コンポーネントの使用例を含むこれらのプロジェクトは、プログラマーとQAスペシャリストによって既にテストされています。 さらに、プロジェクトは、テストケースによって製品の品質と使いやすさを正確に評価したユーザーによって監視されていました。 彼らが間違いに気付いた場合、おそらく、開発者に通知したと思います。
当然、WPFエラーに加えて、これらのアセンブリには他にもエラーがあります。 アナライザーは合計数百の警告を発行しました。 すべてのメッセージが実際のエラーを示すわけではありません。 多くの警告(たとえば、doubleを定数と比較することなど)は、このタイプのプロジェクトには関係ありません。 アナライザーは、関心のないメッセージを抑制するためのいくつかのメカニズムを提供するため、これは恐ろしくありません。
いずれにせよ、多くの警告があり、それらのほとんどはコードの異常を示しています。 これらは実際のバグまたは匂いコードです。 したがって、プロジェクトの作成者が独立してプロジェクトを検証し、警告を調べることをお勧めします。 ここでは、最も興味深いもののみを説明します。
public bool IsValid { get { var valid = double.IsNaN(Latitude) || double.IsNaN(Latitude) || this.Weather.DateTime == Weather.DateTimeInitial; return valid; } }
V3001 「||」の左側と右側に同じ副次式「double.IsNaN(Latitude)」があります。 演算子。 WeatherStation.cs 25
プログラマが生きるのは難しいです。 プログラミング自体だけでなく、プログラムが動作する領域についても理解する必要があります。 そのため、対象分野を理解し、「Vira」(上)、「Lane」(下)、「Latitude」(Latitude)、「Longitude」(Longitude)などの単語を知っている必要があります。 これは、特に概念のスペルが類似している場合にのみ、複雑さを追加します。 したがって、同じ変数のチェックを誤って記述したことが判明しました:double.IsNaN(Latitude)|| double.IsNaN(緯度)。
次のエラー:
private static int clipSegment(....) { if (xmax > rc.Right && xmax > rc.Right) { return -1; } }
V3001 「&&」演算子の左右には、同一の副次式「xmax> rc.Right」があります。 幾何学 Geometry.CubicSpline.cs 529
変数が存在する範囲をチェックすることは一般的ですが、記号を間違えて、次に記述する必要がある変数を間違えるのは非常に簡単です。 実際、このようなエラーをなくすには、次のパターンに従う必要があります。条件の一般変数は、式のさまざまな側面から書き込まれます。
if (xmin < rc.Right && rc.Right < xmax)
間違いはより読みにくくなります。
PS確かに、このようなトリックはEntity Frameworkでは機能しません。LINQコードをSQLクエリに変換すると、プログラムがクラッシュします。 ここにそのようなものがあります:)
実際、このプロジェクトでは、Infragisticsはこのようなチェックを行うことで通常とは異なるものになります。 上記のコードに加えて、同様のエラーが次の行で繰り返されました。
private static int clipSegment(....) { .... if (ymin < rc.Top && ymin < rc.Top) //<= .... if (ymax > rc.Bottom && ymax > rc.Bottom) //<= .... }
V3001にはこれらのエラーはほとんどなく、プロジェクトの拡張を続けています:)。 操作の別の例を次に示します。
private static bool IsInDesignModeStatic(this Application app) { .... if (_isInDesignMode != null && _isInDesignMode.HasValue) return _isInDesignMode.Value; .... }
V3001 「&&」演算子の左右には、同一のサブ式「_isInDesignMode!= Null」があります。 NavigationApp.cs 415
この場合、エラーを処理するのではなく、冗長なコードを処理します。 書くのに十分でした:
if (_isInDesignMode.HasValue)
V3001をもう1つ起動すると、IgWord.Infrastructureプロジェクトに送られます。
void ParagraphSettingsPreviewAdapter_PropertyChanged( object sender, PropertyChangedEventArgs e) { .... if (LineSpacingType == Infrastructure.LineSpacingTypes.Exactly || LineSpacingType == Infrastructure.LineSpacingTypes.Exactly){ .... }
V3001 「||」の左側と右側に同一の副次式「LineSpacingType == Infrastructure.LineSpacingTypes.Exactly」があります。 演算子。 ParagraphSettingsPreviewAdapter.cs 268
開発者がここで正確にやりたいことは明確ではありませんが、書かれていることではありません。
V3001から、優先度の順に、V3010に進みましょう。
IGEarthQuake.WPFプロジェクトには、いくつかの関数呼び出しがあります。
public MapViewModel() { .... WeakPropertyChangedListener.CreateIfNecessary(_service, this); .... }
V3010関数「CreateIfNecessary」の戻り値を使用する必要があります。 MapViewModel.cs 42
public TimeLineViewModel(){ .... WeakPropertyChangedListener.CreateIfNecessary(_service, this); .... }
V3010関数「CreateIfNecessary」の戻り値を使用する必要があります。 TimeLineViewModel.cs 50
実際、どちらの場合も1つの関数が呼び出され、非常に簡単です。 その実装を見てみましょう。
public static WeakPropertyChangedListener CreateIfNecessary(object source, IPropertyChangedListener listener){ INotifyPropertyChanged inpc = source as INotifyPropertyChanged; return inpc != null ? new WeakPropertyChangedListener(inpc, listener) : null; }
実際、ご覧のとおり、この関数はグローバルな変更を加えず、その結果も使用されません。 そこで疑問が生じます-なぜ彼女はまったく呼ばれたのですか? 疑わしいことにこのすべて...
同様の例がプロジェクト「IGHospitalFloorPlan.WPF」で私たちを待っています:
private void ParseAllShapefiles() { .... this.ShapeFilesMaxBounds.Expand(new Thickness(10, 10, 10, 10)); .... }
V3010関数 'Expand'の戻り値を使用する必要があります。 HospitalView.xaml.cs 52
その実装は少し複雑ですが、最終的にはどこでも使用されていない新しいオブジェクトを返すだけです。
記事の途中です。 写真を見てください。 リラックスして、続けます。

最も一般的なタイプのエラーの1つは、コピーペーストコードの失敗です。
public static EsriMapImageryView GetImageryView(EsriMapImageryStyle imageryStyle){ .... if (imageryStyle == EsriMapImageryStyle.UsaPopulationChange2010Overlay) return EsriMapImageryViews.UsaPopulationChange2010Overlay; if (imageryStyle == EsriMapImageryStyle.UsaPopulationChange2010Overlay) return EsriMapImageryViews.UsaPopulationChange2010Overlay; .... }
V3021同一の条件式を持つ2つの「if」ステートメントがあります。 最初の「if」ステートメントにはメソッドの戻り値が含まれます。 これは、2番目の「if」ステートメントが無意味であることを意味しますEsriMapImageryView.cs 97
この場合、同じ条件下では同じコードになります。 この段階では、エラーは失敗した(冗長な)Copy-Pasteコードです。 しかし、リファクタリング後、プログラマが子if文を変更するという状況が発生する場合があります。if文は実行されず、プログラムロジックでエラーが発生します。
また、Infragistics社のコードで他のエラーが見つかったものを見てみましょう。
以下の各行について、警告V3022が発行されました。
public static double GenerateTemperature(GeoLocation location){ .... else if (location.Latitude > 10 || location.Latitude < 25) .... else if (location.Latitude > -40 || location.Latitude < 10) .... } public static WeatherCondition GenerateWeatherCondition(....){ .... else if (location.Latitude > 10 || location.Latitude < 25) .... else if (location.Latitude > -40 || location.Latitude < 10) .... }
エラーはすべて次のメッセージにまとめられます。
V3022式 'location.Latitude> -40 || location.Latitude <10 'は常に真です。 ここでは、おそらく「&&」演算子を使用する必要があります。
何が言えますか? V3001のエラーの1つを説明する場合、おそらく上記と同じです。 式の異なる側から同じ変数が書き込まれる場合、パターンを使用すると便利です。
if (xmin < rc.Right && rc.Right < xmax)
これにより、最初のレベルのエラーの説明が完了し、2番目と3番目に進みます。 同じメッセージ番号は、状況に応じて、異なる優先度を持ちます。
3番目のレベルでは、診断メッセージが収集されます。アナライザーは、その正確性が十分に確信できない場合にそれを出力します。 レベル3には、すべてのプロジェクトに関係のない診断もあります。
実際には、レベル3の警告で真のエラーが明らかになることはほとんどありません。 多くの場合、これらは依然として正しいコードですが、「匂い」を示す可能性のある誤検知またはメッセージです。 いずれにせよ、時間があれば、これらの診断はコードを調査してリファクタリングする価値があります。
2つの同一の機能を持つコードから始めましょう。
// 0 reference public static double Ramp(double a) { return a - Math.Floor(a); } // 1 reference public static double Frac(double a) { return a - Math.Floor(a); }
V3013 「ランプ」機能の本体が「Frac」機能の本体と完全に同等であることは奇妙です( 28、33行目)。 Math.cs 28
Frac関数が意味をなす場合、 同様の機能がPascalにありましたが、Ramp機能にはアナログがないか、見つかりませんでした。 実際、機能が使用されている場所の数のカウンターは、それ自体で話します(コメントを参照)。
エラーV3013から遠くないように、このエラーが2番目のレベルで発生した場合を考えてください。
public void StartCurrent() { StartTask("Current"); } public void StopCurrent() { StartTask("Current"); }
V3013 「StartCurrent」機能の本体が「StopCurrent」機能の本体と完全に同等であることは奇妙です(503、行507)。 DataViewModel.cs 503
どうやら、2番目のケースでは、StartTask関数がStopTaskと混同されたようです。 これらの関数は両方ともコード内にあり、名前に従って非常に明確に機能します。
次に、以下のコードに関連する一連のメッセージを検討します。
{ IsUpdating = true; .... IsUpdating = false; }
同様のコードが4つの場所(各アセンブリ)にあります。
- V3008 「IsUpdating」変数には、値が連続して2回割り当てられます。 おそらくこれは間違いです。 行を確認してください:201、195。GeoRegion.cs 201
- V3008 「IsUpdating」変数には、値が連続して2回割り当てられます。 おそらくこれは間違いです。 行を確認:212、205。GeoRegion.cs 212
- V3008 「IsUpdating」変数には、値が連続して2回割り当てられます。 おそらくこれは間違いです。 行を確認:226、216。GeoRegion.cs 226
- V3008 「IsUpdating」変数には、値が連続して2回割り当てられます。 おそらくこれは間違いです。 行を確認してください:244、236。GeoRegion.cs 244
最初は、この変数はクロススレッド相互作用に使用されるようです。 しかし、判明したように、実際には、この変数は診断が機能した行を除いてどこにも見つかりません。
さて、クロススレッド同期のためにこの変数を使用することに決めたとします。 そして、ここで不愉快な驚きを待っています。 変数宣言は次のとおりです。
protected bool IsUpdating = false;
ご覧のとおり、「volatile」キーワードはありません。その結果、コンパイラーはそれを正常に最適化し、私たちが望むものとはまったく異なる動作をします。
コードで他に面白いものは何ですか? たとえば、追加の計算:
例1:
public static void Normalize(....) { var x = rect.X < boundingRect.X ? boundingRect.X : rect.X; x = (rect.X + rect.Width) > boundingRect.Right ? boundingRect.X : rect.X; }
V3008 「x」変数には値が連続して2回割り当てられます。 おそらくこれは間違いです。 行をチェック:96、95。RectEx.cs
例2:
private static GradientStopCollection fromInterpolation(....){ .... Color color=ColorTool.FromAHSV(ahsv[0], ahsv[1], ahsv[2], ahsv[3]); color = ColorTool.FromARGBInterpolation(min, p, max[i].Color); .... }
V3008 「color」変数には値が連続して2回割り当てられます。 おそらくこれは間違いです。 行を確認してください:165、163。BrushTool.cs
時々、一般的に楽しいコードのスニペットがあります:
private void UpdateAutoSavedState() { AutoSaved = true; AutoSaved = false; }
V3008 「AutoSaved」変数には、連続して2回値が割り当てられます。 おそらくこれは間違いです。 行を確認:691、690。ShellViewModel.cs 691
このコードを疑う人のために、プロパティ宣言を引用します。
private bool autoSaved; public bool AutoSaved { get { return autoSaved; } set { autoSaved = value; } }
繰り返しますが、「揮発性」も、このアクションの隠された意味を語るようなものもありません-いいえ。
エラーV3029の別の行グループに移りましょう。
public void OnPropertyChanged(PropertyChangedEventArgs ea) { .... var index = this.SelectedBrushCollectionIndex; .... if (index >= 0) DebugManager.LogData(this.BrushCollectionList[index].ToText()); if (index >= 0) this.SelectedBrushCollectionIndex = index; .... }
V3029互いに並んでいる「if」演算子の条件式は同一です。 行を確認してください:338、339。
public static void EnableSeriesMouseDoubleClick( this XamGeographicMap geoMap, bool isEnabled = true){ .... if (geoMap != null) geoMap.SeriesMouseLeftButtonDown += OnSeriesMouseLeftButtomDown; if (geoMap != null) geoMap.SeriesMouseLeftButtonUp += OnSeriesMouseLeftButtonUp; .... if (geoMap != null) geoMap.SeriesMouseLeftButtonDown -= OnSeriesMouseLeftButtomDown; if (geoMap != null) geoMap.SeriesMouseLeftButtonUp -= OnSeriesMouseLeftButtonUp; .... }
V3029互いに並んでいる「if」演算子の条件式は同一です。 行を確認:92、93。GeoMapAdapter.cs 92
V3029互いに並んでいる「if」演算子の条件式は同一です。 行を確認:100、101。GeoMapAdapter.cs 100
public void SyncSeriesViewPropertyChanges() { if (this.SeriesView != null) this.SeriesView.PropertyUpdated += OnSeriesViewPropertyUpdated; if (this.SeriesView != null) this.SeriesView.PropertyChanged += OnSeriesViewPropertyChanged; }
V3029互いに並んでいる「if」演算子の条件式は同一です。 チェック行:342、343。GeoSeriesLayer.cs 342
sayingにあるように-「念のため、しかし突然」...
これらはエラーではありませんが、繰り返しチェックするとコードが乱雑になり、理解が複雑になります。
そして、これがリファクタリング中に発生した可能性が最も高い冗長コードです。
public Frame NavigationTarget { get { return (Frame)this.GetValue(NavigationTargetProperty); } set { var targetFrame = value as Frame; if (targetFrame != null) this.SetValue(NavigationTargetProperty, value); } }
「値」はすでにフレームタイプです;キャストは無意味です。 しかし、この場合、より広い意味で状況を考慮する必要があります。 Infragisticsは、DependencyPropertyに書き込むときにnullチェックを実行します。 このようなチェックのために、依存関係プロパティの開発者は、コールバック関数「ValidateValueCallback」を提供しました。 この関数は、DependencyPropertyに書き込まれる値をチェックし、依存関係プロパティを登録するときに設定されます。
おわりに
再び、輝く鎧の私たちの虹のユニコーンは、かなりの数の問題領域を明らかにしました(発見したすべてのエラーが記事にリストされているわけではありません)。 はい、現在、開発者はコードを修正し、それを以前よりも改善することができます...作成時の内容...内容、テストの時期...内容、書き換え時、起動時、クラッシュおよび繰り返し動作、必要に応じて...
前作の私の練習では、締め切りの数日前の週末と夜に、非常に多くのことを非常に迅速に行う必要があったため、臨検がありました。チーム全体が何をすべきかを知っていましたが、急ぎと疲れが感じられ、デバッグに多くの時間が費やされました。つまりコードを記述して実行すると、意図したとおりに機能しません。すべてを停止し、ブレークポイントを設定して再起動します。繰り返しのすべてのステップを実行し、ブレークポイントに来て、行ごとにチェックし、そこで何が起こるかを確認します。コードを前後にジャンプして、変数の値を確認します。しかし、最終的には、条件のどこかで変数または記号が混同されている
ことがわかります... だから、コピーアンドペーストの間違いはタイプミスのために15分の純粋な時間を要することがわかります... だから、いくらプロジェクトをチェックしてもエラーは見つかりませんでした。これは、コードを記述するときに発生する問題の巨大な氷山の一角にすぎません。
間違いから免れる人はいません。ロールモデルおよび会社の名刺として機能するコードを作成しても、間違いを避けることはできません。
心からのアドバイス-PVS-Studioアナライザーを常に使用してください。このため、すべてのツールがあります。たとえば、変更されたファイルをチェックするモードがあり、実行する必要さえありません。アナライザは必要なものをチェックし、それらの問題を報告します。
この記事を英語圏の聴衆と共有したい場合は、翻訳へのリンクを使用してください:Vitaliy Alferov。Infragistics CompanyによるWPFサンプルのソースコードの分析。
記事を読んで質問がありますか?