M-Y-Y
@M-Y-Y

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

C# Dictionaryの定義をシンプルにできないでしょうか?

プログラムの中で同じ型のDictionaryを何度も使うのですが、
関数の引数や一旦ローカル変数に取っておきたいときなどいちいち長々と宣言するのが気になってきました。

public enum Time
{
    MORNING,
    DAY,
    NIGHT
}

// 何度も型を宣言するの面倒↓↓
private Dictionary<Time, int> Dummy(Dictionary<Time, int> time)
{
    var newTime = new Dictionary<Time, int>();

    foreach(var t in time)
    {
        // いろいろ処理
    }

    return newTime;
}
// クラス的な感じで書けないか…?
private Time Dummy(Time time)

素直にクラスにすれば良い気もするのですがforeachで色々処理したいときもあり、良い定義の仕方が思いついていません。
うまい検索ワードも浮かばず、なにかヒントでもあれば教えていただけないでしょうか…。
それともそもそもあまり気にせず毎回宣言しておくべきなのでしょうか。

0

5Answer

とりあえず

using XXX = Dictionary<Time, int>;

(これじゃ不足だからこその質問なのだろうけど)

1Like

Comments

  1. たぶんそれが質問者の人の望んでいるものに一番近いんじゃないかと思います。
    コードをすっきりさせたいのなら、新たな型は作らずエイリアスで済ませる方が意図しない副作用が起きにくいかと。

    using Dic_TimeInt = System.Collections.Generic.Dictionary<Time, int>;
    using KeyValue_TimeInt = System.Collections.Generic.KeyValuePair<Time, int>;

  2. @M-Y-Y

    Questioner

    ありがとうございます。
    最初これだ!と思ったのですが、usingエイリアスをグローバルに使用する方法が見つけられず、ファイル毎に都度書くのもいかがなものかと思いまして…。
    でも変に凝るよりもこちらの方が安全なのかもしれません…。

  3. usingエイリアスをグローバルに使用する方法が見つけられず、ファイル毎に都度書くのもいかがなものか

    私も見つけられず,そして同様に「ファイル毎に…いかがなものか」と思います.
    CやC++でいうところの typedef 相当のことが C# ではできないんですよね.

    using XXX = Dictionary<Time, int>;XXX の部分に適切な名前を付けられる場合,その名前が示すような機能を有する class を作る方向に考えるとか何とかができるかもしれませんが,それはそれ.
    「ただただ長い名前をどうにかしたいだけ」というときに取れる適切な手段が無い.

  4. 「エイリアスをグローバルに定義可能」は「エイリアスをどこで定義しているか探しにくい」と表裏一体ですからね…
    そしてその定義は.csproj単位になるだろうから、「DLLとのやり取りに使う長い名前」なんかはDLLを利用する側でも再度エイリアス定義が必要になります。

    CやC++でいうところの typedef 相当のことが C# ではできないんですよね.

    一応T4 テキスト テンプレートソース ジェネレーターを使えばVisualStudioだけで可能です。
    とはいえこれらはC/C++のプリプロセッサやテンプレート機能の代替&強化したもののような位置づけなので、単にエイリアス定義に使うには大げさな上にめんどくさすぎて「可能ではあるけどやりたいとは思わない」なんですよね。

    「structやenumには使えないけどclassなら(@radian-jpさんが書いたような)プレーンな継承クラスで実現できるから、新たな文法を追加するには必要性が弱い」と判断されてるのかも。

  5. .NET6以上なら、global usingが使えますね。

  6. global usingは名前空間の省略のみで、エイリアス定義のusingはglobalにできないと思います。

  7. 試してみましたが、特に問題なさそうです。

    Global.cs
    global using DicTime = System.Collections.Generic.Dictionary<MyProgram.Time, int>;
    
    Program.cs
    using System;
    
    namespace MyProgram
    {
        public enum Time
        {
            MORNING,
            DAY,
            NIGHT
        }
    
        class Program
        {
            static void Main(string[] args)
            {
                var dic = new DicTime();
                dic[Time.MORNING] = 5;
                dic[Time.DAY] = 8;
                dic[Time.NIGHT] = 6;
    
                foreach(var entry in dic)
                {
                    Console.WriteLine(entry);
                }
    
                Console.ReadKey();
            }
        }
    }
    

    (出力結果)
    [MORNING, 5]
    [DAY, 8]
    [NIGHT, 6]

  8. おお、できるのですね。
    失礼しました。

  9. @M-Y-Y

    Questioner

    私もエイリアスには使えないと思っていました…!
    今のバージョンだと使えないのですが
    自分用の個人開発なので.NETのバージョンあげてしまいます。
    @radian-jpさんありがとうございます。これでいきます!

    皆様色々と相談のっていただいてありがとうございました:bow:

