2012-05-08 12 views
0

私は、Calendar.SelectedDatesが読み取り専用であるという事実と相談していました。プログラムでカレンダー内の複数の日付を選択する方法が必要でした。私は私が欲しいまさにん次のコードスニペットを、見つけましたが、それが動作する理由私が理解することはできません。これは、なぜCalendarコントロールで複数の日を選択できるのでしょうか?

protected void Page_Load(object sender, EventArgs e) 
{ 
    SelectedDatesCollection dates = Calendar1.SelectedDates; 
    dates.Add(new DateTime(2012, 5, 1)); 
    dates.Add(new DateTime(2012, 5, 5)); 
    dates.Add(new DateTime(2012, 5, 9)); 
} 

私は(C#2の私の限られた知識を与えられた)期待する何を、完全に反対です。

protected void Page_Load(object sender, EventArgs e) 
{ 
    ArrayList datelist = new ArrayList(); 
    datelist.Add(new DateTime(2012, 5, 1)); 
    datelist.Add(new DateTime(2012, 5, 5)); 
    datelist.Add(new DateTime(2012, 5, 9)); 
    Calendar1.SelectedDates = new SelectedDatesCollection(datelist); 
} 

ローカルSelectedDatesCollection変数の影響を受けるSelectedDates読み取り専用プロパティはどのくらいですか?なぜそのローカル変数に追加するとCalendar1.SelectedDatesプロパティに影響しますか?プロパティは読み取り専用ですが、あなたはまだのように、オブジェクトとしてそれを変更することができますよう

(これは無変更された/特殊な性質で、ちょうどドラッグアンドドロップASP.Netカレンダーです)

+0

これらの回答はすばらしく、私を助けました。私はすべてを答えにすることができれば幸いです。再度、感謝します。 – CptSupermrkt

答えて

1

SelectedDatesCollectionアイテムを追加または削除します。

こと等により、クラスのメンバとして、(別名、それはそれはデータだ変化に対応した方法だ呼び出す)、およびオブジェクト参照自体を変更するオブジェクトを変更

の違いがあります:

SelectedDatesCollection dates = Calendar1.SelectedDates; 
は、

あなたはコレクションをコピーしていませんが、参照を保存するだけで、別の名前を付けることができます。

最終的に、あなたも行うことができます:

protected void Page_Load(object sender, EventArgs e) 
{ 
    Calendar1.SelectedDates.Add(new DateTime(2012, 5, 1)); 
    Calendar1.SelectedDates.Add(new DateTime(2012, 5, 5)); 
    Calendar1.SelectedDates.Add(new DateTime(2012, 5, 9)); 
} 

それは、一方が他方の方法は、より読みやすいと言うのと同じことです。

datesおよびCalendar1.SelectedDatesには、まったく同じオブジェクトへの参照が含まれています。 datesAddメソッドを呼び出すのは、Calendar1.SelectedDatesで呼び出すのと同じです(逆も同様)。

Calendar1.SelectedDatesを2番目のコード(コンパイルしない)で再割り当てできなかった理由は、あなたが言ったように、SelectedDatesは読み取り専用としてマークされているからです。

メンバーを読み取り専用としてマークすると、そのメンバーがただちにまたはクラス/ struct/etcのコンストラクターにのみ割り当てられることを意味します。

ただし、そのオブジェクト内のデータを変更することはできません。今から

はそれにそれの要素を変更することはできませんクラスReadOnlyCollectionは、あり

だけでいくつかの追加情報です。

たとえば、読み取り専用ReadOnlyCollectionを使用すると、メンバーを変更できなくなり、要素も変更できなくなります。

例:

public class Class1 
{ 
    public List<int> Numbers = new List<int> {1, 2, 3}; 
} 

public class Class2 
{ 
    public readonly List<int> Numbers = new List<int> {1, 2, 3}; 
} 

public class Class3 
{ 
    public ReadOnlyCollection<int> Numbers = new ReadOnlyCollection<int> {1, 2, 3}; 
} 

public class Class3 
{ 
    public readonly ReadOnlyCollection<int> Numbers = new ReadOnlyCollection<int> {1, 2, 3}; 
} 

違い:

var c1 = new Class1(); 
var c2 = new Class2(); 
var c3 = new Class3(); 
var c4 = new Class4(); 

c1.Numbers = new List<int> {4, 5, 6}; // Works 
c1.Numbers.Clear(); // Works 

c2.Numbers = new List<int> {4, 5, 6}; // Error 
c2.Numbers = c2.Numbers; // Error - you just can't reassign it! 
c2.Numbers.Clear(); // Works - you are just calling the Clear method of the existing list object. 

c3.Numbers = new ReadOnlyCollection<int> {4, 5, 6}; // Works - the member is not readonly 

// ReadOnlyCollection doesn't allow to change it's elements after initializing it. 
// It doesn't even have these functions: 
c3.Numbers.Clear(); // Error 
c3.Numbers.Add(); // Error 
c3.Numbers.Remove(2); // Error 

c4.Numbers = new ReadOnlyCollection<int> {4, 5, 6}; // Error - the member is marked as readonly 

// ReadOnlyCollection doesn't allow to change it's elements after initializing it. 
// It doesn't even have these functions: 
c4.Numbers.Clear(); // Error 
c4.Numbers.Add(); // Error 
c4.Numbers.Remove(2); // Error 
+0

恐ろしく!ここにたくさんの良い情報があります。 – CptSupermrkt

1

次のことを試してみてください - 彼らは同様に、日付の選択を解除できるようにする必要があります覚えている:

protected void Page_Load(object sender, EventArgs e) 
    { 
     if (ViewState["StartDates"] == null) 
     { 
      startDates = new ArrayList(); 
     } 
     else 
     { 
      startDates = ViewState["StartDates"] as ArrayList; 
     } 
    } 

    protected void StartSelection_Changed(Object sender, EventArgs e) 
    { 
     startCalendar.SelectedDate = new DateTime(startCalendar.SelectedDate.Year, 
      startCalendar.SelectedDate.Month, startCalendar.SelectedDate.Day, 0, 0, 0); 

     // c.f. http://www.mikepope.com/blog/AddComment.aspx?blogid=604 
     int index = -1; 
     index = startDates.IndexOf(startCalendar.SelectedDate); 
     if (index >= 0) 
     { 
      startDates.RemoveAt(index); 
     } 
     else 
     { 
      DateTime dateTime 
       = new DateTime(startCalendar.SelectedDate.Year, 
        startCalendar.SelectedDate.Month, 
         startCalendar.SelectedDate.Day, 0, 0, 0); 

      startDates.Add(dateTime); 
     } 

     ViewState["StartDates"] = startDates; 
     DisplaySelectedDates(); 
    } 


    protected void DisplaySelectedDates() 
    { 
     startCalendar.SelectedDates.Clear(); 
     for (int i = 0; i < startDates.Count; i++) 
     { 
      startCalendar.SelectedDates.Add((DateTime)startDates[i]); 
     } 
    } 
+0

ねえ、ありがとう。私はこのトラックにいた、ちょうど余分なプッシュを必要とした、ちょっと。しかし、このメソッド(そのブログ記事で詳しく説明しています)は、startDatesというグローバル変数を使用します(そうでなければ、startDate = new ArrayList()は失敗します)。どれくらい安全ですか?私が学んだ一般的なプラクティスは、グローバル変数を避けることです。これがページの他の訪問者に影響を与えますか? – CptSupermrkt

+0

私はいくつか微調整を行い、それを動作させました。それが面倒なことができる唯一の方法は、あなたも時間を記録しようとする場合です...それがあなたのために働く場合は、Aとマークすることを忘れないでください:) – IrishChieftain

