0

名前とリフレクションによるカスタマイズされた属性の存在に基づいて、クラスの特定のフィールドの値を取得しようとしています。私のカスタム属性は次のとおりです。

 [AttributeUsage (AttributeTargets.All, AllowMultiple=true)]
public sealed class ColumnAttribute : Attribute
{
    internal string name = "";
    internal string length = "";
    internal string precision = "";

    public ColumnAttribute() { }
    public ColumnAttribute(String name) { this.name = name; }
    public ColumnAttribute(String name, String length) { }
    public ColumnAttribute(String name, String length, String precision) { }

    public String Name { get { return name; } set { name = value; } }
    public String Length { get { return length; } set { length = value; } }
    public String Precision { get { return precision; } set { precision = value; } }
}

これを使用するサンプル クラスは次のとおりです。

class SampleEntity
{
    //private int number;
    public string name;
    //float marks;

    public virtual int Number { get; set; }
    public SampleEntity() { }
    public SampleEntity(int number)
    {
        this.Number = number;
    }
    public void conversation(string request, string response) { }

    public void ordinary() {
        Console.Write("This isn't ordinary...");
    }
    [ColumnAttribute (Name = "XWBCCD")]
    public String XWBCCD { get; set; }

    [ColumnAttribute (Name = "XWBNCD")]
    public String XWBNCD { get; set; }

私はまた、異なるフィールド名を持つ別のクラスを持っています:

 class SampleRepository
{

    [ColumnAttribute(Name = "XWBCCD")]
    public String SomeOtherFieldName { get; set; }

    [ColumnAttribute(Name = "XWBNCD")]
    public String XWBNCD { get; set; }

    [ColumnAttribute(Name = "XWBWCD")]
    public String XWBWCD { get; set; }
}

リフレクションを通じて、フィールド名ではなく属性「名前」パラメーターを一致させることで値をコピーしようとしています。問題は、リフレクション中に、フィールドに渡された getCustomAttributes() メソッドを介してそのような比較が行われないことです。この問題を解決するための私のアプローチ(これまでのところ失敗しています)は次のとおりです。最初に、objSrc(入力された最初のクラスの)とobjDesc(空の2番目のクラス)の2つのオブジェクトを渡します。

 FieldInfo[] srcFields = objSrc.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetProperty | BindingFlags.IgnoreCase |BindingFlags.FlattenHierarchy);
        FieldInfo[] destFields = objDest.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetProperty);

次に、すべてのフィールドでリフレクションを繰り返し実行しようとしています

foreach (FieldInfo srcFld in srcFields)
        {
            foreach (FieldInfo destFld in destFields)
            {
                if (((MemberInfo)srcFld).Name.Equals(((MemberInfo)destFld).Name)){
                    destFld.SetValue(objDest, srcFld.GetValue(objSrc));
                    break;
                }
                object[] srcAttr = srcFld.GetCustomAttributes(true);
                object[] destAttr = destFld.GetCustomAttributes(true);

                if (Utils.Length(srcAttr) == 1 && Utils.Length(destAttr) == 1){

                    if ((srcAttr[0]).Equals(destAttr[0]) && srcFld.FieldType.Equals(destFld.FieldType))
                        destFld.SetValue(objDest, srcFld.GetValue(objSrc));
                    else
                        break;
                }

            }
        }

null を返すため、GetCustomAttributes() メソッドで問題が発生します。

4

1 に答える 1

0

C# ではなく vb.net コードで申し訳ありませんが、まったく同じことを行っていた linqpad ファイルがたまたまありました。

(実際に本番環境に対応したコードではありませんが、アイデアが伝わることを願っています。)

Sub Main

    dim data as DataRow = GetSomeData.GetData(2311385).rows(0)

    dim dm as IDataMapper = new DataMapper()

    dim login as LoginData = dm.MapDataTo(of LoginData)(data)

    data.Dump()
    login.dump()

End Sub

public interface IDataMapper
    function MapDataTo(of T as {IDataMappable,new})(data as DataRow) as T
end interface

public interface IDataMappable
end interface

public class DataMapper
    implements IDataMapper
    Public Function MapDataTo(Of T As {New, IDataMappable})(ByVal data As System.Data.DataRow) As T Implements IDataMapper.MapDataTo
        dim mapToObj as new T
        dim properties() as PropertyInfo = gettype(T).GetProperties()
        for each propInfo as PropertyInfo in properties
            Dim attributes() As Attribute = propInfo.GetCustomAttributes(GetType(DataMappingAttribute), True)
            if attributes.length > 0 then
                Dim dataAttribute As DataMappingAttribute = CType(attributes(0), DataMappingAttribute)
                Dim column As String = dataAttribute.ColumnName
                Dim dataType As Type = dataAttribute.DataType
                propInfo.SetValue(mapToObj, Convert.ChangeType(data(column), dataType), Nothing)
            end if
        next
        return mapToObj
    end function
end class

<AttributeUsage(AttributeTargets.Property)> _
public class DataMappingAttribute
    inherits Attribute
    private _ColumnName as string
    Public readonly Property ColumnName() As String
        Get
            return _ColumnName
        End Get
    End Property
    private _DataType as Type
    Public readonly Property DataType() As Type
        Get
            return _DataType
        End Get
    End Property
    public sub new(ColumnName as string, DataType as Type)
        me._columnName = ColumnName
        me._DataType = DataType
    end sub 
end class


public class LoginData
    implements IDataMappable

    private _LoginID as integer
    <DataMappingAttribute("loginID",Gettype(integer))> _
    public property LoginID as integer
        get
            return _LoginID
        end get
        set(value as integer)
            _LoginID = value
        end set
    end property

    private _LoginName as string
    <DataMappingAttribute("loginName",Gettype(String))> _
    public property LoginName as string
        get
            return _LoginName
        end get
        set(value as string)
            _LoginName = value
        end set
    end property

    private _FirstName as string
    <DataMappingAttribute("firstName",Gettype(String))> _
    public property FirstName as string
        get
            return _FirstName
        end get
        set(value as string)
            _FirstName = value
        end set
    end property

    private _LastName as string
    <DataMappingAttribute("lastName",Gettype(String))> _
    public property LastName as string
        get
            return _LastName
        end get
        set(value as string)
            _LastName = value
        end set
    end property

    private _EmailAddress as string
    <DataMappingAttribute("emailAddress",Gettype(String))> _
    public property EmailAddress as string
        get
            return _EmailAddress
        end get
        set(value as string)
            _EmailAddress = value
        end set
    end property

end class

public class GetSomeData
    Public shared Function GetData(ByVal ID As Integer) As DataTable
            'return a datatable
    End Function
end class
于 2011-07-28T12:40:16.237 に答える