Coder Social home page Coder Social logo

emptyconstructor's Introduction

EmptyConstructor.Fody

Chat on Gitter NuGet Status

Adds an empty constructor to classes even if you have a non-empty one defined.

See Milestones for release notes.

This is an add-in for Fody

It is expected that all developers using Fody become a Patron on OpenCollective. See Licensing/Patron FAQ for more information.

Usage

See also Fody usage.

NuGet installation

Install the EmptyConstructor.Fody NuGet package and update the Fody NuGet package:

PM> Install-Package Fody
PM> Install-Package EmptyConstructor.Fody

The Install-Package Fody is required since NuGet always defaults to the oldest, and most buggy, version of any dependency.

Add to FodyWeavers.xml

Add <EmptyConstructor/> to FodyWeavers.xml

<Weavers>
  <EmptyConstructor/>
</Weavers>

Configuration Options

Exclude types with an Attribute

If for some reason you want to skip a specific class you can mark it with a DoNotVirtualizeAttribute.

Since no reference assembly is shipped with Virtuosity. Just add the below class to your assembly. Namespace does not matter.

public class DoNotVirtualizeAttribute : Attribute
{
}

So your class will look like this

[DoNotVirtualize]
public class ClassToSkip
{
    ...
}

Include or exclude namespaces

These config options are access by modifying the EmptyConstructor node in FodyWeavers.xml

Visibility

The visibility to use when injecting constructors.

Can not be defined with Visibility.

Allowed values: public or family (aka protected)

Defaults to public.

For example

<EmptyConstructor Visibility='family'/>

Making Existing Empty Constructors Visible

Optionally the visibility of already existing constructors can be increased. If this feature is enabled, the visibility of empty-constructors of non-abstract types will be increased to the same visibility as defined by the Visibility configuration (see above).

For example

<EmptyConstructor MakeExistingEmptyConstructorsVisible='True'/>

Will ensure all constructors on non-abstract types will be public.

ExcludeNamespaces

A list of namespaces to exclude.

Can not be defined with IncludeNamespaces.

Can take two forms.

As an element with items delimited by a newline.

<EmptyConstructor>
    <ExcludeNamespaces>
        Foo
        Bar
    </ExcludeNamespaces>
</EmptyConstructor>

Or as a attribute with items delimited by a pipe |.

<EmptyConstructor ExcludeNamespaces='Foo|Bar'/>

IncludeNamespaces

A list of namespaces to include.

Can not be defined with ExcludeNamespaces.

Can take two forms.

As an element with items delimited by a newline.

<EmptyConstructor>
    <IncludeNamespaces>
        Foo
        Bar
    </IncludeNamespaces>
</EmptyConstructor>

Or as a attribute with items delimited by a pipe |.

<EmptyConstructor IncludeNamespaces='Foo|Bar'/>

Initializers Preservation

By default, the generated constructors remain empty. If you would like field & property initialization to be copied from an existing constructor enable this via the PreserveInitializers attribute.

<EmptyConstructor PreserveInitializers='true'/>

Example, without initializers preservation:

public class Foo
{
    private int someValue;
    private int otherValue;
        
    public Foo(int someValue)
    {
        this.someValue = someValue;
        otherValue = 17;
    }
        
    // generated constructor
    public Foo() { }
}

Example, with initializers preservation:

public class Foo
{
    private int someValue;
    private int otherValue;
        
    public Foo(int someValue)
    {
        this.someValue = someValue;
        otherValue = 17;
    }
        
    // generated constructor
    public Foo()
    {
        // note: this.someValue isn't set
        otherValue = 17;
    }
}

Icon

Icon courtesy of The Noun Project

emptyconstructor's People

Contributors

brunojuchli avatar dependabot-preview[bot] avatar dependabot-support avatar dependabot[bot] avatar kurnakovv avatar ltrzesniewski avatar marcoerni avatar norekz avatar simoncropp avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

emptyconstructor's Issues

Assembly version is 0.0.0.0

The published weaver assembly version is 0.0.0.0, which causes Fody to pick the wrong EmptyConstructor version when multiple versions are available in the packages directory.

  • The Directory.Build.props file contains <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
  • There's also a CommonAssemblyInfo.cs file which is not used by any project (and contains an old version number anyway)

