How to reference a property in .NET?

M

Marcel Müller

Hi,

when bound columns of a DataGrid refer to properties they mostly end up
with a string DataField that is interpreted by a the DataBinder and
TypeDescriptor class of the framework. This is error prone, since it is
neither type safe nor checked for existence at compile time. Furthermore
the result of "find all references" is incomplete and refactoring
results in inconsistent code.
Before .NET 2.0 I did not expect anything else, since .NET 1.1 have not
been type safe anyway. But with the support of generics this is a break
in the application design.

I would like to come around this restrictions. But to do so I need to
get a reference the the property. This reference is not the same than a
delegate to a non-static member function (like get_Age), since it must
not include the object itself. Instead it should be something like a
reference to a static function like

class Customer
{
public int Age { get; internal set; }
...

// nonsense, only for demonstration:
public static int get_Age(Customer this)
{ return Age; }
}

with the resulting reference type

Func<Customer, int> PropertyRef = Customer.get_Age;

To access the property the reference have to be applied to an object of
type Customer, which should be the line item type of the DataGrid.
Of course, special care have to be taken if Age is virtual and/or
Customer is an interface type.

Unfortunately I did not found a way to get something like the above
reference from the property Customer.Age. Of course, one could use lamda
expressions all over the world.

Func<Customer, int> PropertyRef = cust => cust.Age;

But this does not really make the code readable. Especially if the
result is a generic method parameter:

class X
{ public void SetProperty(Func<O, T> func)
{ ...
}

}

X x;
x.SetProperty((Customer cust) => cust.Age);

Furthermore it creates much redundancy in the assembly code, since the
above anonymous method is implemented over and over while the required
code already exists: Customer.get_Age.


Is there a way around that? I mean to create references to properties
/without/ using reflections (like TypeDescriptor or DataBinder) with all
their drawbacks?


Marcel
 
M

Marcel Müller

Hi,

Peter said:
Perhaps you could clarify what you mean. System.Windows.Forms.DataGrid
is a GUI class, dealing in things that a user can understand, such as
strings.

well, I would like to call it HTML, which can be by far more than string
(although there is a biunique conversion to string).
You can abstract a database with a strongly-typed class by using the
database features in VS to create a database adapter that does that.

First of all I have no database. At least no database, that can hold the
OO data model natively in any way. So the adapter would not be helpful.
Secondly, generated typed datasets are one of the slowest things I have
ever seen. Whereever we used them, they degraded application performance
compared to individual data types significantly. Especially the memory
footprint is horrible. I prefer not to see them in production code where
performance counts in any way. Last but not least they are restricted to
relational data models.
Thirdly, the user wants to operate on results of joins over different
entities. So I would have to write a new data type for each bindable
result in the application. I really do not want to do so.
Last but not least, I do not restrict the column content to anything
similar to strings. Instead depending on the data type complex controls
(sometimes with wizards) will bind to complex non flat data objects like
arrays or even class objects.
What would your proposed generic design for the DataGrid class be?

I have wrapped the Grid with a strongly typed version which has a
bindable DataSource for the X and the Y direction. The X data source is
a list of column descriptors that feed an (overloadable) column factory.
The column descriptors must be references to properties of the element
type of the Y data source.

I don't see how the addition of a new feature to the language should be
considered to _break_ design.