Comments

  1. @M-Y-Y

    Questioner

    ありがとうございます。基礎的なことは大体大丈夫です:bow:

おっしゃるとおり、素直にクラス化するのが良いと思います。
foreach で対応するならば、IEnumerable を実装することで対応できるようになりますが、一番手っ取り早いのは、Dictionaryのサブクラス化ですね。

public enum Time
{
    MORNING,
    DAY,
    NIGHT
}

public class TimeDictionary : Dictionary<Time, int>
{
  // 必要に応じてお好きな処理を実装。
}

public static TimeDictionary Dummy(TimeDictionary time)
{
    var newTime = new TimeDictionary();

    foreach(var t in time)
    {
        // いろいろ処理
    }

    return newTime;
}
0Like

Comments

  1. @M-Y-Y

    Questioner

    ありがとうございます。
    これが求めていたものという気がしています!

×Dictionaly
〇Dictionary
ですね。質問文、タグ、タイトルの訂正をお願いします。

    private class MyTime : Dictionary<Time, int> { }

    private MyTime Dummy(MyTime time)
    {
        var newTime = new MyTime();

        foreach (var t in time)
        {
            // いろいろ処理
        }

        return newTime;
    }

こういう事がしたいのかな?
ただ、宣言が長いからという理由で継承したクラス作るのはおすすめしません。
Dictionaryを使ってどういう処理をやっているかが分かれば、他の実装の提案もできるかもしれませんが。

0Like

Comments

  1. @M-Y-Y

    Questioner

    ありがとうございます。
    タイポは修正しました。GoogleIMEめ…。

    継承クラスが一番求めていたものなのと思っているのですが、
    もっとクラスを活用できるような気もします…。

    
    public enum Time
    {
        MORNING,
        DAY,
        NIGHT
    }
    
    // こんなクラスがあって
    public class Person
    {
        // キーは1つだけだったり全部あったり
        public Dictionary<Time, int> realCalorie = new Dictionary<Time, int>();
        public Dictionary<Time, int> idealCalorie = new Dictionary<Time, int>();
    }
    
    // こんな感じや
    var total = person.realCalorie.Select(n => n.Value).Sum();
    
    // 存在するキーの分だけテキストボックスを作ったり
    // 別の画面で同じくボタンを作ったり
    var inputs = new Dictionary<Time, TextBox>();
    foreach(var c in person.realCalorie)
    {
        inputs[c.Key] = new TextBox
        {
            Text = c.Value.ToString()
    
        };
    }
    
    
    

TKey が MORNING, DAY, NIGHT の 3 つしか取れない Dictionary の存在意味が分かりません。foreach(var t in time) の time がどこから来たのか分かりません・・・が、そこは本題ではなさそうなのでちょっと置いといて。

foreachで色々処理したいときもあり

その「処置」というのが具体的に何なのか書いてもらえるといろいろ案も出てくるのではなかろうかと思います。書けませんか?

foreach で処理したいから質問に書いてあったようなコードにできないのですよね? 処理できれば質問のコードが望みなのですよね?

0Like

Your answer might help someone💌