1

[Sorry about the clumsy title - I couldn't figure out the best way to express what I am trying to do.]

I feel a bit silly - I just discovered a bug in the following code of mine:

private static XmlSchemaSet internalSchema = null;
private static XmlSchemaSet externalSchema = null;
private static XmlSchemaSet GetSchema(SchemaType schemaType)
{
    // Lazy evaluation of schema objects - only create internal
    // and external schema once
    XmlSchemaSet schema =
        schemaType == SchemaType.Internal ? internalSchema : externalSchema;
    if (schema == null)
    {
        schema = new XmlSchemaSet();
        schema.Add("", CreateXmlSchemaFile(schemaType));
    }
    return schema;
}

The intent of the code is to allocate the static members internalSchema and externalSchema only once, when they are first requested.

Of course there's an obvious bug with my attempted concise code - the schema local reference is pointing to the object that internalSchema or externalSchema is pointing to (null initially), but as soon as I call new, it only reassigns the local reference, not the static member.

Is there a easy way to achieve what I am trying to do? I guess I could create another method which takes an XmlSchemaSet via the ref keyword, but it seems silly to create another method just for this.

LeopardSkinPillBoxHat
  • 28,915
  • 15
  • 75
  • 111
  • 1
    you can choose which field to set using a ref parameter: `if (condition) Set (ref fieldA); else Set (ref fieldB);` but since C# doesn't support ref locals, you can't assign the reference based on a condition and have a single call site for the method. – phoog May 23 '12 at 04:15
  • 1
    Eric Lippert has written a few times about implementing a prototype C# with the ref local feature; if I recall correctly, he has done it, but there has been no compelling use case identified that would justify adding the feature to the actual product. – phoog May 23 '12 at 04:24
  • @phoog - thanks. My initial thoughts when asking this question was whether there was such thing as a ref local, and my original question was going to ask this more explicitly. – LeopardSkinPillBoxHat May 23 '12 at 04:35
  • Related answers: http://stackoverflow.com/questions/4542536/is-it-possible-to-return-a-reference-to-a-variable-in-c/4543089#4543089, http://stackoverflow.com/questions/3284767/can-i-use-a-reference-inside-a-c-sharp-function-like-c/3285002#3285002 – LeopardSkinPillBoxHat May 23 '12 at 07:07
  • Also see Eric Lippert's blog post here: http://blogs.msdn.com/b/ericlippert/archive/2011/06/23/ref-returns-and-ref-locals.aspx – LeopardSkinPillBoxHat May 23 '12 at 07:12
  • Thanks for finding that link -- I didn't have time to do so when I posted those comments. – phoog May 23 '12 at 17:54

2 Answers2

4

Lazy class is what you are looking for.

Approximate usage:

private static Lazy<XmlSchemaSet> internalSchema = new Lazy<XmlSchemaSet>(
  () => {
   schema = new XmlSchemaSet();
   schema.Add("", CreateXmlSchemaFile(SchemaType.Internal));
   return schema;
  });
Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179
2

No, there is no easy way to assign "reference to a reference type" to a local variable the way you're asking; using a ref parameter to a method is the only direct way to accomplish it.

If you are using .NET 4.0 you can use the Lazy<> class to do the lazy initialization the way you want, which (IMO) can make your code easier to read by removing the one-time initialization code from the common-case access code, e.g.:

private static Lazy<XmlSchemaSet> internalSchema = new Lazy<XmlSchemaSet>(() => CreateSchema(SchemaType.Internal));
private static Lazy<XmlSchemaSet> externalSchema = new Lazy<XmlSchemaSet>(() => CreateSchema(SchemaType.External));

private static XmlSchemaSet CreateSchema(SchemaType schemaType)
{
    var schema = new XmlSchemaSet();
    schema.Add("", CreateXmlSchemaFile(schemaType));
    return schema;
}

private static XmlSchemaSet GetSchema(SchemaType schemaType)
{
    return schemaType == SchemaType.Internal 
      ? internalSchema.Value 
      : externalSchema.Value;
}

Otherwise, I would suggest you not try to be too fancy, and just write your code to do exactly what you want. "Correct" code trumps "concise" code 100% of the time:

if (schemaType == SchemaType.Internal)
{ 
    if (internalSchema == null)
    {
        internalSchema = new XmlSchemaSet();
        internalSchema.Add("", CreateXmlSchemaFile(schemaType));
    }
    return internalSchema;
}
else
{
    if (externalSchema == null)
    {
        externalSchema = new XmlSchemaSet();
        externalSchema.Add("", CreateXmlSchemaFile(schemaType));
    }
    return externalSchema;
}
Michael Edenfield
  • 28,070
  • 4
  • 86
  • 117