I just noticed the outdated/unused CommonAssemblyInfo.cs issue is also present in some other addins of yours @SimonCropp, so you way want to take a look at that.

After update to version 3.0.0, compile throws System.NullReferenceException

Description

After update versions on project:

  • From 1.1.7 to 3.0.0 - EmptyConstructor.Fody
  • From 1.29.2 to 6.1.0 - Fody
  • From 1.19.12 to 3.0.0 - Virtuosity.Fody

With "FodyWeavers.xml" with this configuration:

<?xml version="1.0" encoding="utf-8"?>
<Weavers>
  <EmptyConstructor />
  <Virtuosity />
</Weavers>

The compilers throws en error "System.NullReferenceException":

Error		Fody: An unhandled exception occurred:
Exception:
  Failed to execute weaver C:\Workspace\eVinfoPOL\sources\packages\EmptyConstructor.Fody.3.0.0\build\..\weaver\EmptyConstructor.Fody.dll
Type:
  System.Exception
  StackTrace:
     en InnerWeaver.ExecuteWeavers() en C:\projects\fody\FodyIsolated\InnerWeaver.cs:línea 206
     en InnerWeaver.Execute() en C:\projects\fody\FodyIsolated\InnerWeaver.cs:línea 111
Source:
  FodyIsolated
TargetSite:
  Void ExecuteWeavers()
  Referencia a objeto no establecida como instancia de un objeto.
Type:
  System.NullReferenceException
  StackTrace:
   en ModuleWeaver.Execute()
   en InnerWeaver.ExecuteWeavers() en C:\projects\fody\FodyIsolated\InnerWeaver.cs:línea 178
Source:
  EmptyConstructor.Fody

Is there any way to get info about the source of NullReferenceException?

I guess Fody is missing something on project configuration, but I can't find what it is.

Thanks in advance.
Regards

New Feature "Field Initialization" in 2.1.1 Results in System.InvalidProgramException

2.1.1 introduced a new feature "Field Initialization", see PR 133.

Unfortunately sometimes the generated IL is incorrect, which results in a System.InvalidProgramException.

Minimal Repro

The easy way: see PR #144

The issue can be reproduced using the following code:

class Program
{
    static void Main(string[] args)
    {
        // this will throw a
        // System.InvalidProgramException : Common Language Runtime detected an invalid program.
        Activator.CreateInstance<Child>();

        Console.WriteLine("program ended");
    }
}

public class Child : Base<int>
{
    private bool value;

    private Child(int enumValue)
        : base(enumValue)
    {
        this.value = true;
    }
}

public abstract class Base<TValue>
{
    protected Base(TValue value)
    {
    }
}

Note, that this is a minimal repro:

  • removing the <TValue> generic parmeter from Base will make the problem go away
  • removing the TValue value argument from Base ctor will make the problem go away
  • removing the int enumValue argument from Child ctor will make the problem go away
  • removing the this.value = true from the Child ctor will make the problem go away
    -- note, though, that the assignment can be replaced with a call to a local method like this.Foo()

Workaround

This can be worked around by opting out of field initialization via FodyWeavers.xml:

<EmptyConstructor DoNotPreserveInitializers="true" />

Discussion of Issue Resolution

May I ask @NorekZ what your use case for Field Initialization / EmptyConstructor.Fody is?

Our use case is:
We use EmptyConstructor.Fody and Virtuosity.Fody in order for our types to become mockable (i.E. inherited from and methods overridable) without us needing to create an interface for every type.
We're only interested in the type, not the behavior, thus EmptyConstructor.Fody adding any logic to the constructor is just superfluous. And in some cases, as seen above, actually produces invalid IL.

I'm asking you on how you're using it in order to better understand the user base of EmptyConstructor.Fody, this again in order to provide information for a decision:

Should this feature be changed to opt-in instead of opt-out?

If most users will need the behavior, it obviously makes sense to be opt out.
If most users don't need it, but it doesn't interfere with their usage, it may be opt out.
If most users don't need it and lots of them need to turn it off, then it should be opt out.

