27

次のような構造体を介してステータスの更新を渡す WCF サービスがあります。

[DataContract]
public struct StatusInfo
{
    [DataMember] public int Total;
    [DataMember] public string Authority;
}
...
public StatusInfo GetStatus() { ... }

次のように ViewModel でプロパティを公開します。

public class ServiceViewModel : ViewModel
{
    public StatusInfo CurrentStatus
    {
        get{ return _currentStatus; }
        set
        { 
            _currentStatus = value;
            OnPropertyChanged( () => CurrentStatus );
        }
    }    
}

XAML は次のようになります。

<TextBox Text="{Binding CurrentStatus.Total}" />

アプリを実行すると、Total プロパティが見つからないことを示すエラーが出力ウィンドウに表示されます。私はチェックしてダブルチェックし、正しく入力しました。エラーは、「プロパティ」が見つからないことを明確に示していることがわかりました。そのため、構造体にプロパティを追加すると、うまく機能しました。しかし、WPF がフィールドへの一方向バインディングを処理できないというのは、私には奇妙に思えます。構文的には、コードで同じようにアクセスしますが、StatusInfo 構造体のためだけにカスタム ビュー モデルを作成する必要があるのはばかげているようです。WPF バインディングについて見逃したことがありますか? フィールドにバインドできますか、それともプロパティ バインドが唯一の方法ですか?

4

2 に答える 2

33

通常、バインドはフィールドには機能しません。PropertyDescriptorほとんどのバインディングは、(デフォルトで)プロパティで機能するComponentModelモデルに部分的に基づいています。これにより、通知、検証などが可能になります(いずれもフィールドでは機能しません)。

私が入ることができるより多くの理由のために、公共の場は悪い考えです。それらはプロパティである必要があります、事実。同様に、可変構造体は非常に悪い考えです。特に、予期しないデータ損失(通常は可変構造体に関連する)から保護します。これはクラスである必要があります:

[DataContract]
public class StatusInfo
{
    [DataMember] public int Total {get;set;}
    [DataMember] public string Authority {get;set;}
}

これで、思ったとおりに動作します。不変の構造体にしたい場合は、それで問題ありません(ただし、データバインディングはもちろん一方向のみです)。

[DataContract]
public struct StatusInfo
{
    [DataMember] public int Total {get;private set;}
    [DataMember] public string Authority {get;private set;}

    public StatusInfo(int total, string authority) : this() {
        Total = total;
        Authority = authority;
    }
}

しかし、そもそもなぜこれが構造体なのか疑問に思います。.NET言語で構造体を作成することは非常にまれです。WCFの「mex」プロキシレイヤーは、とにかくコンシューマーでクラスとして作成することに注意してください(アセンブリ共有を使用しない場合)。


「構造体を使用する理由」の返信(「不明(google)」)への回答:

それが私の質問への回答である場合、それは多くの点で間違っています。まず、変数としての値型は、通常、スタックに(最初に)割り当てられます。それらがヒープにプッシュされた場合(たとえば、配列/リスト内)、クラスとのオーバーヘッドに大きな違いはありません-小さなオブジェクトヘッダーと参照です。構造体は常に小さくする必要があります。複数のフィールドがあるものはサイズが大きすぎて、スタックを殺すか、ブリッティングのために速度が低下するだけです。さらに、構造体は不変である必要があります-自分が何をしているのかを本当に理解していない限り。

オブジェクトを表すほとんどすべてのものは、不変でなければなりません。

データベースにアクセスしている場合、構造体とクラスの速度は、プロセスから外れて、おそらくネットワークを介して実行される場合と比較して、問題ではありません。それが少し遅いとしても、それはそれを正しくするという点と比較して何も意味しません-つまり、オブジェクトをオブジェクトとして扱います。

100万オブジェクトを超えるいくつかのメトリックとして:

struct/field: 50ms
class/property: 229ms

以下に基づいています(速度の違いは、フィールドとプロパティではなく、オブジェクトの割り当てにあります)。したがって、約5倍遅くなりますが、それでも非常に高速です。これがボトルネックになることはないので、これを時期尚早に最適化しないでください。

using System;
using System.Collections.Generic;
using System.Diagnostics;
struct MyStruct
{
    public int Id;
    public string Name;
    public DateTime DateOfBirth;
    public string Comment;
}
class MyClass
{
    public int Id { get; set; }
    public string Name { get; set; }
    public DateTime DateOfBirth { get; set; }
    public string Comment { get; set; }
}
static class Program
{
    static void Main()
    {
        DateTime dob = DateTime.Today;
        const int SIZE = 1000000;
        Stopwatch watch = Stopwatch.StartNew();
        List<MyStruct> s = new List<MyStruct>(SIZE);
        for (int i = 0; i < SIZE; i++)
        {
            s.Add(new MyStruct { Comment = "abc", DateOfBirth = dob,
                     Id = 123, Name = "def" });
        }
        watch.Stop();
        Console.WriteLine("struct/field: "
                  + watch.ElapsedMilliseconds + "ms");

        watch = Stopwatch.StartNew();
        List<MyClass> c = new List<MyClass>(SIZE);
        for (int i = 0; i < SIZE; i++)
        {
            c.Add(new MyClass { Comment = "abc", DateOfBirth = dob,
                     Id = 123, Name = "def" });
        }
        watch.Stop();
        Console.WriteLine("class/property: "
                   + watch.ElapsedMilliseconds + "ms");
        Console.ReadLine();
    }
}
于 2009-05-09T09:59:49.347 に答える
0

プロパティのみをサポートする理由を推測することしかできません。おそらく、変更可能なフィールドを公開しないことが.NETフレームワークの普遍的な規則であるように思われ(おそらくバイナリ互換性を保護するため)、すべてのプログラマーが同じ規則に従うことをどういうわけか期待していたからです。

また、フィールドとプロパティは同じ構文でアクセスされますが、データ バインディングではリフレクションが使用されます。また、フィールドにアクセスする場合とプロパティにアクセスする場合では、リフレクションを異なる方法で使用する必要があると聞いています。

于 2009-05-16T15:51:46.723 に答える