QA@IT
«回答へ戻る

回答を投稿

結論が出ないまま終わるのも残念なので
unibonさんの提示した内容に合うと思われるコードを書いてみました。

1つ目がkey検査付きの基本となるクラス。
2つ目が今回の提示されたキーチェック条件を実装したもの。
3つ目がFormによる呼び出し例で2つのテキストボックスにkeyと値を入れ
Exceptionは派生クラスを作成しています。
Add優先の処理、Update優先の処理をそれぞれ行うものです。
AddなのかUpdateなのかはチェックしてみないと分からないのでこのような処理で
試す必要があるかと思い2通り用意してみました。Addを呼ぶかUpdateを呼ぶかに
関わらず間違ったメソッドを呼ぶと例外が発生してしまい効率が悪い気がしました。
中身を見ずにAddをするかUpdateをするか決められるのなら間違い発生時に例外と
なるので早期に修正することが出来るかとは思います。提示されたような最初に有効な
キーをAddしてしまえる固定キーのパターンでは有効かもしれません。

    public class DicWithKeyCheck<Tkey, TValue>:IEnumerable<KeyValuePair<Tkey,TValue>>
    {
        private Dictionary<Tkey,TValue> _dic;

        public DicWithKeyCheck()
        {
            _dic = new Dictionary<Tkey, TValue>();
        }

        virtual public Boolean CheckKey(Tkey key)
        {
            return true;
        }

        public void Add(Tkey key, TValue value)
        {
            if (CheckKey(key))
            {
                if (!_dic.ContainsKey(key))
                {
                    _dic.Add(key, value);
                }
                else
                {
                    throw new KeyExistsException("keyが既に存在します。");
                }
            }
            else
            {
                throw new KeyInvalidException("Keyが不正です。");
            }
        }

        public void Update(Tkey key, TValue value)
        {
            if (CheckKey(key))
            {
                if (_dic.ContainsKey(key))
                {
                    _dic[key] = value;
                }
                else
                {
                    throw new KeyNotFoundException("keyが追加されていません。");
                }
            }
            else
            {
                throw new KeyInvalidException("Keyが不正です。");
            }           
        }

        IEnumerator<KeyValuePair<Tkey, TValue>> IEnumerable<KeyValuePair<Tkey, TValue>>.GetEnumerator()
        {
            return _dic.GetEnumerator();
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return _dic.GetEnumerator();
        }
    }
    class SampDicWithKeyCheck:DicWithKeyCheck<int,string>
    {
        public SampDicWithKeyCheck():base()
        {
        }

        public override bool CheckKey(int key)
        {
            int i1 = (int)Math.Floor(Math.Sqrt(key));
            if (i1 * i1 == key)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
    }
    public partial class Form1 : Form
    {
        private SampDicWithKeyCheck _sampdic;

        public Form1()
        {
            InitializeComponent();
            _sampdic = new SampDicWithKeyCheck();
        }


        private void button1_Click(object sender, EventArgs e)
        {
            //--- Add先の場合
            int key = int.Parse(textBox1.Text);
            string value = textBox2.Text;
            try
            {
                _sampdic.Add(key, value);
            }
            catch (KeyExistsException)
            {
                _sampdic.Update(key, value);
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            //--- Update先の場合
            int key = int.Parse(textBox1.Text);
            string value = textBox2.Text;
            try
            {
                _sampdic.Update(key, value);
            }
            catch (KeyNotFoundException)
            {
                _sampdic.Add(key, value);
            }
        }

        private void button3_Click(object sender, EventArgs e)
        {
            listBox1.Items.Clear();
            foreach(var kv in _sampdic)
            {
                listBox1.Items.Add(String.Format("key:{0} , value:{1}", kv.Key, kv.Value));
            }
        }


    }
結論が出ないまま終わるのも残念なので
unibonさんの提示した内容に合うと思われるコードを書いてみました。

1つ目がkey検査付きの基本となるクラス。
2つ目が今回の提示されたキーチェック条件を実装したもの。
3つ目がFormによる呼び出し例で2つのテキストボックスにkeyと値を入れ
Exceptionは派生クラスを作成しています。
Add優先の処理、Update優先の処理をそれぞれ行うものです。
AddなのかUpdateなのかはチェックしてみないと分からないのでこのような処理で
試す必要があるかと思い2通り用意してみました。Addを呼ぶかUpdateを呼ぶかに
関わらず間違ったメソッドを呼ぶと例外が発生してしまい効率が悪い気がしました。
中身を見ずにAddをするかUpdateをするか決められるのなら間違い発生時に例外と
なるので早期に修正することが出来るかとは思います。提示されたような最初に有効な
キーをAddしてしまえる固定キーのパターンでは有効かもしれません。

```
    public class DicWithKeyCheck<Tkey, TValue>:IEnumerable<KeyValuePair<Tkey,TValue>>
    {
        private Dictionary<Tkey,TValue> _dic;

        public DicWithKeyCheck()
        {
            _dic = new Dictionary<Tkey, TValue>();
        }

        virtual public Boolean CheckKey(Tkey key)
        {
            return true;
        }

        public void Add(Tkey key, TValue value)
        {
            if (CheckKey(key))
            {
                if (!_dic.ContainsKey(key))
                {
                    _dic.Add(key, value);
                }
                else
                {
                    throw new KeyExistsException("keyが既に存在します。");
                }
            }
            else
            {
                throw new KeyInvalidException("Keyが不正です。");
            }
        }

        public void Update(Tkey key, TValue value)
        {
            if (CheckKey(key))
            {
                if (_dic.ContainsKey(key))
                {
                    _dic[key] = value;
                }
                else
                {
                    throw new KeyNotFoundException("keyが追加されていません。");
                }
            }
            else
            {
                throw new KeyInvalidException("Keyが不正です。");
            }           
        }

        IEnumerator<KeyValuePair<Tkey, TValue>> IEnumerable<KeyValuePair<Tkey, TValue>>.GetEnumerator()
        {
            return _dic.GetEnumerator();
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return _dic.GetEnumerator();
        }
    }
```

```
    class SampDicWithKeyCheck:DicWithKeyCheck<int,string>
    {
        public SampDicWithKeyCheck():base()
        {
        }

        public override bool CheckKey(int key)
        {
            int i1 = (int)Math.Floor(Math.Sqrt(key));
            if (i1 * i1 == key)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
    }
```

```
    public partial class Form1 : Form
    {
        private SampDicWithKeyCheck _sampdic;

        public Form1()
        {
            InitializeComponent();
            _sampdic = new SampDicWithKeyCheck();
        }


        private void button1_Click(object sender, EventArgs e)
        {
            //--- Add先の場合
            int key = int.Parse(textBox1.Text);
            string value = textBox2.Text;
            try
            {
                _sampdic.Add(key, value);
            }
            catch (KeyExistsException)
            {
                _sampdic.Update(key, value);
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            //--- Update先の場合
            int key = int.Parse(textBox1.Text);
            string value = textBox2.Text;
            try
            {
                _sampdic.Update(key, value);
            }
            catch (KeyNotFoundException)
            {
                _sampdic.Add(key, value);
            }
        }

        private void button3_Click(object sender, EventArgs e)
        {
            listBox1.Items.Clear();
            foreach(var kv in _sampdic)
            {
                listBox1.Items.Add(String.Format("key:{0} , value:{1}", kv.Key, kv.Value));
            }
        }


    }
```