ラベル プロパティ の投稿を表示しています。 すべての投稿を表示
ラベル プロパティ の投稿を表示しています。 すべての投稿を表示

2016年5月25日

Kotlin から見た Java の getter / setter (getXXX / isXXX / setXXX)

Calling Java code from Kotlin - Getters and Setters の補足みたいな話。
Kotlin 1.0.2

Kotlin から Java のコードを呼ぶ際、getter / setter (getXXX / isXXX / setXXX メソッド) はプロパティとして扱える。
詳細なルールとしては、
getter
  • get{X} または is{X} で始まる引数無し・戻り値ありのインスタンスメソッド
    {X} は小文字と解釈されない文字、日本語でもOK
  • getXXX / isXXX でプロパティ名の規則が異なる
    • getHoge メソッド → hoge プロパティ
    • isHoge メソッド → isHoge プロパティ
  • isXXX の戻り値の型は問わない (Boolean 以外でも可)
setter
  • set{X} で始まる引数 1 つのインスタンスメソッド
  • 戻り値の有無は問わない (あってもいい)
  • 対になる getter が必要 (Kotlin は今の所 set-only プロパティをサポートしてないため)

[ルールのサンプル (Java)]

// Kotlin でプロパティになるケース (メソッドとして使用できない)
public class PropertySample {
    public String getName() { /* 略 */ }
    public void setName(String name) { /* 略 */ }
    // [Kotlin] public final var name: String!
    // getter/setter があるので var プロパティ

    public Boolean isKey() { /* 略 */ }
    public void setKey(Boolean key) { /* 略 */ }
    // [Kotlin] public final var isKey: Boolean!
    // getter が isXXX の場合、プロパティ名は同じ(isXXX)

    public Boolean getKey() { /* 略 */ }
    // [Kotlin] public final var key: Boolean!
    // getter が isXXX と getXXX の 2 つ存在する場合、プロパティも 2 つになる
    // setter は共通 (両方のプロパティから使用される)

    public int getId() { /* 略 */ }
    // [Kotlin] public final val id: Int
    // getter のみは val プロパティ

    public String getあ() { /* 略 */ }
    public String setあ(String あ) { /* 略 */ }
    // [Kotlin] public final var あ: String!
    // 日本語可、setter に戻り値があっても可
}

// Kotlin でプロパティにならないケース (メソッドとして使用できる)
public class NotPropertySample {
    // setter のみ
    public void setNum(int num) { /* 略 */ }

    // 小文字スタート
    public int geta() { /* 略 */ }

    // static メソッド
    public static int getStatic() { /* 略 */ }

    // プロパティ名がかぶる
    public String getUrl() { /* 略 */ }
    public String getURL() { /* 略 */ } // 全部大文字の場合、プロパティ名は小文字になる
}

雑記

isXXX は混乱の元になりそうなのであまり使いたくないところ。
でも Kotlin から Java を呼び出すケースって、おそらく既存ソースの再利用で isXXX がある可能性もそれなりにあって・・・

ちなみに Java から Kotlin のプロパティを使用する際は、逆のイメージ。
  • XXX プロパティ → getXXX / setXXX メソッド
  • isXXX プロパティ → isXXX / setXXX メソッド

2015年2月11日

プロパティのアクセシビリティと PropertyInfo

PropertyInfo を取得する際、アクセシビリティで混乱したので調査。

プロパティ定義 GetProperties の引数 BindingFlags PropertyInfo 情報
get
アクセサ
set
アクセサ
CanRead CanWrite GetMethod
.Attributes
SetMethod
.Attributes
public public Public Public Public
public private Public Public Private
private public Public Private Public
public - Public Public -
- public Public - Public
protected protected NonPublic Family Family
internal internal NonPublic Assembly Assembly
protected
internal
protected
internal
NonPublic FamORAssem FamORAssem
private private NonPublic Private Private
private - NonPublic Private -
- private NonPublic - Private
※GetMethod と SetMethod の MethodBase.Attributes は、Public/Private/Family/Assembly/FamORAssem
のみ抽出

