访问和保存动态对象

本文关键字:对象 动态 保存 访问 | 更新日期: 2023-09-27 17:57:02

我想从服务发送到服务对象:

public abstract class Notification : AggregateRoot
{
    public string Title { get; set; }
    public string Content { get; set; }
    public DateTime Created { get; set; }
    public NotificationType NotificationType { get; set; }
}
public class Alert : Notification
{
    public object LinkedObject { get; set; }
    public bool WasSeen { get; set; }
}

从我的单元测试中:

[Theory, AutoNSubstituteData]
    public async void Send_NotificationIsAlertTypeDocumentDontExist_DocumentShouldBeCreatedAndNotificationSaved(
        IDocumentDbRepository<AlertsDocument> repository,
        CampaignAlertsSender sender,
        Alert notification
        )
    {
        // Arrange
        notification.NotificationType = NotificationType.Alert;
        notification.LinkedObject = new
        {
            MerchantId = Guid.NewGuid()
        };
        repository.GetItemAsync(Arg.Any<Expression<Func<AlertsDocument, bool>>>()).Returns((Task<AlertsDocument>) null);
        // Act
        await sender.SendAsync(notification);
        // Assert
        await repository.Received(1).GetItemAsync(Arg.Any<Expression<Func<AlertsDocument, bool>>>());
        await repository.Received(1).CreateItemAsync(Arg.Any<AlertsDocument>());
    }

看看链接对象,它object但我用new制作它。并将其发送到服务。

public override async Task SendAsync(Notification notification)
    {
        if(notification == null)
            throw new ArgumentNullException(nameof(notification));
        var alert = notification as Alert;
        if(alert == null)
            throw new ArgumentException();
        var linkedObject = alert.LinkedObject as dynamic;
        Guid merchantId = Guid.Parse(linkedObject.MerchantId); // here is problem! linkedObject "object" dont have "MerchantId". 
        var document = await Repository.GetItemAsync(doc => doc.MerchantId == merchantId);
        if (document == null)
        {
            document = new AlertsDocument
            {
                MerchantId = merchantId,
                Entity = new List<Alert>()
            };
            document.Entity.Add(alert);
        }
    }

这是问题!linkedObject "object" 没有 "MerchantId"。但是为什么?调试时,我在linkedObject中看到值MerchantId。怎么办?

错误:

    An exception of type 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException' occurred in mscorlib.dll but was not handled in user code
Additional information: 'object' does not contain a definition for 'MerchantId'

访问和保存动态对象

LinkedObject被创建为匿名类型,该匿名类型生成为internal类型。如果访问对象的代码不在同一程序集中,则会收到该错误。调试器可以看到,因为它正在使用反射,但是当您尝试通过反射访问它时dynamic会出现错误(再次因为匿名类型是作为内部生成的)。

但是,您仍然可以通过反射来获得它。

var linkedObject = alert.LinkedObject as dynamic;    
Guid merchantId = (Guid)linkedObject.GetType()
                           .GetProperty("MerchantId")
                           .GetValue(linkedObject, null);

但这很快就会变得混乱。

如果你看看我在这里提供的答案

如何对返回匿名对象的核心 MVC 控制器 ASP.NET 进行单元测试?

使用了动态包装器,该

包装器在后台使用反射来访问匿名类型的属性。

同样的理论也适用,你可以使用该包装器来访问linkedObject的属性。

var linkedObject = new DynamicObjectResultValue(alert.LinkedObject);
Guid merchantId = (Guid)linkedObject.MerchantId;

从您的代码来看,MerchantId 已经是一个 Guid ,所以你只需要强制转换它,而不是解析:

var linkedObject = (dynamic)alert.LinkedObject;
var merchantId = (Guid)linkedObject.MerchantId;