1

I'd like to do:

var myClassInstance = myFactory.CreateMyClass() { MyPropertyA = "blah", MyPropertyB = "Bleh"};

but the compiler doesn't like that.

Is there away around this? I'm trying to avoid:

var myClassInstance = myFactory.CreateMyClass();
myClassInstance.MyPropertyA = "blah";
myClassInstance.MyPropertyB = "Bleh";

I know I said myFactory, but it isn't mine. I can't change CreateMyClass

Servy
  • 202,030
  • 26
  • 332
  • 449
toddmo
  • 20,682
  • 14
  • 97
  • 107
  • 1
    Well, that's not really an initializer, because the object has already been initialized when it is returned. – Sentry Feb 04 '17 at 23:24
  • No, has been proposed [there](https://github.com/dotnet/roslyn/issues/133) but actually you can't. – Alessandro D'Andria Feb 04 '17 at 23:24
  • @Sentry, ok but you see what I want to do so how should I change my title? – toddmo Feb 04 '17 at 23:24
  • I think the title is fine. Alessandro could link to the proposal, but chances are most people searching for this functionality would call it "initializer" – Sentry Feb 04 '17 at 23:26
  • Why are you trying to avoid that? – CodingYoshi Feb 04 '17 at 23:33
  • @CodingYoshi, `myClassInstance`,`myClassInstance`,`myClassInstance` gets monotonous. Reading the code is like listening to someone who can't quite seem to get to the point. There's an old song by the Talking Heads that goes "I said it once. Why say it again?". It doesn't bother 99% of developers, but it bothers me. lol – toddmo Feb 04 '17 at 23:40
  • Honestly I don't agree with you. It is very common to have such code and if you go through all the trouble of creating extension methods just to achieve that, it is not worth it. If you do that everywhere, you will just end up with tonnes of extension methods. Not worth it... But that's me. – CodingYoshi Feb 05 '17 at 01:02
  • @CodingYoshi, see my edit. I'm not sure how you get a ton of extension methods. I see one (1). Did you think it was going to be one method per type / property combination? And do you like the way the usage looks now? – toddmo Feb 05 '17 at 19:28
  • If you like it then be it. I still don't like it because everything is object and now the extension method will show up for everything. The intellisense is polluted. However, you like it so go for it. But you should not edit your question like that because now the answer makes no sense so people may down vote the accepted answer. Please roll back. – CodingYoshi Feb 06 '17 at 00:55
  • If you want to post an answer to your question, post it as an answer, not as an edit to the question. – Servy Feb 23 '17 at 21:36
  • Again, you should not be editing your answer into your question. Your question is where you post your question, not the answer you have for it. – Servy Feb 23 '17 at 21:48

3 Answers3

1

While it isn't possible to do exactly what you are asking, you can use the Builder design pattern to increase readability.

Something along these lines:

var myClassInstance = myFactory.CreateMyClass()
                               .WithMyPropertyA("blah")
                               .WithMyPropertyB("Bleh");

This can be done with either extension methods or wrapping myFactory in a builder class of your own.

Community
  • 1
  • 1
David Culp
  • 5,354
  • 3
  • 24
  • 32
  • I feel an extension method coming on lol. Thanks! We know how to party on a Saturday night. – toddmo Feb 05 '17 at 00:21
0

What i would do (depending on how often this is called and how important the performance is):

public class Factory
{
   MyObject CreateMyObject(object source)
   {
    var target = new MyObject();
    CopyPropertiesFromSource(target, source):
    return target;
   }

static void CopyPropertiesFromSource(MyObject target, object source)
{
    var propertiesToInitialize = typeof(MyObject).GetProperties();
    var sourceProperties = source.GetType().GetProperties();
    foreach(var property in propertiesToInitialize)
    {
      var correspondingProperty = sourceProperties.FirstOrDefault(x => x.Name == property.Name && x.PropertyType == property.PropertyType);

    if(correspondingProperty == null)
       continue;

      property.SetValue(target, correspondingProperty.GetValue(source));
    }
  }
}

var myClassInstance = new Factory().CreateMyObject({ MyPropertyA = "blah" });

zaitsman
  • 8,984
  • 6
  • 47
  • 79
-2

Based on David Culp's answer, I made this extension function:

  public static object With(this object obj, object additionalProperties)
  {
    var type = additionalProperties.GetType();
    foreach (var sourceField in type.GetFields())
    {
      var name = sourceField.Name;
      var value = sourceField.GetValue(additionalProperties);
      if (type.GetMember(name)[0] is FieldInfo)
        type.GetField(name).SetValue(obj, value);
      else
        type.GetProperty(name).SetValue(obj, value);
    }
    return obj;
  }

and it's used like this:

var myClassInstance = myFactory.CreateMyClass().With(new { MyPropertyA = "blah", MyPropertyB = "bleh"});

It really shines when there's a lot of properties.

    // insert a new version
    T newVersion = (T)MemberwiseClone();
    newVersion.IsSuspended = true;
    newVersion.RealEffectiveDate = RealExpirationDate;
    newVersion.RealExpirationDate = NullDate;
    newVersion.Version++;
    newVersion.BusinessEffectiveDate = BusinessExpirationDate;
    newVersion.BusinessExpirationDate = NullDate;

becomes:

    // insert a new version
    T newVersion = (T)MemberwiseClone().With(new
    {
      IsSuspended = true,
      RealEffectiveDate = RealExpirationDate,
      RealExpirationDate = NullDate,
      Version = Version + 1,
      BusinessEffectiveDate = BusinessExpirationDate,
      BusinessExpirationDate = NullDate

    });
toddmo
  • 20,682
  • 14
  • 97
  • 107
  • 1
    Argh - it might look nice on the editor, but is it _really_ worth the reflection? Maybe your original version was the most performant (and easier to maintain) code... – code4life Feb 23 '17 at 21:41
  • This is going to be multiple orders of magnitude slower, and it loses all static typing, creating lots of possibilities for both obvious and subtle errors, as well as just generally inhibiting code maintenance in enumerable ways going forward. And you don't even get any advantages. The code isn't shorter or easier to write than the code you're trying to replace. In fact, it's *much harder* to write out than the code you're trying to replace. – Servy Feb 23 '17 at 21:45
  • @Servy, could an extension method take a lambda to keep the type checking? – toddmo Feb 23 '17 at 22:04
  • @toddmo Sure. You're not actually getting anything over your original code though, although you'd end up losing a lot less. You still won't have gained anything from where you were when you started. – Servy Feb 23 '17 at 22:06