[英]Getting the value of a generic property at run time
我正在使用代理和拦截器进行日志记录。 我要记录的属性之一是Rabbit MQ的消息ID。
我们正在使用以下对象:
namespace MassTransit
{
public interface ConsumeContext<out T> : ConsumeContext, MessageContext, PipeContext, IPublishEndpoint, IPublishObserverConnector, ISendEndpointProvider where T : class
{
T Message { get; }
/// <summary>Notify that the message has been consumed</summary>
/// <param name="duration"></param>
/// <param name="consumerType">The consumer type</param>
Task NotifyConsumed(TimeSpan duration, string consumerType);
/// <summary>
/// Notify that a fault occurred during message consumption
/// </summary>
/// <param name="duration"></param>
/// <param name="consumerType"></param>
/// <param name="exception"></param>
Task NotifyFaulted(TimeSpan duration, string consumerType, Exception exception);
}
}
这是我在拦截中需要掌握的通用消息。
我可以成功地将其转换为对象:
ConsumeContext<AuthenticationDataRequest>
在Visual Studio中,一旦我将其投射,就会弹出Message对象(不投射就没有MessageObject)。
要进行投射,我使用以下通用方法:
public Guid? RunMessageRetrieve(dynamic obj, Type castTo)
{
MethodInfo castMethod = GetType().GetMethod("GetMessageIdFromContext").MakeGenericMethod(castTo);
return castMethod.Invoke(null, new object[] { obj }) as Guid?;
}
public static Guid? GetMessageIdFromContext<T>(dynamic context) where T : class
{
Guid? messageId = null;
try
{
var contextCasted = (T)context;
Type contextType = contextCasted.GetType();
var message = contextCasted.GetType().GetProperty("Message");
if (message != null)
{
messageId = message.GetType().GetProperty("MessageId").GetValue(message) as Guid?;
}
}
catch (InvalidCastException castException)
{
Console.WriteLine("Could not retrieve message Id from context message as the cast failed");
}
catch (NullException nullException)
{
Console.WriteLine("Could not retrieve message Id from context as the message Id did not exist");
}
return messageId;
}
在这里,您可以在Visual Studio中看到消息,在其中我可以得到消息ID:
但是我尝试使用反射来获取实际的消息属性,因为当然我不知道在编译时的类型,而且似乎无法解决它。 以下为空,因为它当然是通用类型:
var message = contextCasted.GetType().GetProperty("Message");
这必须是可行的,因为在拦截之后调用实际方法时,它具有消息的正确对象。
只需将其转换为具有所需属性的接口,然后使用它即可。 不需要反思。
public static Guid? GetMessageId<T>(ConsumeContext<T> input) where T : class
{
var casted = input as ConsumeContext<IMessage>;
if (casted == null) return null;
return casted.Message.MessageId;
}
示例程序:
public class Program
{
public static Guid? GetMessageId<T>(ConsumeContext<T> input) where T : class
{
var casted = input as ConsumeContext<IMessage>;
if (casted == null) return null;
return casted.Message.MessageId;
}
public static void Main()
{
var exampleObject = new MyClass<Message>();
exampleObject.Message = new Message { MessageId = new Guid("00000001-0002-0003-0004-000000000005") };
var messageId = GetMessageId(exampleObject);
Console.WriteLine(messageId.Value);
}
}
输出:
00000001-0002-0003-0004-000000000005
如果必须向下转换,它也可以工作,即,即使T
是特定类型的消息,您仍然可以将其强制转换为公开消息的接口或基类。
public static void Main()
{
var exampleObject = new MyClass<SpecificMessage>();
exampleObject.Message = new SpecificMessage { MessageId = new Guid("00000001-0002-0003-0004-000000000005") };
var messageId = GetMessageId(exampleObject);
Console.WriteLine(messageId.Value);
}
最后,我继续进行以下工作,请客,我没想到立即像这样直接使用Type。 动态参数使事情变得混乱:
public static Guid? GetMessageIdFromContext(object context, Type contextType)
{
Guid? messageId = null;
try
{
var contextProp = contextType.GetProperty("Message");
if (contextProp != null)
{
var message = contextProp.GetValue(context);
if (message != null)
{
messageId = message.GetType().GetProperty("UniqueId").GetValue(message) as Guid?;
}
}
}
catch (NullException nullException)
{
Console.WriteLine("Could not retrieve message Id from context as the message Id did not exist");
}
return messageId;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.