0

There are places where you can not declare new variables like in a base-constructor call (Exclaimer: this is an example to show-case the problem):

public class SportLicense : BaseEntity<SportLicense>
{
    public SportLicense() : base(
        tableName: new SportLicenseNames().EntityName,
        recordIdFieldName: new SportLicenseNames().RecordIdFieldName)
        { } 
}

It would be nice to declare the instance of SportLicenseNames inline to avoid creating multiple instance. Sometimes it's just about optimizing performance, but often I do need the same instance a second and third time for another parameter of the base-constructor.

There are several similar scenarios where declaring a variable within an expression would be nice to avoid creating a method body (Exclaimer: this is an example to show-case the problem):

public static TEntity ThrowIfNull<TEntity, TId>(this TEntity entity, TId recordId)
where TEntity : Entity, new()
{
    if (entity != null) return entity;
    var e = new TEntity();
    throw new($"Record not found in table '{e.EntityName}' with id '{recordId}'\r\nSELECT * FROM {e.EntityName} WHERE {e.GetPrimaryKeyColumn().Name} = '{recordId}'");
}

If it wasn't for the variable e i could just use an expression-body. Sure I could have created another Instance of TEntity - every time I needed a value of it in the string - but that'd just be wasteful.

Daniel
  • 486
  • 4
  • 19

2 Answers2

0

I solved this issue by creating a generic extension-method Var like this:

public static TObject Var<TObject>(this TObject obj, out TObject varName) => varName = obj;

This allows me to solve the first issue with the base-constructor-call like this:

public class SportLicense : BaseEntity<SportLicense>
{
    public SportLicense() : base(
        tableName: new SportLicenseNames().Var(out var sportLicenseNames).EntityName,
        recordIdFieldName: sportLicenseNames.RecordIdFieldName)
        { } 
}

And the second scenario can be written much shorter without compromising on multiplying the number of instances:

public static TEntity ThrowIfNull<TEntity, TId>(this TEntity entity, TId recordId)
    where TEntity : Entity, new()
    =>
        entity ??
        throw new(
            $"Record not found in table '{new TEntity().Var(out var e).EntityName.Var(out var eName)}' with id '{recordId}'\r\nSELECT * FROM {eName} WHERE {e.GetPrimaryKeyColumn().Name} = '{recordId}'");

With that approach I can often optimize performance (reusing created property-values etc.) without having to write a lot of code with declaring variables first etc.

Daniel
  • 486
  • 4
  • 19
  • Took me a while to figure out what you were trying to achieve but I see what you've done there - cute way to pack it all in to a single expression body - but you have sacrificed readability for questionable gains. I prefer your first version - simple and obvious. As long as there's not much in the constructor creating new objects may not be as expensive as you think. The compiler is going to do it's own optimizations on the code. Your second version with the extension method and stacked variables may even be less performant as well as being way more cryptic. – Etherman May 23 '22 at 08:05
  • Yes, I like shortening and sometimes I take it a bit too far :) This example is a bit extreme. As you say, first example may actually be the better code... I like the var-extension in general as a nice tool, but it has to be considered where to use it an where to go with an extra line of code to maintain readability. Thank for your thoughts! The constructor-sample show-cases better, what to use the extension-method for... – Daniel May 24 '22 at 11:28
0

How about this:

public class SportLicense : BaseEntity<SportLicense>
{
    public SportLicense() : this(new SportLicenseNames()) { }

    private SportLicense(SportLicenseNames licenseNames) : base(
        tableName: licenseNames.EntityName,
        recordIdFieldName: licenseNames.RecordIdFieldName)
    { }
}

Only one instance of SportLicenseNames is created and no need for extension methods, out variables etc.

Johnathan Barclay
  • 18,599
  • 1
  • 22
  • 35
  • Thanks for participating! Yes this works for that case, but my constructor-code is only an artificial example, it could be any value created within the constructor-call. I'd like to have a more general solution to this. – Daniel Apr 27 '22 at 09:45
  • Then just add additional parameters to the private constructor? – Johnathan Barclay Apr 27 '22 at 09:46
  • Sure, this certainly fixes some cases, but is quite bit more code than just declaring a variable quickly. – Daniel Apr 27 '22 at 09:47