[調査コード]

class Program
{
    static void Main(string[] args)
    {
        ShowPropInfo(new Props());
    }
    static void ShowPropInfo<T>(T source)
    {
        var t = typeof(T);
        Console.WriteLine("[Public]");
        ShowPropDetail(t.GetProperties(BindingFlags.Instance | BindingFlags.Public));

        Console.WriteLine();

        Console.WriteLine("[NonPublic]");
        ShowPropDetail(t.GetProperties(BindingFlags.Instance | BindingFlags.NonPublic));
    }
    static void ShowPropDetail(IEnumerable<PropertyInfo> props)
    {
        foreach( var prop in props ){
            Console.WriteLine("Name:{0} CanRead:{1} CanWrite:{2}",
                prop.Name, prop.CanRead, prop.CanWrite);

            if( prop.GetMethod != null ) Console.WriteLine(
                "  <Get> Name:{0} Attributes:[{1}]",
                prop.GetMethod.Name, prop.GetMethod.Attributes);

            if( prop.SetMethod != null ) Console.WriteLine(
                "  <Set> Name:{0} Attributes:[{1}]",
                prop.SetMethod.Name, prop.SetMethod.Attributes);
        }
    }
}

class Props
{
    public int plGetSet { get; set; }
    public int plGetpvSet { get; private set; }
    public int pvGetplSet { private get; set; }
    public int plGet { get { return 0; } }
    public int plSet { set { } }

    protected int ptGetSet { get; set; }
    internal int inGetSet { get; set; }
    protected internal int ptinGetSet { get; set; }

    private int pvGetSet { get; set; }
    private int pvGet { get { return 0;} }
    private int pvSet { set { } }
}

まとめ

  • get アクセサ/set アクセサのいずれかが public → BindingFlags.Public の対象
  • 上記以外 → BindingFlags.NonPublic の対象

  • get アクセサ無し → CanRead : False → GetMethod : null
  • set アクセサ無し → CanWrite : False → SetMethod : null

2014年4月7日

C#.NET でインデクサの名前変更

C#.NET のインデクサのデフォルトの名前は Item である。
機会は少ないが、下記のように Item を別のメンバの名前にする場合、そのままではコンパイルが通らない。

public class IndexerName
{
    // コンパイルエラーになる
    public string this[int index] { get { return index.ToString(); } }

    public string Item;
}

そこで、IndexerNameAttribute で、インデクサの名前を変更することができる。

using System.Runtime.CompilerServices;

public class IndexerName
{
    // インデクサの名前が"Indexer"になり、コンパイルエラーにならない。
    // ※変数名の禁則文字は使えない。(エラーになる)
    // ※VB からなら instance(0) の他に、instance.Indexer(0) でもアクセス可能
    [IndexerName("Indexer")]
    public string this[int index] { get { return index.ToString(); } }

    public string Item;
}

参考URL

2014年4月4日

プロパティの比較

項目 C#.NET VB.NET
静的プロパティ
読込専用プロパティ
書込専用プロパティ
get, set 毎のアクセス修飾子
引数付きプロパティ
インデクサ
自動プロパティ
自動プロパティの
get, set 毎のアクセス修飾子
自動プロパティの初期化
自動プロパティの
バッキングフィールド
<PropertyName>k__BackingField _PropertyName
※VB.NET の get, set 毎のアクセス修飾子は、Visual Studio 2008/2010 で可能、2003 では不可であることを確認。
MSDN を信じると Visual Studio 2005 から可能。

  • C#.NET

using System;
using System.Reflection;

class CSharpProperties
{
    // 静的プロパティ
    public static int SValue
    {
        get { return -1; }
        set { Console.WriteLine(value); }
    }

    // 読取専用プロパティ
    public int RValue { get { return 0; } }

    // 書込専用プロパティ
    public int WValue { set { Console.WriteLine(value); } }