Of course, the addition of the generics breaks nothing. However, when
using template meta programming consequently, almost any actions that
are constant with respect to the resulting binary is moved from run time
to compile time. Small lacks in the language features inhibit this
programming style.
And I think using generics in the context
of a data grid object of any sort would be very unwieldy (a separate
generic type for each possible number of columns and one type parameter
per column? I'd rather not),

Of course, not.

// Any property of an object type O
interface IPropertyRef<O>
{ ... }

interface IColumnFactory
{
GridColumn CreateColumn<O>(IPropertyRef<O> prop);
}

class Grid<O>
{
public IEnumerable<O> DataSource { get; set; } // Y data source

public IEnumerable<IPropertyRef<O>> XDataSource { get; set; }

public IColumnFactory ColumnFactory { get; set; }
}

Currently I have the meta data completely separated from the data
objects. The meta data is stored in a singleton class for each entity.
These classes have fields for each property of the entity. The data
objects itself are stupid. They only have a generic get and set method
that can be invoked with a property descriptor of the matching meta data
class. These methods provide O(1) access to the data. Furthermore the
data objects have a TypeDescriptorProvider to keep the DataGrid happy.

[TypeDescriptionProvider(typeof(AnyObjectTypeDescriptionProvider))]
class AnyObject<E> where E : EntityType
{
// element access
// Unfortunately this is no valid code. Indexers cannot be generic.
// However, this is what actually happens with an explicit
// Get and Set method as work around.
public T this<T>[EntityAttribute<E,T> key]
{ get {...}
set {...}
}
}

// Meta data of an entity
class EntityType
{...}

// Meta data of a property of an entity.
class EntityProperty<E,T> : IPropertyRef<AnyObject<E>>
where E : EntityType
{...}

class CustomerType : EntityType
{
public static EntityProperty<CustomerType, int> Age
= new EntityProperty<CustomerType, int>();
public static EntityProperty<CustomerType, Address[]> Addresses
= new EntityProperty<CustomerType, Address[]>();
...
}

class Address
{
public string Street { get; set; }
...
}

AnyObject<CustomerType> obj = ...
// Element access must be .Get/.Set in real life. See above.
int age = obj[CustomerType.Age];
obj[CustomerType.Age] = 17;

myGrid.XDataSource = new IPropertyRef<AnyObject<CustomerType>>[]
{ CustomerType.Age,
...
}

This concept fulfills all my requirements, since the EntityProperty
instances serve as references to properties.
Unfortunately this is mutually exclusive with the .NET concept to bind
to properties via reflection. So if I need to join these completely
generic entity objects with simple class objects with public properties
(e.g. Address) I do no longer have a type safe way to access the
properties of both entities in one Grid. It only works as long as I join
only over my own entities. This would mean in the above example that I
have to turn Address[] into AnyObject<AddressType>[]. This is an very
inconvenient implication. Currently only strong entities are kept in the
above way.

as well as not really solve the fundamental
problems anyway (binding would still have to be done through converters,
and general-purpose property names would be less useful than passing
string names to a column indexer).

?
What do yo call general-purpose property names?

Do you mean "return this.Age"?

Oops, of course.
How is your proposal different from
using reflection and a PropertyInfo object?

In no way. Except that using reflections has all the disadvantages that
the DataBinder solution shares too.
If you actually want a delegate instance, what's so wrong with using
real delegates?

Real delegates cannot be taken from properties (or I did not find out
the right syntax). And furthermore they do not support to be applied to
a different object than the one which was used to create them. The
latter is a show stopper. The above pseudo code is an ugly (and
incomplete) work-around.
[...]
Unfortunately I did not found a way to get something like the above
reference from the property Customer.Age. Of course, one could use lamda
expressions all over the world.

"All over the world"? Seems to me, you'd have to pass appropriate
delegate instances during the initialization of your envisioned DataGrid
variant, and that would be that.

Yes, but there are many Grids. Furthermore the same binding scheme also
applies to single controls. These Controls could be generated by a
repeater over the meta data of a type and a control factory. This will
generate a fully functional editor for any data type, even if its
properties are not only basic data types. Of course, a user or
customizing data may choose, which properties can be accessed in a view.

Why does your example declare "SetProperty" with a Func<T, TResult>, but
then apparently use the method with an Action<T>?

Where do you see Action<T>? (Customer cust) => cust.Age is of type
Func said:
Wouldn't Action<T> be
more appropriate in the declaration?

No. At the point of the delegate definition (i.e. column creation) I do
not have an object of type customer. The function has to be applied to
each data row.
And what are "O" and "T" in that
declaration?

O := row type
T := property type

What drawbacks are you trying to avoid that you think that your proposed
feature would solve?

First of all: type safety. Not /that/ important: performance.
Given your problem description (vague as it is),
it seems that what you're really asking for is exactly what reflection
provides: an object (i.e. PropertyInfo) that provides an abstraction of
the property getter and setter that can be used at any time later.
Reflection is necessarily not type-safe at compile time, but it's
trivial to cast at run-time assuming the code can know the type (and if
it can't, you couldn't use generics anyway).

Hmm, wrapping the PropertyDescriptor type safely could be an option.

You could instead use lambda expressions to create type-safety at
compile time, and there's nothing about your problem description that
makes clear to me why you would need to specify the expression more than
once in your code.
It should be able to be used to create a delegate
instance on initialization, where that instance is then reused at any
point later where you need the access you're looking for.

OK, I could hold a delegate for each property in a central location,
rather than at any place where I refer to a property. Well, two
delegates for each property, since I need a setter too and a .NET
function cannot return something like "ref T".

Writing entity types becomes somewhat like child labor, because each
property needs at least 3 consistent objects (the property and the two
delegates).
But fundamentally, one major problem here is that your problem
description is vague. You didn't post any sort of complete code example
that would show exactly what you mean,

Well, the complete OR mapper code is large. And it consists of several
things that do not belong to this topic, like emulated constness and
sharing of const objects between threads. Making a minimal working
example is several hours of work.
There are a few lines of code in your question that hint at
what you really want, but those sketches aren't enough to really explain
what you mean.

You are right. I am sorry for inconvenience. Hopefully I could improve
that. But maybe I only raised even more questions.

Thanks for your reply. I will rethink the tip with the static delegates.
Putting the getter and setter together in a struct will give me
something like a type safe reference to a property.
But it would be really helpful if the .NET language would support to
initialize a delegate type from a property. I am almost sure that this
is nearly a no-op in IL code, since the required methods get_Property
and set_Property already exist. There is only no syntax to access them
explicitly.


Marcel
 
M

Marcel Müller

Peter said:
I must be missing something, because in the above I still don't see how
the property access is strongly-typed. I see the generic type parameter
for the object type itself, but not for the properties of said object.

You are right. In this case not, since the column factory should be able
to create a column for any type in O anyway. I mentioned this after I
sent the last post.

In case of individual controls, they bind to another interface which is
strongly typed to the property type rather than the object type. This
interface is also implemented by EntityProperty:
class EntityProperty<E,T>
: IPropertyRef<AnyObject<E>>, IPropertyTypeRef<T>

class MyBindableTextControl
{
IPropertyTypeRef<string> DataAttribute { get; set; }
...
}

Are you using the Entity Framework? Unfortunately, I have practically
no experience with EF, so you'll need to dumb down the examples for me
if you want me to understand them. Please don't assume I know the EF
syntax and typical use cases.

No, I do not know it either. I am restricted to .NET 3.5 which I heard
has no reasonable EF implementation. But there are similarities to my
requirements.

The EF implementation also uses delegates:
delegate V DGet<T, V>(T t);
delegate void DSet<T, V>(T t, V v);
delegate void DRSet<T, V>(ref T t, V v); // I guess for value types

But the code around them is really dirty:
if (!objectType.IsValueType)
iLGenerator.Emit(OpCodes.Ldind_Ref);
...

[...]
This concept fulfills all my requirements, since the EntityProperty
instances serve as references to properties.
Unfortunately this is mutually exclusive with the .NET concept to bind
to properties via reflection.

I think ultimately if you don't want to write code that explicitly
refers to named properties (e.g. lambda expressions), you're stuck with
reflection. It's fundamental to C#, either the compiler gets to know
what you're trying to access and that shows up in an anonymous method
for the purpose of creating delegates, or you use reflection to find out
about it at run-time.

Seems that you are right: Lambdas and/or delegates are the only safe
solution.

See below for a code example. For more information, read the
documentation for the System.Delegate class
(http://msdn.microsoft.com/en-us/library/y22acf51.aspx) and in
particular the parts of the discussion involving "open instance" delegates.

Oh, I never heard about open instance delegates so far. This is rather
close to my needs. Unfortunately it is not supported be the C# language
AFICS. So I need to initialize it by reflection - not so pretty, because
it will still break refactoring. However, better than nothing and only
at initialization.

[...]
What drawbacks are you trying to avoid that you think that your
proposed feature would solve?

First of all: type safety. Not /that/ important: performance.

Reflection does not have to be inherently type unsafe. Yes, the API
uses "object", but when wrapped in generic code, you can cast
appropriately.

Unfortunately this will introduce auto boxing intensely for any simple
type like int. This could be quite expensive when used for any access to
the data.

[...]
Writing entity types becomes somewhat like child labor, because each
property needs at least 3 consistent objects (the property and the two
delegates).

I'm not sure what you mean by "property" in this case. I don't see any
way to get out of two delegates, assuming you want both a setter and a
getter. But they can each be constructed in a way that requires no
additional information except for the reference to the object from or to
which the getter or setter is applied.

.... and the name of the individual property as string to get the MemberInfo.

It seems to me that the underlying question here probably has little or
nothing to do with "the complete OR mapper code". That is, you should
be able to conceive a way to present the basic question in a more
fundamental way, ignoring the question of application.

One hopes for that one would not need several hours of work. Of course,
it could take some time and effort to re-imagine the question outside
the context of the ORM design. But in the long run, that can only help
both you and anyone else reading this discussion, as it would generalize
the discussion in a way that could lead to more and/or better answers
from different people, as well as help apply the answers to a broader
range of scenarios.

Maybe. For now I evaluate the delegate concept. It does not look that
bad so far, but a POC has still to be done. I will do that.

Yes, but inasmuch as you're able to answer the questions in a useful
way, we should at least be able to make forward progress, however
slowly. :)
Indeed.


But, even without assuming the getter and setter name, it's not too
difficult to use reflection to get at the needed information and
construct a delegate instance from that. For example:

Func<TObject, TProperty> GetOpenGetter<TObject, TProperty>(string name)
{
PropertyInfo pi = typeof(TObject).GetProperty(name);
MethodInfo miGetter = null;

foreach (MethodInfo mi in pi.GetAccessors())
{
if (mi.ReturnType != typeof(System.Void))
{
miGetter = mi;
break;
}
}

return Delegate.CreateDelegate(typeof(Func<TObject, TProperty>),
miGetter);
}

(Or something like that; I didn't bother to compile, never mind test,
the above code, so there might be minor typographical or API errors in it).

No Problem. I see what you mean.

Btw.:
Perhaps that can give you some ideas for how to implement your
general-purpose, strongly-typed, generics-based system?

Yes. But I must do something wrong. The code tends to become an entirely
large workaround because of missing language features. References to
properties are only one aspect.
It seems to me that the language is still a too new with respect to
template meta programming. C++ also took years to come around its start
up problems. Things like partial specialization are still waiting for
the .NET languages. And it is really a pitty that .NET does not provide
const types and member functions. This would make dozens of proxy
classes obsolete like ReadOnlyCollection (which is btw. in fact a
ReadOnlyList).


Marcel
 
M

Marcel Müller

Peter said:
[...]
Reflection does not have to be inherently type unsafe. Yes, the API
uses "object", but when wrapped in generic code, you can cast
appropriately.

Unfortunately this will introduce auto boxing intensely for any simple
type like int. This could be quite expensive when used for any access to
the data.

It _could_ be, yes. But probably won't be.

Unfortunately I have no reliable information about the real memory
impact of auto-boxing. So I am simply unsure.

I suppose in some very specific scenarios it might be useful to be able
to refer to the actual getter or setter of a property without using
reflection. But frankly, I don't think it comes up that much; I realize
that when one is running into a specific scenario, it always seems like
surely everyone else must have the same issue. But in reality, I think
the language designers have a pretty good handle on what's actually a
common case and what's not.

Maybe my statement could be misunderstood. I am not disappointed about
the missing features. I know .NET supports no multiple inheritance and I
can live with that. Sometimes it would have been helpful but not too
often. And in fact it makes many other things easier.
From my point of view it's a pity that .NET supports no const
references to mutable objects. But this is consequent and OK.

On the other side there are language features that are only supported
partially. E.g. there are Methods. Some of them can use generic
parameters. Some of them can be assigned to a delegate.
Generic Delegate
static method yes yes
instance method yes yes
static getter no(*) no (*) makes little sense
static setter no(*) no
instance getter no(*) no
instance setter no(*) no
overloaded operator no no(**) (**) AFAIK
conversion operator no no(**)
indexer getter no no
indexer setter no no
extension method yes yes

The syntactical support of the properties (in fact getters and setters)
has nothing to do with the functionality of delegates and methods. This
is what I call inconsistent or non-orthogonal. And most of the 'no's in
the above list are straight forward to implement without breaking the
syntax look and feel. And AFAICS from the CLI point of view, all of them
are nothing special at all.

Frankly, if anything I find the real world syntax clearer. It's also
much simpler, because it relies on a language feature that's vastly
useful in all manners of other scenarios as well. There's no
special-purpose, property-only language feature required.

The properties /are/ a special purpose feature. Their functionality is
equal to zero, because using explicit get/set methods would result in
exactly the same assembly with the same run time behavior. They only
create more pretty code. (/Much/ more pretty.)
Unfortunately by using them other existing features like taking
delegates are discarded.
And it seems to me that the language is light-years beyond C++ in
"template meta programming".

There is almost nothing except reflections that can't be done in C++ in
a very similar way. Well, from the functional point of view. From the
programmers point of view, exposing every template source code might be
quite bad.
IMHO, one of the biggest issues in C++ is that fundamentally, templates
are macros.

In fact .NET is not that much different. Only the expansion process is
deferred to the JIT compiler. And of course, this can reduce the code
size automatically (shared implementations).
The language has come a long way since the first iteration
of templates, and there are things one can do with templates that are
simply not possible with the .NET generic system.

Of course. Most of them I never really missed. Some would be nice to
have, e.g. partial specialization (enables traits classes).

But I don't find those scenarios nearly as interesting as the benefits
that the .NET generic system gives me. And I've wasted far too much of
my time trying to figure out C++ code someone else wrote where they
either abused the template system, or stumbled across some trap
templates set up for them.

Well, .NET has enough features to write Yo-yo code too.
I gladly trade improved maintainability and
productivity of generics for the so-called "power" of C++ templates.

The greatest problem of C++ is the mixed C code. Many programmers mainly
changed the file extension but not the paradigm. C++ requires
discipline. .NET requires much less of it.
Things like partial specialization are still waiting for
the .NET languages. [...]

It's true that there are a number of features found in other languages
that are not present in .NET. I don't miss them. If you do miss them,
then perhaps C# is not the language you should be using.

The C# language will develop further. And with that it will become more
and more complex. And with the complexity it will become more difficult
to learn, and code will become more difficult to maintain. And at some
point someone will come, present a new language and framework (with
limited features) and say that it is much easier and better than any
language before. This cycle has always been part of computer languages.

At the end of
the day, it's the same computer running your code, so you should be
writing your program in whatever language allows _you_ to best express
to that same computer what it is you want it do.

I took the decision pro C# for our company years ago. But this does not
mean that there might not be improvements to the language.


Marcel
 
M

Marcel Müller

Peter said:
Past experience tells me that in most cases, the cost of boxing is far
less than the overall cost of whatever else the code is doing.

I do not expect unreasonable CPU load. I only care about the memory
load. If I apply a LINQ Query to let's say 20000 memory objects and this
includes comparisons for two auto-boxed properties, a single query of
one user creates 40000 temporary objects. I don't know how effectively
the GC gets rid of them, especially when 20 users press the button. But
maybe even that is no real problem.

But as with all performance issues, it's not something one should worry
much about without some specific proof that it's in fact a problem. The
first priority should be working, maintainable code.

Well, I learned that keeping performance at least in mind at early
development stages. It saved many days because the tests become faster
and expensive structural changes at later development stages are not
required. This does not count if you only have one software per physical
or virtual machine. But if you are running on shared web application
servers or SAP application servers, it makes a difference whether any
module is only written in a way that it will not cause the system
collapse (when running alone). Of course, there is some break even.

I would love to see a kind of "const" in C# that enforces object
immutability. This is quite different from the "const" C++ programmers
are used to. I definitely would not like to see C++'s "const" in C#.

So what is your proposal for const in C#?

Take another look at your list:


In every case, the "methods" you have marked as "no" are abstractions.
Your "generic" column is all wrong anyway, because in the ways that are
important, those methods _can_ be generic (i.e. as a member of a generic
type).

OK, I did not mean generic classes. Of course, this works.


[...]
Fact is, if you don't like the abstraction, you are free to ignore them
and just use methods for all of those things. Then you can trivially
make them generic or create delegates from them.

That's what I did in case of the indexers. In fact I did not have any
alternatives.
Of course, the moment you do so, you'll find that you lose the benefit
of the abstraction. And with respect to the generics question, I think
you'll find that being able to make any of those generic is of very
little practical use.

This turned out to be different for me.

There are a number of key features of generics that C++ templates don't
have. The two most important IMHO are yes, reflection (you have
run-time access to the constructed type's information),

When I look back, every time when I used reflections in the past (Java
and C#), it was only to compensate for missing language features or for
debugging or testing purposes.
and code
generation (for reference types, you only need one copy of the code in
your assembly, and any other assembly can use that copy simply by
referencing your own, rather than winding up with yet another copy of
the code in its own).

That right, with some restrictions. AFAIK, if you use reflections in
static methods then individual copies have to be created.
In C++ I used a similar pattern, but it always requires a non template
base class. So the programmer has to care about this fact.

Not correct. There is no "expansion process" at all. Generic types are
real, reusable types. The only expansion (i.e. duplication of code)
that happens is for generics used with value types,

Are you sure? (see above)

Surely there are things that can be included to make the language more
useful. But so far, none of the things you've complained about fit that
description. Every single one of your complaints falls into the
category of "I want C# to have the same brittleness of C++". That is
antithetical to the whole idea behind C#.

If you want a language as brittle as C++, then please, use C++.

I used some more languages. But yes, my experience with generic
programming is mainly based on C++ (since mid 90s). So I am biased. But
my goal is to separate algorithms, data storage and business logic as
far as possible. This requires a high level of abstraction of the
programming language. Once in a while I run into limitations of a
particular language. C++ is no exception. The only language that I never
managed to drive beyond it's limits is Mathematica from Wolfram
Research. It has a very orthogonal design, but it is far away from being
usable for business applications.


Marcel
 
M

Marcel Müller

Peter said:
Like I said: it enforces object immutability. That is, to be able to
declare an object as immutable, imposing the requirements that:

* Every field in the object is initialized at construction
* Every reference type field in the object refers only to other
immutable objects

Today, I can write a type that is immutable, but the run-time has no
idea that it is, never mind can enforce the immutability or take
advantage of it in any interesting ways (such as optimizing concurrently
executing code).

OK, this would be helpful especially in multi threaded context, as long
as the immutability implies that shared (read) access is guaranteed to
work unsynchronized.
Currently this could only be done with discipline. Read-only fields will
mostly do the job, but you have to use them consequently over all levels
of your object composition. The important point is the read-only fields
must not be anything else than value types and immutable types.
Furthermore to be compatible with the reflection based GUI framework
classes you need an additional property for each readonly field. Not too
pretty.

From this point of view it should be rather called "readonly class"
than "const" to be consistent with the language syntax.

I don't see the point in a generic indexer, other than a single indexer
in a generic class.

A generic indexer could be used to implement a type safe ntuple with no
compile time limited size.

If so, I'm skeptical that you chose the best approach for your design.
But of course, absent a real code example purporting to demonstrate the
utility of a generic indexer method, it would be foolish of me to
discount the possibility completely.

Think about an instance of the DataRow class. If you had typed columns
like DataColumn<int> myIntColumn the expression myDataRow[myIntColumn]
would return int rather than object.

Of course, if all your columns are known at compile time, you could use
a code generator and create a strongly typed DataSet. But if you are
writing a library that has no idea of the data types it will be used
for, then you do not have this option.

Reflection is very useful for writing general purpose code to handle
unknown types. The serialization infrastructure relies on it heavily,
for example.

That's true. If you do not always want to implement ISerializable,
Reflections are really handy.

But in fact, every time I see someone using reflection as a way around
what they perceive as missing language features, it has pretty much
always turned out that they simply are trying to force the language into
an incorrect model. It generally turns out that there are better, more
idiomatic ways to achieve the same goal, without reflection.

That's some truth. But sometimes the intension of the programmer to type
as few as possible get him in the wrong direction.

Not true.

OK, seems I misunderstood the Microsoft paper about the generics
implementation. They add hidden parameters instead.
I was and still am positive. Just to double-check, I went ahead and
wrote a quick-and-dirty project to see what code was executing, even
when I called a static generic method via reflection. The code being
executed was always the same (i.e. same native instructions at the same
memory address), regardless of the constructed type being used.

You are right. The difference is up to the caller. The static functions
are supplied with the type parameters at run time.
(Maybe it is up to the implementation to behave different.)


Marcel
 
M

Marcel Müller

Peter said:
Think about an instance of the DataRow class. If you had typed columns
like DataColumn<int> myIntColumn the expression myDataRow[myIntColumn]
would return int rather than object.

And the indexer would look like:

public T this<T>[int index]
{
get { return (T)array[index];
}

Then the call site looks like:

int value = column<int>[5];

instead of:

int value = (int)column[5];

I fail to see why the former is better than the latter. Either way you
have to specify the type.

It makes no sense in this case. It makes only sense if the type can be
inferred from the argument. E.g.

class ColumnDescriptor<T>
{
public int Index { get; private set; }
...
}

public T this<T>[ColumnDescriptor<T> col]
{ get { return (T)array[col.Index]; }
}

I don't find them useful at all when supplying
the type parameter does nothing more than move a cast from outside the
called method to inside it.

In very rare cases I used this pattern, because the explicit type
parameters bind closer than the type cast and therefore requires less
braces. But normally it makes no sense.

Note also that applying a generic parameter to an indexer method is
problematic from a language specification and compiler's point of view,
because wherever you put it, it doesn't fit with the current way that
generic type parameters work.

Do you mean the syntax for specifying the explicit type parameters?


Marcel
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top