+0

@IrishChieftainそれは素晴らしい解決策ですが、OPのオリジナルの質問、なぜ1つのものが動作し、もう1つのものは動作しないのかについて。あなたの解決策は、「これをどのようにして最良の方法で動作させるのですか? – SimpleVar

1

より簡潔がありますあなたの質問への回答:

ローカルSelectedDatesCollection変数の影響を受けるSelectedDates読み取り専用プロパティはどのくらいですか?なぜそのローカル変数に追加するとCalendar1.SelectedDatesプロパティに影響しますか?

SelectedDatesCollectionは参照型です。読み取り専用SelectedDatesプロパティは、参照をそのタイプのオブジェクトに返します。したがって、ローカル変数は、そのオブジェクトに参照も保持します。そのオブジェクトはCalendarControlが参照するオブジェクトと同じオブジェクトなので、そのオブジェクトへの変更はCalendarControlに反映されます。


このような状況から生じるもう一つの問題:

できるクラスを設計し、この問題を引き起こしますか?

はい!多くの開発者は、例えば、読み取り専用のプロパティを介してリストを公開することで、消費者コードがリストを変更できないという誤った仮定の下で、誤ったセキュリティの感覚に惑わされます。もちろんこれは当てはまりません。読み取り専用プロパティを使用してプライベート参照型データを公開すると、コードのユーザーはオブジェクトを変更できます。たとえば:Yoryeネイサン・ノートとして

class Parent 
{ 
    private readonly List<Child> _children = new List<Child>(); 
    public List<Child> Children { get { return _children; } } 
} 

class SomeOtherClass 
{ 
    void EvilParentConsumer() 
    { 
     Parent a = GetSomeParent(); 
     Parent b = GetSomeParent(); 

     //Kidnap all of b's children and give them to a!!! 
     a.Children.AddRange(b.Children); 
     b.Children.Clear(); 
    } 
} 

、あなたはReadOnlyCollectionとしてプライベートリストを露光することにより、これを防ぐことができます。要件を許可する場合は、コレクションに要素を追加する方法を公開しないIEnumerable<T>としてコレクションを公開することもできます。

関連する問題