As I understand, this is a a new feature, so it's easy to conclude that users of EmptyConstructor.Fody 2.1.0 and before didn't need the behavior. So the question is: how will the user base grow with this feature?

Here's another take:

  • the new feature (currently) breaks some of the old usages (as experienced by us)
  • in some cases, the new feature produces invalid IL. Should it be opt-in until it's stable enough to not produce invalid IL? Or do we live with it (edge case?)? Or do we try to fix it ASAP?

Optional parameter issue

Hi, here is a demo project that can reproduce the issue:
https://dl.dropboxusercontent.com/u/46508238/github.com/TestEmptyConstructor-2013-08-02.zip

Steps to reproduce the issue:

  1. Create a test project and a class library;
  2. In the test project, add:
    [Test]
    public void Pass()
    {
        var entity = new Entity(1);
        Assert.NotNull(entity.Locker);
    }

    [Test]
    public void Fail()
    {
        var entity = new Entity();
        Assert.NotNull(entity.Locker);
    }
  1. In the class library, add:
public class Entity
{
    public object Locker;

    public Entity(int id = 0)
    {
        Locker = new object();
    }
}
  1. Run the tests, the first test will pass, second one will fail;

I checked the IL, and found it was compiled to:

    [Test]
    public void Fail()
    {
        Assert.NotNull((new Entity()).Locker);
    }

    [Test]
    public void Pass()
    {
        Assert.NotNull((new Entity(1)).Locker);
    }

When I moved Entity to the test project, both tests past. And the IL was:

    [Test]
    public void Fail()
    {
        Assert.NotNull((new Entity(0)).Locker);
    }

    [Test]
    public void Pass()
    {
        Assert.NotNull((new Entity(1)).Locker);
    }

Generated constructor should behave the same way as hand-written

if I have fields with initializers they will not be called with generated constructor.

class X
{
    private int y = 42; // this will be called before base constructor.

    public X(int z) 
    {
    }
}

The generated code will be like following

class X
{
    private int;

    public X(int z) 
    {
       this.y = 42;
       base..ctor();
    }

    public X() : base () 
    {
        //y should be initialized here as well.
    }  
}

Field & property initializers are not preserved in generated constructor

I have the same issue as #3 - property initalizers are not executed while using generated constructor.

When I add test

    [Fact]
    public void ClassWithInitializedFields()
    {
        var instance = testResult.GetInstance("ClassWithInitializedFields");
        Assert.Equal(9, instance.X);
        Assert.Equal("aString", instance.Y);
        Assert.NotNull(instance.Z);
    }

to IntegrationTests.cs, it fails.

Logging Severity

Is it possible to decrease the logging severity for the log message which stating that a empty constructor was created from severity info to debug? Currently the EmptyConstructor weaver is extremely chatty and fills up our build log.

Support for .NET 5

Could this be updated to work with .NET 5?

When I attempt to install from nuget it is asking for a ton of dependencies within a .NET 5 project.

Class Sequence breaks adding Empty Constructor to Class inheriting from Generic Class

Description

Sometimes a class mistakenly does not get an empty constructor.
This is the case if all of the following criteria are met:

  • child class inherits from a generic base class
  • base class does not have a parameter-less constructor
  • child class is processed before base class

Minimal Repro

public class Foo : GenericBase<string> { }

public class GenericBase<T>
{
    public GenericBase(T argument) { }
}

Details

The issue is with ModuleWeaver:

MethodReference baseEmptyConstructor;
if (baseType is TypeDefinition baseTypeDefinition)
{
    if (!processed.TryGetValue(baseTypeDefinition, out baseEmptyConstructor))
    {
        queue.Enqueue(type);
        continue;
    }
}
else
{
    if (!external.TryGetValue(baseType, out baseEmptyConstructor))
    {
        var emptyConstructor = baseType.Resolve().GetEmptyConstructor();
        if (emptyConstructor != null)
        {
            baseEmptyConstructor = ModuleDefinition.ImportReference(emptyConstructor);
        }
        external.Add(baseType, baseEmptyConstructor);
    }
}

The baseType of the child class is not a TypeDefinition, it's a GenericInstanceType. Hence re-queueing the child-class for later weaving is skipped.

Submit a PR that fixes the bug

I'm on it ;-)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.