Why does the dynamic type work when casting does not work?

So far, my hunch has been that a dynamic type simply disables type checking at compile time and does something similar to type when a message is called in a dynamic instance. Obviously, something else is happening.

The attached NUnit test case shows my problem: using a dynamic type, I can use a method that is only available in a specific subclass, but I cannot do the same with cast (results in InvalidCastException). I would prefer to do a casting, as this gives me complete code completion in VS.

Can someone explain what is happening and / or give me a hint how can I get code completion in my case without rebuilding the WorkWithAndCreate method in each specific subclass?

greetings, Johannes

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

Here's a formatted real world example from my comment:

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

Some details are missing, but I hope this makes the goal clear.

+3
source share
2 answers

The reason dynamicis that it dynamicdoes not depend on knowing the compilation time of object types. MyGenericClass<string>doesn't have a method OnlyInConcreteClass(), but the instance you go through, of course, has a method and dynamicfinds it.

By the way, you can do it WorkWithAndCreatework as follows:

public T WorkWithAndCreate<T1>(Action<T1> action)
    where T1 : MyGenericClass<T>
{
    action((T1)this);
    return this.Create();
}

Then the call will work:

private static string CreateWithCast(Action<MyConcreteClass> action)
{
    return new MyConcreteClass().WorkWithAndCreate(action);
}

Now you no longer need to drop it.

And as for your builder, will there be a next job?

private static TResult AnInstance<TBuilder, TResult>(Action<TBuilder> buildingAction)
    where TBuilder : Builder<TResult>, new()
{
    return new TBuilder().BuildFrom(buildingAction);
}
+3
source

:

http://msdn.microsoft.com/en-us/library/dd264736.aspx

:

, - ,

, , . , .

, ? , , - , .

, interface . , , . dynamic , .

, , generic type, . . Pieter , .

+1

Source: https://habr.com/ru/post/1772065/


All Articles