    // get, set 毎のアクセス修飾子
    public int RWValue
    {
        get { return 0; } // 省略時はプロパティと同じ = public
        private set { Console.WriteLine(value); }
    }

    // 引数付きプロパティ -> 不可
    // public string ParamValue[int index] { get { return index.ToString(); } set { } }

    // インデクサ
    public string this[int index]
    {
        get { return index.ToString(); }
        set { Console.WriteLine("[{0}] = {1}", index, value); }
    }

    // 自動プロパティ
    public int AutoValue { get; set; }

    // 自動プロパティの get, set 毎のアクセス修飾子
    public int RAutoValue { get; private set; } // 外部から読取専用
    public int WAutoValue { private get; set; } // 外部から書込専用

    // 自動プロパティの初期化 -> 不可
    // public int IAutoValue { get; set; } = 1;

    // 自動プロパティのバッキングフィールドへのアクセス -> リフレクションで可能
    public void AccessToAutoValue()
    {
        var fi = this.GetType().GetField("<AutoValue>k__BackingField",
                                         BindingFlags.Instance | BindingFlags.NonPublic);
        Console.WriteLine(fi.GetValue(this));
    }
}

  • VB.NET

Imports System

Class VbProperties
    ' 静的プロパティ
    Public Shared Property SValue As Integer
        Get
            Return -1
        End Get
        Set(value As Integer)
            Console.WriteLine(value)
        End Set
    End Property

    ' 読取専用プロパティ
    Public ReadOnly Property RValue As Integer
        Get
            Return 0
        End Get
    End Property

    ' 書込専用プロパティ
    Public WriteOnly Property WValue As Integer
        Set(value As Integer)
            Console.WriteLine(value)
        End Set
    End Property

    ' get, set 毎のアクセス修飾子
    Public Property RWValue As Integer
        Get
            Return 0
        End Get
        Private Set(value As Integer)
            Console.WriteLine(value)
        End Set
    End Property

   ' 引数付きプロパティ
    Public Property ParamValue(ByVal index As Integer) As String
        Get
            Return index.ToString()
        End Get
        Set(value As String)
            Console.WriteLine("[{0}] = {1}", index, value)
        End Set
    End Property

    ' インデクサ
    Default Public Property Item(ByVal index As Integer) As String
        Get
            Return index.ToString()
        End Get
        Set(value As String)
            Console.WriteLine("[{0}] = {1}", index, value)
        End Set
    End Property

    ' 自動プロパティ
    Public Property AutoValue As Integer

    ' 自動プロパティの get, set 毎のアクセス修飾子 -> 不可
    ' Public Property RAutoValue As Integer
    '     Get
    '     Private Set
    ' End Property

    ' 自動プロパティの初期化
    Public Property IAutoValue As Integer = 1

    ' 自動プロパティのバッキングフィールドへのアクセス -> 直に可能
    Public Sub AccessToAutoValue()
        Console.WriteLine(_AutoValue)
    End Sub
End Class

まとめ(感想のようなもの)

get, set 毎のアクセス修飾子を設定できる C# のプロパティは、とても便利。
しかもインデクサ、自動プロパティでも可能!!
C# は、自動プロパティで get, set 毎のアクセス修飾子を設定できる点が便利。
ただ、インデクサ以外の引数付きプロパティは使えない・・・残念。

対する VB の利点は、引数付きプロパティが使えること、自動プロパティが初期化できること。
欠点としては、バッキングフィールドに簡単にアクセスできること。
バッキングフィールドと同じ名前のメンバが定義できず、地味に不便。

おまけ

C# から VB の引数付きプロパティへのアクセスは下記で可能。
・・・ダサい。

var instance = new VbProperties();
// getter
var temp = instance.get_ParamValue(1);
// setter
instance.set_ParamValue(1, "a");

検証環境

Windows 7 64bit/Visual Studio 2010 SP1/.NET 4.0

参考URL