dotnet / dotnet-api-docs

.NET API reference documentation (.NET 5+, .NET Core, .NET Framework)
https://docs.microsoft.com/dotnet/api/
Other
688 stars 1.53k forks source link

Activator.CreateInstance remarks outdated #9172

Open cremor opened 1 year ago

cremor commented 1 year ago

The remarks section of Activator.CreateInstance<T>() currently states this:

In general, there is no use for the CreateInstance<T>() generic method in application code, because the type must be known at compile time. If the type is known at compile time, normal instantiation syntax can be used (new operator in C#, New in Visual Basic, gcnew in C++).

This is not correct any more. Consider the following example:

public class MyType
{
    public required string Name { get; set; }
}

public static class MyFactory
{
    public static T CreateWithNewConstraint<T>() where T : new()
    {
        return new T();
    }

    public static T CreateWithActivator<T>()
    {
        return Activator.CreateInstance<T>();
    }
}

public static class MySample
{
    public static void Sample()
    {
        // This shows compiler error CS9040
        var o1 = MyFactory.CreateWithNewConstraint<MyType>();

        // This works fine
        var o2 = MyFactory.CreateWithActivator<MyType>();
    }
}

Compiler error CS9040 is currently not documented. It has the following message: "'MyType' cannot satisfy the 'new()' constraint on parameter 'T' in the generic type or or method 'MyFactory.CreateWithNewConstraint()' because 'MyType' has required members."

dotnet-issue-labeler[bot] commented 1 year ago

I couldn't figure out the best area label to add to this issue. If you have write-permissions please help me learn by adding exactly one area label.

tarekgh commented 1 year ago

adding the doc link: https://learn.microsoft.com/en-us/dotnet/api/system.activator.createinstance?view=net-7.0#system-activator-createinstance-1

MichaelDeutschCoding commented 11 months ago

As far as I understand it, the required keyword just makes it that the compiler considers there is no parameterless constructor for that type. It feels more like a bug that you're able to create a new object using Activator.CreateInstance, as I would expect it to throw the same MissingMethodException that would happen if the class actually had no parameterless constructor -- hich would compile fine, but then fail at runtime. The class with required now compiles and executes without problem using CreateInstance().

It feels odd that the compiler and the runtime are not in agreement about whether the required keyword makes it as if there is no public parameterless constructor.

cremor commented 11 months ago

In my opinion the compiler changes on the constructor for the required keyword are more like having a private parameterless constructor. The constructor is still there (it is even public), you just can't call it via normal code (unless you use an old compiler version which doesn't know about required properties yet - then you can call it just fine). But just like Activator.CreateInstance (or reflection in general) allows you to call private methods, it also allows you to call this constructor. So I think this is fine.

Also, imagine it wouldn't allow this. How would you ever be able to create an object of a type that has required properties (and no other custom constructor) via Activator.CreateInstance?