До сих пор я предполагал, что динамический тип просто «отключает» проверку типов во время компиляции и делает что-то похожее на приведение типов, когда сообщение вызывается в динамическом экземпляре. Очевидно, что-то еще происходит.
Прикрепленный тестовый пример NUnit показывает мою проблему: используя динамический тип, я могу использовать метод, доступный только в конкретном подклассе, но я не могу сделать то же самое с использованием приведения (приводит к InvalidCastException). Я бы предпочел сделать приведение, так как это дает мне полное завершение кода в VS.
Может кто-нибудь объяснить, что происходит, и / или дать мне подсказку, как я могу получить завершение кода в моем случае без необходимости переопределения метода WorkWithAndCreate в каждом конкретном подклассе?
ура, Йоханнес
using System;
using NUnit.Framework;
namespace SlidesCode.TestDataBuilder
{
[TestFixture]
public class MyTest
{
[Test]
public void DynamicWorks()
{
string aString = CreateDynamic(obj => obj.OnlyInConcreteClass());
Assert.AreEqual("a string", aString);
}
private static string CreateDynamic(Action<dynamic> action)
{
return new MyConcreteClass().WorkWithAndCreate(action);
}
[Test]
public void CastingDoesNotWorkButThrowsInvalidCastException()
{
string aString = CreateWithCast(obj => obj.OnlyInConcreteClass());
Assert.AreEqual("a string", aString);
}
private static string CreateWithCast(Action<MyConcreteClass> action)
{
return new MyConcreteClass().WorkWithAndCreate((Action<MyGenericClass<string>>) action);
}
}
internal abstract class MyGenericClass<T>
{
public abstract T Create();
public T WorkWithAndCreate(Action<MyGenericClass<T>> action)
{
action(this);
return this.Create();
}
}
internal class MyConcreteClass : MyGenericClass<string>
{
public override string Create()
{
return "a string";
}
public void OnlyInConcreteClass()
{
}
}
}
Вот пример отформатированного реального мира из моего комментария:
Customer customer = ACustomer(cust =>
{
cust.With(new Id(54321));
cust.With(AnAddress(addr => addr.WithZipCode(22222)));
});
private static Address AnAddress(Action<AddressBuilder> buildingAction)
{
return new AddressBuilder().BuildFrom(buildingAction);
}
private static Customer ACustomer(Action<CustomerBuilder> buildingAction)
{
return new CustomerBuilder().BuildFrom(buildingAction);
}
В нем отсутствуют некоторые детали, но я надеюсь, что это проясняет цель.