Using Lazy for properties - Hack and slash attempt





0/5 (0 vote)
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:
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:
new User()
-->UserType
should be set tonull
.User.PopulateBy(id)
--> Gets info forUser
, including theID
of theUserType
.UserType
should lazy load from theID
if someone requests that property.User.UserTypeId = Id
--> Same as #2, but emphasizing that theUserType
can be changed.User.UserType = UserType
--> Sets theUserType
. Does not need to go to the database.Save(
) --> Gets theUserTypeId
. It should not need to load theUserType
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:
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:
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.)