C# で Type.GetType(string)の戻り値がnullになる場合の対処方法

C# で Type.GetType(string)の戻り値がnullになる場合の対処方法

例えば以下のようにType.GetTypeを使用していても何故かnullが返ってきてしまうときがある。
もちろんクラスが存在しないから、などという落ちではない。
そのような状況に陥ったときの解決方法について解説する。

Type objType = obj.GetType();
string typeFullName = objType.FullName;
// 蛇足だが、AssemblyQualifiedNameとは
// アセンブリの名前を含む型のアセンブリ修飾名である。
string assemblyQualifiedName = objType.AssemblyQualifiedName;


// 何故か以下の2つの文はどちらもnullが返ってくる。
Type type1 = Type.GetType(typeFullName);
Type type2 = Type.GetType(assemblyQualifiedName)
前提環境
  • Windows 10
  • Visual Studio Professional 2019
  • .NET Framework 4.2
  • C#

コードのポイント

以下のようなメソッドを作成し、参照済みのAssamblyから一致したものを取得すればよい。
上記がnullで、これだと大丈夫なのは謎だが、うん、よくわからん。

public static Type GetTypeByAssemblyQualifiedName(string assemblyQualifiedName)
{
    foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
    {
        foreach (Type type in assembly.GetTypes())
        {
            if (type.AssemblyQualifiedName == assemblyQualifiedName)
            {
                return type;
            }
        }
    }
    return null;
}

C#のListを並び替える方法(数字や文字列以外にStruct(構造体)なども!)

概要

C#のListをどうやって並び替えていますか?
数字や文字列以外にStruct(構造体)など、各種ジェネリックでも対応可能な方法について解説します。

前提環境
  • Windows 10
  • Visual Studio Professional 2019
  • .NET Framework 4.2
  • C#

コードのポイント

  • ListはSortメソッドで並び替えが可能です。
  • Sortメソッドを使用すると、そのオブジェクトList自体が並び変えられます。
    (他の変数に代入したい場合はOrderByメソッドなどを使用します。)
  • compareToメソッドがある型を並び替える場合、Sortは引数無しでOKです。
    (正確にはIComparableインターフェースのある型)
  • compareToメソッドが無い場合、ラムダ式で比較内容を記載すると楽ちんです。(サンプルコード参照。)

サンプルコード

int(数値)のListの場合

List<int> intList = new List<int>();
// 追加は省略
intList.Sort();  // Sortを引数無しで呼び出す。

string(文字列)のListの場合

List<string> stringList = new List<string>();
// 追加は省略
stringList.Sort();  // Sortを引数無しで呼び出す。

Struct(構造体)のListの場合

// 下記のような構造体をdisplayNameで並び替える。
struct TestStruct
{
        public string name;
        public string displayName;
        public string description;
}

// 追加は省略
List<TestStruct> stList = new List<TestStruct>();

// Sort引数の中身をラムダ式で表現する。
// 以下の例はdisplayNameで並び替えを行っています。
// 今回のラムダ式の詳しい解説は下記に記載しています。
stList.Sort((a, b) => a.displayName.CompareTo(b.displayName));

ラムダ式の簡単な解説

そもそもSortの()の中には何を書くの?

  • マニュアルを参照すると4種類ぐらいありますが、今回紹介しているのは「Comparison<T>」です。
  • 「Comparison<T>」とは同じ型の 2 つのオブジェクトを比較する「メソッド」を表します。
  • そうです。「メソッド」を引数にするのです。普段、数字や文字列ばかりだと慣れないかもしれませんが、「メソッド」も引数にできるのです。
  • で、「Comparison<T>」ですが、「public delegate int Comparison<in T>(T x, T y);」というメソッドで、引数が2つ、返り値がint型のメソッドです。

なんでラムダ式?矢印の左のカッコと右側って何?

  • ラムダ式は「メソッド」の1つです。なので、Sortの()の「Comparison<T>」として書くことができます。
  • 「=>」の左が引数で、右側が処理内容です。
  • (a, b)なので、引数が2つです。右側の「a.displayName.CompareTo(b.displayName)」が処理内容です。本来なら{}で囲んで、returnも付ける必要がありますが、1行だけの場合はどちらも省略可能です。
  • つまり引数が2つで戻り値がint(compreToの結果を返す)ので、「public delegate int Comparison<in T>(T x, T y);」と一致したメソッドになります。

それはわかったけど戻り値と並び替えの関係性は?

「public delegate int Comparison<in T>(T x, T y);」の戻り値intと、並び替えの関係ですが以下のようになります。

戻り値意味
0より小さい引数aは引数bよりも小さい(昇順の並び替えで上にくる)
0引数aは引数bと同じ大きさ。並び替えない
0より大きい引数aは引数bよりも大きい(昇順の並び替えで下にくる)

C# 構造体のカスタム属性をつかったHTMLのセレクトボックス(ドロップダウン)の作成方法

概要

C#の構造体の情報を使ってHTMLのセレクトボックス(ドロップダウンともいうselectタグとoptionタグのやつ)を作成する場合、値であるvalueは構造体から取得できますが、実際に画面に表示させる文字列はどうやっていますか?
今回はそれらの情報をカスタム属性を使用して構造体に記載し、構造体のデータだけでセレクトボックスを作成する方法を解説します。

前提環境
  • Windows 10
  • Visual Studio Professional 2019
  • .NET Framework 4.2
  • C#

