Click here to Skip to main content
15,881,516 members
Articles / Programming Languages / C# 4.0

Using Lazy for properties - Hack and slash attempt

Rate me:
Please Sign up or sign in to vote.
0.00/5 (No votes)
19 Aug 2011CPOL1 min read 9.5K   2   2
Getting Lazy to work for me.

Introduction

OK, I love the idea of the Lazy<T> class, but it never seems to do what I want it to. Assuming you don't think I'm wanting too much. If you have a simpler way, please let me know!

Background

I'm using the lazy loading for properties of a data or business entity. Example non-lazy classes:

C#
class User { int id; UserType userType; }  
class UserType { int id; string Name; }

This is what I would want my lazy loading to handle for the above example:

  1. new User() --> UserType should be set to null.
  2. User.PopulateBy(id) --> Gets info for User, including the ID of the UserType. UserType should lazy load from the ID if someone requests that property.
  3. User.UserTypeId = Id --> Same as #2, but emphasizing that the UserType can be changed.
  4. User.UserType = UserType --> Sets the UserType. Does not need to go to the database.
  5. Save() --> Gets the UserTypeId. It should not need to load the UserType from the database.

So Lazy<T> isn't specific enough to do what I want. I tried to implement it, but it got messy. Take a peek.

Code

Here's what my User class looks like:

C#
public class User {
    public int Id { get; set; }
    public string Name { get; set; }

    //assuming: passing the UserType constructor
    //an Id causes it to populate itself.
    private LazyProperty<UserType> _userType = 
      new LazyProperty<UserType>((id) => new UserType(id), (u) => u.Id);
    public int? UserTypeId {
        get { return _userType.Id; }
        set { _userType.Set(value); }
    }
    public UserType UserType {
        get { return _userType.Value; }
        set { _userType.Set(value); }
    }
}

To make the above work, below is the code that I came up with:

C#
using System;
using System.Threading;

public class LazyProperty<T> where T : class {
    public delegate T CreateProperty<T>(int id);
    public delegate int GetId(T item);

    #region members
    int? _id = null;
    bool? _isThreadSafe;
    T _value;
    Lazy<T> _Lazy;
    GetId _GetId;
    CreateProperty<T> _createEntity;
    LazyThreadSafetyMode? _mode;
    #endregion

    #region Properties
    public int? Id { 
        get { return _id; }
    }
    public T Value { 
        get {
            if (_Lazy == null)
                return _value;
            else
                return _Lazy.Value;
        } 
    }
    public bool IsValueCreated {
        get {
            if (_Lazy == null)
                return true;
            else
                return _Lazy.IsValueCreated;
        }
    }
    #endregion
    
    private T doCreate(){
        return _createEntity(Id.Value);
    }

    public LazyProperty(CreateProperty<T> creator, GetId getId) : 
           this(creator, getId, null, null) { }
    public LazyProperty(CreateProperty<T> creator, GetId getId, 
           bool isThreadSafe) : this(creator, getId, isThreadSafe, null) { }
    public LazyProperty(CreateProperty<T> creator, GetId getId, 
           LazyThreadSafetyMode mode) : this(creator, getId, null, mode) { }
    private LazyProperty(CreateProperty<T> creator, GetId getId, 
            bool? isThreadSafe, LazyThreadSafetyMode? mode) {
        _createEntity = creator;
        _isThreadSafe = isThreadSafe;
        _mode = mode;
        _GetId = getId;
        doSet(null, null);
    }
    public void Set(int? id) {
        doSet(id, null);
    }
    public void Set(T value) {
        int? id = null;
        if (value != null)
            id = _GetId(value);
        doSet(id, id == null ? null : value);
    }
    private void doSet(int? id, T value) {
        _id = id;
        _value = value;
        if (id == null || value != null)
            _Lazy = null;
        else if (_mode.HasValue)
            _Lazy = new Lazy<T>(doCreate, _mode.Value);
        else if (_isThreadSafe.HasValue)
            _Lazy = new Lazy<T>(doCreate, _isThreadSafe.Value);
        else
            _Lazy = new Lazy<T>(doCreate);
    }
}

Conclusion

Again, this seems like I needed to do a lot of work to make things work for me. How would you do it better?

History

(Made code slightly cleaner... it's too late on a Friday for this.)

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
United States United States
likes boardgames, computer games, and enjoys his .net programming job.

Comments and Discussions

 
SuggestionNeeds some work Pin
DaveAuld19-Aug-11 22:24
professionalDaveAuld19-Aug-11 22:24 
GeneralRe: Needs some work Pin
ColinBashBash23-Aug-11 11:04
ColinBashBash23-Aug-11 11:04 
Thanks. I'll try to fix this up soon. I was really hoping somebody would take one look at it and tell me why everything was worthless and how I could have done it some other way. I suppose I still need more explanation before I get that kind of feedback. Smile | :)

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.