2

リフレクションを使用して、DTO (xSearchQuery) から 1 つのクラス (xSearchObject) にマップ (プロパティを設定) しています。達成しようとしていることを簡単に確認できるように、コードを削減しようとしました。変えることはできませんがSearchField、変えることはできますDTOSearchField

  • ソース クラスには、タイプ のn 個のプロパティがありDTOSearchField<T>ます。
  • 宛先クラスには、タイプ のn 個のプロパティがありSearchField<T>ます。
  • ソースと宛先には、同じ名前の同じ数のプロパティがあります。

ソース クラス プロパティ タイプ

public class DTOSearchField<T> : IDTOSearchField
{
  public T EqualTo;
}

宛先クラス プロパティ タイプ:

public class SearchField<T> : ISearchField
{
  public void WhereEquals(T value)
  {
    _clauses.Add(_name + " = " + Converter.ConvertValueToSql(value));
  }
    
  // etc
}

マッピング: ( Lightweight Object to Object Mapper に基づく) ジェネリックの代わりに、DTOSearchField<T>たとえばなどのクラスを持っていて、それらにキャストすると、マッピングを非常にうまく行うことができます。したがって、ソース プロパティごとに次のようになります。StringDTOSearchFieldIntDTOSearchField

if (sourceVal.GetType().IsAssignableFrom(typeof(StringDTOSearchField)))
{
  var destinationProperty = destinationPropertyAccessor.GetPropertyValue(destination, propertyMatch.DestinationProperty.Name) as SearchField<string>;

  var sourceStringField = sourceVal as StringSearchField;
  if (sourceStringField != null)
  {
    if (!string.IsNullOrEmpty(sourceStringField.EqualTo)) destinationProperty.WhereEquals(sourceStringField.EqualTo);
  }
}
else if (sourceVal.GetType().IsAssignableFrom(typeof(IntDTOSearchField)))
{
  // Etc
}

または、ジェネリックDTOSearchField<T>を保持して、以下に基づいて If-Then-elses を実行することもできます。

Type t = sourceVal.GetType().GetGenericArguments()[0];

適切な型にキャストするには、

しかし、私は次のようなことができるはずだと感じています:

Type t = sourceVal.GetType().GetGenericArguments()[0];
var destinationProperty = destinationPropertyAccessor.GetPropertyValue(destination, propertyMatch.DestinationProperty.Name) as SearchField<t>;
destinationProperty.WhereEquals(sourceVal.EqualTo.Value); 

sourceValis aDTOSearchField<T>destinationPropertyis aであり、どちらも T 型のプロパティを持っているためSearchField<T>、実行時まで T が何であるかを知らなくても問題ないように感じます。

T は実行時までわからないため、キャストが機能しないことを理解しています。可能なすべてのタイプのIf-Then-Else以外に、私が望むものを達成する方法はありますか? 私がそうしなければならない場合、ジェネリックを使用する利点を無効にしているようです。

ありがとう、

4

1 に答える 1

0

リフレクションを通じて WhereEquals メソッドを呼び出すこともできますが、次のようにジェネリックを活用することをお勧めします (DTOSearchField を変更するアクセス権があるため)。

public interface IDTOSearchField
{
    void MapToSearchField(ISearchField searchField);
}

public class DTOSearchField<T> : IDTOSearchField
{
    public T EqualTo;

    public void MapToSearchField(ISearchField searchField)
    {
        if (!(searchField is SearchField<T>))
        {
            throw new ArgumentException("SearchField must be of type " + typeof(T).FullName + ".", "searchField");
        }

        ((SearchField<T>)searchField).WhereEquals(EqualTo);
    }
}

次に、インターフェイスでこの新しいメソッドを使用して、次のようにマップできます。

    public void MapField(IDTOSearchField source, ISearchField destination)
    {
        source.MapToSearchField(destination);
    }

DTOSearchField クラスに SearchField クラスの知識を持たせたくない場合は、これを回避する方法がありますが、この回答については議論が多すぎます。

于 2012-12-23T14:09:54.197 に答える