コードのポイント

  • カスタム属性「System.ComponentModel.DescriptionAttribute」を使うことで、構造体のメンバに対して説明の文字列を追加することができます。
  • 構造体のメンバをforeachで取得するにはEnum.GetValuesを使用します。
  • カスタム属性を取得するにはGetCustomAttributesを使用します。

サンプルコード

前提となる構造体

public enum FruitEnum
{
     [System.ComponentModel.DescriptionAttribute("りんご")]
     Apple = 1,

     [System.ComponentModel.DescriptionAttribute("みかん")]
     Orange = 2,

     [System.ComponentModel.DescriptionAttribute("パイナップル")]
     Pine = 3,
}

HTMLのセレクトボックス(ドロップダウン)の作成

Type type = typeof(FruitEnum);
string inputHtml = "<select name=\"fruitName\">";

// 構造体の各メンバの値をforeachで取得する。
foreach (Object enumVal in Enum.GetValues(type))
{
    // 構造体の値からメンバを取得
    FieldInfo enumField = type.GetField(enumVal.Tostring());

    // 構造体のメンバに設定したカスタム属性を取得する。
    // カスタム属性は同じものを複数設定できることがあるため、配列で取得することになる。
    // そのためFirstOrDefaultで1つに絞り込む。
    var attributes = (DescriptionAttribute[])enumField.GetCustomAttributes(typeof(DescriptionAttribute), false);
    var desciptionstring = attributes.Select(n => n.Description).FirstOrDefault();
    string enumName = desciptionstring.Tostring();

    inputHtml += $"<option value=\"{enumVal.Tostring()}\">{enumName}</option>";
}
inputHtml += $"</select>";

Formから取得したデータ(文字列)を構造体に変換する場合

string value = Page.Request.Form["fruitName"];

FruitEnum fruit;
if (! Enum.TryParse<FruitEnum>(value, out fruit)) {
    fruit = FruitEnum.Apple;
}

C#で文字列から構造体への変換

概要

構造体はそのまま使用するのがコード上で求められるわけですが、DBのデータから取得した値や、WebのHTML Formなどで送信されてきた値を構造体に変換させることが求められることがあります。 そこで、「文字列」のデータを「構造体」のデータに変換させる方法について記載します。

前提環境
  • Windows 10
  • Visual Studio Professional 2019
  • .NET Framework 4.2
  • C#

コードのポイント

変換不可能な場合がありますから、TryParseを使って変換可能か確認しつつ値を変換します。
TryParseの第2引数は out を使うことで参照渡しとなり、変換可能な場合に値が入ります。

サンプルコード

public enum FruitEnum
{
    Apple,
    Orange,
    Pine,
}

public class Test
{
    public void getEnum(String enumCode)
    {
        FruitEnum fruit;
        // ジェネリックで型指定を忘れないように!
        if (! Enum.TryParse<FruitEnum>(enumCode, out fruit)) {
           fruit = FruitEnum.Apple;
        }

// 以下省略

C#で複数の型を持つ多次元配列(型指定あり)を作る

概要

PHPでは以下のような型の異なる多次元配列を作成することが可能です。
このような多次元配列をC#でも作成する方法について解説します。

$list = [
    ["TV", 25]
    ["Table", 80],
];
前提環境
  • Windows 10
  • Visual Studio Professional 2019
  • .NET Framework 4.2
  • C#

コードのポイント

複数の型をもつデータを持つにはいろいろな方法があります。
Class(クラス)やStruct(構造体)がまず思いつきますが、コード上のその場限りで使うにはふさわしくありません。
そこで今回はTuple(タプル)を使うことにします。このTupleのデータに対してListを使って配列化していきます

サンプルコード

public function createTable() {
    // Tupleを使って、文字列や数字、メソッド(関数)などの型を持つデータ構造を作ります。
    // そのTupleの型をListのジェネクリックに指定して多次元配列とします。
    // 戻り値無しのメソッドの型はAction。戻り値がある場合はFuncを使います。
    // Actionの後ろの<int>は引数のジェネリックで、第一引数のintを示します。
    List<Tuple<string, int, Action<int>, Action>> list = new List<Tuple<string, int, Action<int>, Action>>();
    
    // Tupleをnewする場合は、後ろの丸括弧内に値を記載します。
    list.Add(new Tuple<string, int, Action<int>, Action>("TV", 23, ShowTVSize, ShowTVPrice));
    list.Add(new Tuple<string, int, Action<int>, Action>("Table", 90, ShowTableSize, ShowTablePrice));
 
   // foreachでTupleのListデータを取得する場合はこのような記載になります。
    foreach (Tuple<string, int, Action<int>, Action> tuple in list)
    {
        // Tupleの値はItem1, Item2となりますが、可読性が低いので変数を用意します。
        string name = tuple.Item1;
        int size = tuple.Item2;
        Action<IConfig> showSizeMethod = tuple.Item3;
        Action showPriceMethod = tuple.Item4;

/*
 * 途中省略
 */

// TVのサイズを表示するメソッド
public void ShowTVSize(int size)
{
    System.Console.WriteLine("TV Size is {0}", size * 2.54);
}

// 食卓のサイズを取得するメソッド
public void ShowTVSize(int size)
{
    System.Console.WriteLine("Table Size is {0}", size);
}

// TVの金額を取得するメソッド
public void ShowTVPrice()
{
    System.Console.WriteLine("TV Price is 25,000");
}

// 食卓の金額を取得するメソッド
public void ShowTVPrice()
{
    System.Console.WriteLine("Table Price is 10,000");
}