2016-07-15 59 views
0

我想從業務發送給服務對象:Accesing和保存動態對象

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>()); 
    } 

看那linkedobject是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' 

回答

1

LinkedObject創建爲匿名類型爲internal類型。如果訪問該對象的代碼不在同一個程序集中,則會出現該錯誤。調試器可以看到,因爲它使用了反射,但是當您嘗試通過dynamic訪問它時,您會看到錯誤(同樣因爲匿名類型是以內部方式生成的)。

但是你仍然可以通過反射來獲得它。

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

但是這樣會變得非常快。

如果你看看我的答案在這裏

How do you unit test ASP.NET Core MVC Controllers that return anonymous objects?

它使用引擎蓋下反射來訪問使用匿名類型的屬性的動態包裝提供。

同樣的理論適用,您可能可以使用該包裝來訪問linkedObject的屬性。

​​
0

從你的代碼似乎MerchantId已經是Guid,所以你只需要投它,而不是解析:

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

還是同樣的問題。 – Nerf