Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to use a c# object initializer with a factory method?

I have a class with a static factory method on it. I want to call the factory to retrieve an instance of the class, and then do additional initialization, preferablly via c# object initializer syntax :

MyClass instance = MyClass.FactoryCreate()
{
  someProperty = someValue;
}

vs

MyClass instance = MyClass.FactoryCreate();
instance.someProperty = someValue;
like image 340
Jason Coyne Avatar asked Mar 23 '09 22:03

Jason Coyne


People also ask

Is it OK to use AC everyday?

There is no harm in doing so and it is designed to keep your room cool for the entire day. An air conditioner is a device that is designed to maintain a set room temperature all day long. There is no such thing as the appliance will melt, or get damaged if run continuously for 24 hours.

Is it harmful to use AC?

Affects Indoor Air If you work in an air-conditioned building with poor ventilation, it can raise your risk of “sick building syndrome.” Symptoms include headaches, dry cough, dizziness and nausea, trouble concentrating, fatigue, and sensitivity to odors.

Can AC be used for heating?

The reality is that many air conditioning units can also be used to heat rooms. There are air conditioning systems on the market which can keep rooms warm in the winter, and cooler in the summer.

Can we use AC in winter?

When running an air conditioner in the winter, the unit reverses its function and fills your space up with warm air instead of cold—saving you the cost of getting a separate heating system. So yes, air conditioners do indeed work in winter.


3 Answers

No. Alternatively you could accept a lambda as an argument, which also gives you full control in which part of the "creation" process will be called. This way you can call it like:

MyClass instance = MyClass.FactoryCreate(c=>
   {
       c.SomeProperty = something;
       c.AnotherProperty = somethingElse;
   });

The create would look similar to:

public static MyClass FactoryCreate(Action<MyClass> initalizer)
{
    MyClass myClass = new MyClass();
    //do stuff
    initializer( myClass );
    //do more stuff
    return myClass;
}

Another option is to return a builder instead (with an implicit cast operator to MyClass). Which you would call like:

MyClass instance = MyClass.FactoryCreate()
   .WithSomeProperty(something)
   .WithAnotherProperty(somethingElse);

Check this for the builder

Both of these versions are checked at compile time and have full intellisense support.


A third option that requires a default constructor:

//used like:
var data = MyClass.FactoryCreate(() => new Data
{
    Desc = "something",
    Id = 1
});
//Implemented as:
public static MyClass FactoryCreate(Expression<Func<MyClass>> initializer)
{
    var myclass = new MyClass();
    ApplyInitializer(myclass, (MemberInitExpression)initializer.Body);
    return myclass ;
}
//using this:
static void ApplyInitializer(object instance, MemberInitExpression initalizer)
{
    foreach (var bind in initalizer.Bindings.Cast<MemberAssignment>())
    {
        var prop = (PropertyInfo)bind.Member;
        var value = ((ConstantExpression)bind.Expression).Value;
        prop.SetValue(instance, value, null);
    }
}

Its a middle between checked at compile time and not checked. It does need some work, as it is forcing constant expression on the assignments. I think that anything else are variations of the approaches already in the answers. Remember that you can also use the normal assignments, consider if you really need any of this.

like image 127
eglasius Avatar answered Oct 06 '22 23:10

eglasius


You can use an extension method such as the following:

namespace Utility.Extensions
{
    public static class Generic
    {
        /// <summary>
        /// Initialize instance.
        /// </summary>
        public static T Initialize<T>(this T instance, Action<T> initializer)
        {
            initializer(instance);
            return instance;
        }
    }
}

You would call it as follows:

using Utility.Extensions;
// ...
var result = MyClass.FactoryCreate()
                .Initialize(x =>
                {
                    x.someProperty = someValue;
                    x.someProperty2 = someValue2;
                });
like image 42
Hans Vonn Avatar answered Oct 06 '22 23:10

Hans Vonn


Yes. You can use object initializer for already created instance with the following trick. You should create a simple object wrapper:

public struct ObjectIniter<TObject>
{
    public ObjectIniter(TObject obj)
    {
        Obj = obj;
    }

    public TObject Obj { get; }
}

And now you can use it like this to initialize your objects:

new ObjectIniter<MyClass>(existingInstance)
{
    Obj =
    {
        //Object initializer of MyClass:
        Property1 = value1,
        Property2 = value2,
        //...
    }
};

P.S. Related discussion in dotnet repository: https://github.com/dotnet/csharplang/issues/803

like image 3
Roman Artiukhin Avatar answered Oct 07 '22 00:10

Roman Artiukhin