1

次の方法があるとします。

private static void SetLastModifiedTimeUser<TEntity>(TEntity entity) where TEntity : class
{
    PropertyInfo propertyInfo;

    propertyInfo = entity.GetType().GetProperty("LastModifiedUser");
    if (propertyInfo != null)
        propertyInfo.SetValue(entity, IdentityHelper.UserName, null);
}

ご覧のとおり、このメソッドはジェネリック型を受け入れます。このメソッドに渡されるすべてのクラスには、「LastModifiedUser」という名前のプロパティが含まれます。リフレクションを使用せずにこのプロパティにアクセスする方法はありますか?あるとは思いませんが、お願いしたいと思いました。

4

4 に答える 4

4

はい、すべてのエンティティにLastModifiedUserプロパティがある場合、すべてのエンティティを基本クラスから継承させるか、次のようなインターフェイスを実装できます

public interface IModifyable
{
    string LastModifiedUser { get; set; }
}

次に、この制約を追加するだけです(または、メソッドを非ジェネリックにして、 を受け入れますIModifyable

where TEntity : class, IModifyable

コードは次のようになります。

private static void SetLastModifiedTimeUser<TEntity>(TEntity entity) 
   where TEntity : class, IModifyable
{
   entity.LastModifiedUser = IdentityHelper.UserName;
}
于 2012-12-03T20:25:30.187 に答える
3

プロパティを定義するインターフェイスからクラスを継承させLastModifiedUserます。

public interface ILastModifiedUser
{
    public string LastModifiedUser { get; set; }
}

メソッド宣言を次のように変更します

private static void SetLastModifiedTimeUser(ILastModifiedUser entity)
于 2012-12-03T20:26:06.643 に答える
1

すべてのクラスを変更して共通のインターフェイスを実装できない場合は、使用できますdynamic

private static void SetLastModifiedTimeUser<TEntity>(TEntity entity) where TEntity : class
{
    dynamic d = entity;
    d.LastModifiedUser = IdentityHelper.UserName;
}

それ以外は、 Robert Harveyが示すように単純です。

于 2012-12-03T20:27:25.237 に答える
1

If you can't add an interface to your objects, consider this approach.

The first time it encounters each Type (TEntity), it looks up the property and gets the property's SetMethod. Then, on each use, it creates invokes the method.

var one = new EntityOne();
LastModifiedTimeUserSetter.Set(one);
Console.WriteLine(one.LastModifiedUser);

public static class LastModifiedTimeUserSetter
{
  public static void Set<TEntity>(TEntity entity)
  {
     var method = Properties.GetOrAdd(typeof (TEntity), GetSetMethod);
     var action = (Action<string>) Delegate.CreateDelegate(typeof (Action<string>), entity, method);
     action(IdentityHelper.UserName);
  }
  static MethodInfo GetSetMethod(Type type)
  {
     var prop = type.GetProperty("LastModifiedUser");
     if (prop == null)
        return null;
     return prop.GetSetMethod();
  }

  static readonly ConcurrentDictionary<Type, MethodInfo> Properties = new ConcurrentDictionary<Type, MethodInfo>();
}

Going further

There is a way to further improve performance by using the System.Reflection.Emit.MethodBuilder. And building a method that takes Entity and sets the property.

public static class LastModifiedTimeUserSetter
{
  public static void Set<TEntity>(TEntity entity)
  {
     var action = (Action<TEntity>) Properties.GetOrAdd(typeof(TEntity), CreateDynamicSetMethodDelegate);
     if(action != null)
        action(entity);
  }

  static Delegate CreateDynamicSetMethodDelegate(Type type)
  {
     return CreateDynamicSetMethod(type).CreateDelegate(GetActionType(type));
  }

  static DynamicMethod CreateDynamicSetMethod(Type typeWithProperty)
  {
     var methodBuilder = new DynamicMethod(
        "Dynamic_" + typeWithProperty.FullName + "_SetLastModifiedUser",
        typeof (void),
        new[] {typeWithProperty});
     EmitSimpleAssignmentMethod(methodBuilder,
                                GetIdentityHelperUserNameGetMethod(),
                                GetPropertySetMethod(typeWithProperty));
     return methodBuilder;
  }

  static MethodInfo GetIdentityHelperUserNameGetMethod()
  {
     return typeof(IdentityHelper).GetProperty("UserName").GetGetMethod();
  }

  static MethodInfo GetPropertySetMethod(Type type)
  {
     var prop = type.GetProperty("LastModifiedUser");
     if (prop == null)
        return null;
     return prop.GetSetMethod();
  }

  static void EmitSimpleAssignmentMethod(DynamicMethod methodBuilder, MethodInfo getMethod, MethodInfo setMethod)
  {
     var il = methodBuilder.GetILGenerator();
     il.Emit(OpCodes.Ldarg_0);
     il.EmitCall(OpCodes.Call, getMethod, null);
     il.EmitCall(OpCodes.Call, setMethod, null);
     il.Emit(OpCodes.Ret);
  }

  static Type GetActionType(Type type)
  {
     return typeof (Action<string>).GetGenericTypeDefinition().MakeGenericType(type);
  }

  static readonly ConcurrentDictionary<Type, Delegate> Properties = new ConcurrentDictionary<Type, Delegate>();
}

See an Article from MSDN magazine about XBOX Live.

于 2012-12-03T21:27:07.887 に答える