It sounds like you're saying you want to have some generic object that
you hold onto in your class but you don't want to know what the type
of that object is. However, you want to be able to write code that
uses that object. There's not any sensible way that the compiler
could type-check your code without knowing what T is, which is why you
either need to specify a value of T in your field (i.e. bind the
parameter to a type), or you need to make T a generic parameter of
your type (i.e. leave it as an 'open' generic and 'provide' the T from
the use site of your class).
The thing I'm not really getting is why the control author cares what
T is. It seems to me that if you're doing VM / PM pattern well, you
should be striving to have very little (if any) code in your controls,
and all of the interaction should be through bindings to the VM (which
are - by definition - untyped, though if you use something like the
binding frameworks that Glenn has been trying to build, you'll see
that you can use stronger typing in your bindings).
What you can do, and I've done this in the past, is not make the
repository generic, but rather make its methods generic (i.e.
Query<T>(...) instead of IRepository<T>::Query(...)) but this won't
allow you to resolve different repositories by type from the IoC
container.
The other thing I'd ask yourself is whether inheritance is the right
solution to your problem. In nearly every case in my past that I
thought it was, I turned out to be wrong. You might also think about
whether the type of the repository is important to be in a base class,
or whether you can get the same effect by having the base class be
abstract, providing a few methods to 'hook' into the derived class
implementations, and then you can have the type parameter on the base
class and have the deriving class provide the "T" when it derives. In
other words, you could make:
public class FooContainerControl: ContainerControlBase<Foo> { ... }
We do this a lot in our UI code (though we do it with the PMs, not the
controls, I personally hate base classes for controls - it never works
out well, we use interfaces exclusively for them). For instance, we
have a:
public class EditorGridPresentationModelBase<T> where T: IItemCore, class
{ ... }
and then for Table and Variable (both IItemCore implementers), we have
public class EditorGridPresentationModel: EditorGridPresentationModelBase<Table>
{ ... }
(in the Tables namespace), and
public class EditorGridPresentationModel:
EditorGridPresentationModelBase<Variable>
{ ... }
(in the Input namespace).
Kelly
> --
> You received this message because you are subscribed to the Google Groups
> "Seattle area Alt.Net" group.
> To post to this group, send email to altnet...@googlegroups.com.
> To unsubscribe from this group, send email to
> altnetseattl...@googlegroups.com.
> For more options, visit this group at
> http://groups.google.com/group/altnetseattle?hl=en.
>
* Don't use a generic repository. e.g interface InvoiceRepository
- The interface will also help express intent of your code better
where ever the interface is used
- The implementation of InvoiceRepository could be backed by
a generic repository to achieve technical quality factors like
removing duplication, better reuse etc...
If you would like to use a generic repository and are already on c#
4.0 I believe you could use contravariance like this,
//Marker Interface
public interface AggregateRoot
public OrderBook : AggregateRoot
public interface IRepository<T>
public interface IOrderBookRepository :
IRepository<OrderBook>
public class ControlBase {
protected IRepository<AggregateRoot> _repository;
}
public class CoolControl : ControlBase {
public CoolControl() {
_repository = IoC.Resolve<IOrderBookRepository>();
}
public LoadData () {
// do some typed IQueryable stuff on repository
}
}
HTH
Cheers,
Aeden
On Wed, Mar 3, 2010 at 4:10 PM, Erick Thompson <erick.t...@gmail.com> wrote:
> --
> You received this message because you are subscribed to the Google Groups
> "Seattle area Alt.Net" group.
> To post to this group, send email to altnet...@googlegroups.com.
> To unsubscribe from this group, send email to
> altnetseattl...@googlegroups.com.
> For more options, visit this group at
> http://groups.google.com/group/altnetseattle?hl=en.
>
--
Cheers,
Aeden
Software Musings @
http://aedenjameson.blogspot.com/
Also, no cool control I know would take a dependency on an IOC container. :)
On Wed, Mar 3, 2010 at 4:10 PM, Erick Thompson <erick.t...@gmail.com> wrote:
Glenn's project that I was referring to is a side project, AFAIK, that
he was working on for binding using a fluent interface in code, rather
than specifying your bindings in XAML. AFAIK, it's still in the
"exploratory" stages, but I'm sure he'd love to talk about it with you
if he has time.
I think the control shouldn't have any of this stuff in it, though.
It seems to me that the control code should be empty if at all
possible. All of the "view" logic should be in the VM. I don't take
as strong a view of the VM/M separation as some people do. In my
opinion it's ok to have a lot of code in the VM, so long as that
aligns with your testing needs and goals. Our issue right now is that
it doesn't ;)
Kelly
On Wed, Mar 3, 2010 at 10:31 PM, Erick Thompson
public class VMBase<DataType, RepositoryType>: INotifyPropertyChanged
where DataType: DataObjectBase,
RepositoryType: IRepository<DataType>
{
private readonly RepositoryType _Repository;
public VMBase(RepositoryType repository)
{
_Repository = repository;
}
// some accessors for commonly used repository operations...
protected IQueryable<DataType> GetAllObjects()
{
return _Repository.GetAll();
}
// allow access to 'private' repository, without the caller having
direct access to the field...
protected void AccessRepository(Action<RepositoryType> repositoryAction)
{
repositoryAction(_Repository);
}
...
protected void OnPropertyChanged<T>(Expression<Func<T>> propertyAccessor)
{
// crack the property name from the expression and use it to fire
the PropertyChanged event.
}
}
public class BooksRepository: BaseRepository<Book>
{
public IQueryable<Book> GetBooksBySubjectFilter(string subjectFilter)
{
...
}
}
public class BooksVM: VMBase<Book, BooksRepository>
{
public BooksVM(BooksRepository repository)
: base(repository)
{
}
public string SubjectFilter
{
get { return _SubjectFilter; }
set
{
if(_SubjectFilter == value)
return;
_SubjectFilter = value;
_RefreshBooksList();
OnPropertyChanged(() => SubjectFilter);
}
}
private void _RefreshBooksList()
{
IQueryable<Book> booksList;
AccessRepository(r => booksList =
r.GetBooksBySubjectFilter(_SubjectFilter));
// ... do something to put booksList in a UI accessable
collection (ObservableCollection, etc.)
}
}
... yada yada yada...
get the idea?
On Wed, Mar 3, 2010 at 10:56 PM, Erick Thompson
otherwise, I think the skeleton code will compile if you replace the
comments with some 'meat'. Obviously gmail isn't the best C#
compiler, so you may have to do some tweaking to get a working sample.
kelly