変奏現実

パソコンやMMORPGのことなどを思いつくまま・・・記載されている会社名・製品名・システム名などは、各社の商標、または登録商標です。

この画面は、簡易表示です

C#

[C#]Type.FindMembersとか

Type.GetType({型名})で取得できるタイプの中身を調べるType.FindMembersで見つけたサンプルをちょっこっと加工したもの。

// ToSearch フィルター
public static bool ToSearch(MemberInfo objMemberInfo, Object? objSearch)
{
    // Compare the name of the member function with the filter criteria.
    return true; // 常にtrueなのでFilterはnull以外なら何でもいい。
}
// FindMembers:MemberTypes.xxxx
public static void GetMemberTypes(Type t, MemberTypes mt, List<string> list)
{
    string filter = "*"; // 実はnull以外なら何でもいい。
    var mems = t.FindMembers(mt,
        BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance,
        new MemberFilter(ToSearch),
        filter);
    if (mems.Length > 0)
    {
        for (int j = 0; j < mems.Length; j++)
        {
            list.Add($"{t} {mt}'s supported: {mems[j].ToString()}.");
        }
    }
    else
    {
        // list.Add($"{t} does not implement the {mt}'s {filter}.");
    }
}
// GetMemberTypesAll
public static void GetMemberTypesAll(Type t, List<string>list)
{
    if (!listA.Exists(x => x == t.FullName))
    {
        listA.Add(t.FullName);
        GetMemberTypes(t, MemberTypes.Constructor,list);
        GetMemberTypes(t, MemberTypes.Custom, list);
        GetMemberTypes(t, MemberTypes.Event, list);
        GetMemberTypes(t, MemberTypes.Field, list);
        GetMemberTypes(t, MemberTypes.Method, list);
        GetMemberTypes(t, MemberTypes.NestedType, list);
        GetMemberTypes(t, MemberTypes.Property, list);
        GetMemberTypes(t, MemberTypes.TypeInfo, list);
        //以下はオマケ。
        GetTypeInterfaces(t, list);
        GetMembers(t, list);
    }
}
// FindInterfaces
public static List<string> listA = new();
public static void GetTypeInterfaces(Type t, List<string> list)
{
    string filter = "*";
    TypeFilter myFilter = new TypeFilter(ToSearch);
    Type[] myInterfaces = t.FindInterfaces(myFilter, "*");
    if (myInterfaces.Length > 0)
    {
        list.Add($"{t} implements the interface {filter}.");
        for (int j = 0; j < myInterfaces.Length; j++)
        {
            list.Add($"> Interfaces supported: {myInterfaces[j]}.");
            //
            string iTypename = myInterfaces[j].ToString();
            Type? t2 = Type.GetType(iTypename);
            if (t2 != null)
            {
                if (!listA.Exists(x => x == t2.FullName))
                {
                    List<string> list2 = new List<string>();
                    GetMemberTypesAll(t2, list2);
                    list.AddRange(list2);
                    listA.Add(t2.FullName);
                }
            }
        }
    }
    else
    {
        // list.Add($"{t} does not implement the interface {filter}.");
    }
}
// GetMembers
public static void GetMembers(Type t, List<string> list)
{
    // Get the MemberInfo array.
    MemberInfo[] members = t.GetMembers();
    // Get and display the name and the MemberType for each member.
    list.Add($"Members of {t.Name} ({members.Length})");
    foreach (var member in members)
    {
        MemberTypes memberType = member.MemberType;
        list.Add($"> {member.Name}: {memberType}");
    }
}

をこんな感じで呼び出す。

// 「コンソール・アプリ(>NET Framework)」のC#は、newの型省略表記やNull容認mの指定等が未対応の為
// 「コンソール・アプリ」でプロジェクトを作成。
// プロジェクトへのCOM参照: Microsoft ActiveX Data Object 6.1 Library
// using System.Reflection;

// コンパイラが変数の型宣言に伴う処理を行うことで
// Type.GetType("ADODB.Connection")で情報を得られる様にする。
public static ADODB.Connection dummy = null;
public static ADODB.Recordset? recordset = null;
public static ADODB.Connection? connection = null;
public static ADODB.Field? field = null;
//
public static void Main(string[] args)
{
    Type? t = Type.GetType("ADODB.Connection");
    List<string> list = new ();
    GetMemberTypesAll(t, list);
    //結果表示
    Console.Write("\r\n" + string.Join("\r\n", list.ToArray()) + "\r\n");
}

実行してみると、

ADODB.Connection implements the interface *.
> Interfaces supported: ADODB._Connection.
ADODB._Connection Method's supported: System.String get_ConnectionString().
ADODB._Connection Method's supported: Void set_ConnectionString(System.String).
ADODB._Connection Property's supported: System.String ConnectionString.
ADODB._Connection implements the interface *.
> Interfaces supported: ADODB.Connection15.
ADODB.Connection15 Method's supported: System.String get_ConnectionString().
ADODB.Connection15 Method's supported: Void set_ConnectionString(System.String).
ADODB.Connection15 Property's supported: System.String ConnectionString.
ADODB.Connection15 implements the interface *.
> Interfaces supported: ADODB._ADO.
Members of _ADO (0)
Members of Connection15 (3)
> get_ConnectionString: Method
> set_ConnectionString: Method
> ConnectionString: Property
> Interfaces supported: ADODB._ADO.
Members of _Connection (3)
> get_ConnectionString: Method
> set_ConnectionString: Method
> ConnectionString: Property
> Interfaces supported: ADODB.Connection15.
> Interfaces supported: ADODB._ADO.
> Interfaces supported: ADODB.ConnectionEvents_Event.
Members of ConnectionEvents_Event (0)
Members of Connection (0)ts_Event (0)
Members of Connection (0)

ほとんど情報を得られなかった。


  • タグ:

[C#]Type.GetTypeFromProgID

64ビットの環境では、GetTypeFromProgIDで得たタイプはSystem.__ComObjectにラップされているらしく何も情報が取得できないので、PowerShellのGet-Memberを借りてプロパティやメソッドの情報を得るしかない様に思えたが・・・

プロジェクトにADODBの参照を追加した時点で、

ADODB.Connection cn = null;

と書けるようになるのだから、”ADODB.xxxx”の大半の名前の問題が解消されているハズ。

実際に上をコードすると、

Type.GetTypeFromProgIDの結果はそのままだけど、

Type?t = Type.GetType("ADODB.Connection");

で、それっぽいタイプが得られる。

ADODB.Fieldは、Type.GetTypeFromProgIDでTypeを得られないので、ソースに変数を宣言しないと全く取得できなかった。

public static ADODB.Field? field = null;

これで、プロパティとかメソッドが見つかると思い、FindMembersを使っても大空振り。

ADODB.Connectionのツールチップにはinterface ADODB.Connection。

更にツールチップの逆アセンブル?リンクから

ADODB._Connectionが大元のインタフェースらしい

しかし、FindMembersを使っても ConnectionString くらいしか情報が得られない。

一方、FindInterfacesは、ADODB._Connection、ADODB.Connection15、ADODB._ADO、ADODB.ConnectionEvents_Eventを見つけてくるので、

FindMembersとFindInterfacesを組み合わせて、タイプを検索するC#コードを拡張していく様にすると、良い事があるかもしれない。

何度も何度も何度も・・・ビルドし直すのは面倒なんでやらないけど


  • タグ:

[C#]warning CS8602: null 参照の可能性があるものの逆参照です。

よく判らない警告が出る。

JsonArray arr = jsonNode.AsArray();
string[] paramArray = new string[arr.Count];
ArrayList list = new ArrayList();
for (int i = 0; i < arr.Count; i++)
{
    list.Add(arr[i].ToString()); ※「warning CS8602: null 参照の可能性があるものの逆参照です。」が発生する。
}
return paramArray;

正解は、

JsonArray arr = jsonNode.AsArray();
string[] paramArray = new string[arr.Count];
ArrayList list = new ArrayList();
for (int i = 0; i < arr.Count; i++)
{
    var ji = arr[i];
    list.Add((ji != null)?ji.ToString():"");
}
return paramArray;

arr[i] は何の型かは不定だから、var宣言の変数に格納するしか手段はない。

そう明示的に書けば、CS8602も大人しくなる。

が・・・

普通の型の配列子にはしつこい。

関数(... string?[]? paramArray) {
・・・
object?[] param = new object?[] { null, null, null, null};
if (paramArray != null)
{
    param[0] = paramArray[0].Replace("%EXEPATH%", Resource.GetExePath());
}
t.InvokeMember(methodName,
    BindingFlags.InvokeMethod,
    null,
    obj,
    param);

は、

関数(... string?[]? paramArray) {
・・・
object?[] param = new object?[] { null, null, null, null};
if (paramArray != null)
{
    var p0 = paramArray[0];
    if (p0 != null)
    {
        p0 = p0.Replace("%EXEPATH%", Resource.GetExePath());
    }
    param[0] = p0;
}
t.InvokeMember(methodName,
    BindingFlags.InvokeMethod,
    null,
    obj,
    param);



top