Consider the following code:
public interface IIdentifiable<T>
{
T Id { get; set; }
}
public interface IViewModel
{
}
public class MyViewModel1 : IViewModel, IIdentifiable<int>
{
public string MyProperty { get; set; }
public int Id { get; set; }
}
public class MyViewModel2 : IViewModel, IIdentifiable<string>
{
public string MyProperty { get; set; }
public string Id { get; set; }
}
I also have class that operates with ViewModels:
public class Loader<T> where T: IViewModel
{
public void LoadData()
{
/*some important stuff here*/
if (typeof(IIdentifiable<??>).IsAssignableFrom(typeof(T)))
{ // ^- here's the first problem
data = data.Where(d => _dataSource.All(ds => ((IIdentifiable<??>) ds).Id != ((IIdentifiable<??>) d).Id)).ToList();
} // ^---- and there the second ----^
/*some important stuff here too*/
}
}
Now, as you can see, viewmodels that I have might implement the IIdentifiable<> interface. I want to check that, and if it's true,
I want to make sure my data list does not contains any entry that are already present in my _dataSourse list.
So I have 2 questions:
I don't know what IIdentifiable<> has in its generic parentheses, it might be int, string or even GUID.
I tried typeof(IIdentifiable<>).IsAssignableFrom(typeof(T)) which is the correct syntax, yet it always returns false.
Is there a way to check whether T is IIdentifiable<> without knowing the exact generic type?
If there is an answer for the first question, I would also like to know how can I compare the Id fields without knowing their type.
I found this answer quite useful, yet it doesn't cover my
specific case.
I know that I probably can solve that problem if I make my Loader<T> class a generic for two types Loader<T,K>, where K would be the
type in IIdentifiable<>, yet I would like to know if there are other solutions.
P.S. In addition to my first question: I'm also curious why one can write something like this typeof(IIdentifiable<>).IsAssignableFrom(typeof(T)) if it returns false when the generic type of IIdentifiable<> is not specified?
Edit: I guess, in hindsight, I understand why I can't write the code this bluntly - because there's might be the collection ICollection<IViewModel> where the entries implement different types of IIdentifiable<> (or don't implement it at all), and the check like that would fail awkwardly. Yet maybe there is a way to do something like that with some restrictions, but without creating second generic parameter to my Loader?
Try add two methods to your Loader<T>:
public bool CanCast<TId>()
{
var identifiableT = typeof(IIdentifiable<>).MakeGenericType(typeof(TId));
return identifiableT.IsAssignableFrom(typeof(T));
}
public IEnumerable<IIdentifiable<TId>> Filter<TId>(IEnumerable<T> data)
{
return data.Where(d => _dataSource.All(
ds => !((IIdentifiable<TId>) ds).Id.Equals(((IIdentifiable<TId>) d).Id)));
}
Then in LoadData
if (CanCast<int>())
data = Filter<int>(data);
else if (CanCast<Guid>())
data = Filter<Guid>(data);
// and so om
Well, I would suggest you to always use a string for identification. You can convert int and guid to a string. And if you want to ensure proper type is used then you can prefix the string with type information.
However, I do think that the performance of you algorithm would be very poor as you wouls essentially loop 2 containers so it would be O(n * m).
Thus it would be best to either do appropriate SQL query if both sources are from the database or use a dictionary if you do it in code. Alternatively if data is properly sorted, you could find duplicates more efficiently.
By the way generics are quite limited in C#. Sometime using ˋFunc<>ˋ could help but even then you have to provide extra information to the algorithm.
We should address your question in two steps (because there really are two problems to solve here).
First, make following change to your interface IIdentifiable<T>
public interface IIdentifiable<T>
where T : IEquatable<T>
{
T Id { get; set; }
}
This will ensure that you can compare Id properties correctly.
Secondly, in your LoadData() method, change the if statement to
if (T is IIdentifiable<T>)
{ // ^- here's the first problem
data = data.Where(d => _dataSource.All(ds => ((IIdentifiable<T) ds).Id != ((IIdentifiable<T) d).Id)).ToList();
}
Related
I am trying to find a better way to handle some growing if constructs to handle classes of different types. These classes are, ultimately, wrappers around disparate value types (int, DateTime, etc) with some additional state information. So the primary difference between these classes is the type of data they contain. While they implement generic interfaces, they also need to be kept in homogeneous collections, so they also implement a non-generic interface. The class instances are handled according to the type of data they represent and their propogation continues or doesn't continue based on that.
While this is not necessarily a .NET or C# issue, my code is in C#.
Example classes:
interface ITimedValue {
TimeSpan TimeStamp { get; }
}
interface ITimedValue<T> : ITimedValue {
T Value { get; }
}
class NumericValue : ITimedValue<float> {
public TimeSpan TimeStamp { get; private set; }
public float Value { get; private set; }
}
class DateTimeValue : ITimedValue<DateTime> {
public TimeSpan TimeStamp { get; private set; }
public DateTime Value { get; private set; }
}
class NumericEvaluator {
public void Evaluate(IEnumerable<ITimedValue> values) ...
}
I have come up with two options:
Double Dispatch
I recently learned of the Visitor pattern and its use of double dispatch to handle just such a case. This appeals because it would allow undesired data to not propogate (if we only want to handle an int, we can handle that differently than a DateTime). Also, the behaviors of how the different types are handled would be confined to the single class that is handling the dispatch. But there is a fair bit of maintenance if/when a new value type has to be supported.
Union Class
A class that contains a property for each value type supported could be what each of these classes store. Any operation on a value would affect the appropriate component. This is less complex and less maintenance than the double-dispatch strategy, but it would mean that every piece of data would propogate all the way through unnecessarily as you can no longer discriminate along the lines of "I don't operate upon that data type". However, if/when new types need to be supported, they only need to go into this class (plus whatever additional classes that need to be created to support the new data type).
class UnionData {
public int NumericValue;
public DateTime DateTimeValue;
}
Are there better options? Is there something in either of these two options that I did not consider that I should?
method 1, using dynamic for double dispatch (credit goes to http://blogs.msdn.com/b/curth/archive/2008/11/15/c-dynamic-and-multiple-dispatch.aspx).
Basically you can have your Visitor pattern simplified like this:
class Evaluator {
public void Evaluate(IEnumerable<ITimedValue> values) {
foreach(var v in values)
{
Eval((dynamic)(v));
}
}
private void Eval(DateTimeValue d) {
Console.WriteLine(d.Value.ToString() + " is a datetime");
}
private void Eval(NumericValue f) {
Console.WriteLine(f.Value.ToString() + " is a float");
}
}
sample of usage:
var l = new List<ITimedValue>(){
new NumericValue(){Value= 5.1F},
new DateTimeValue() {Value= DateTime.Now}};
new Evaluator()
.Evaluate(l);
// output:
// 5,1 is a float
// 29/02/2012 19:15:16 is a datetime
method 2 would use Union types in c# as proposed by #Juliet here (alternative implementation here)
I tell you have I've solved a similar situation - is by storing the Ticks of a DateTime or TimeSpan as double in the collection and by using IComparable as a where constraint on the type parameter. The conversion to double / from double is performed by a helper class.
Please see this previous question.
Funnily enough this leads to other problems, such as boxing and unboxing. The application I am working on requires extremely high performance so I need to avoid boxing. If you can think of a great way to generically handle different datatypes (including DateTime) then I'm all ears!
Good question. The first thing that came to my mind was a reflective Strategy algorithm. The runtime can tell you, either statically or dynamically, the most derived type of the reference, regardless of the type of the variable you are using to hold the reference. However, unfortunately, it will not automatically choose an overload based on the derived type, only the variable type. So, we need to ask at runtime what the true type is, and based on that, manually select a particular overload. Using reflection, we can dynamically build a collection of methods identified as handling a particular sub-type, then interrogate the reference for its generic type and look up the implementation in the dictionary based on that.
public interface ITimedValueEvaluator
{
void Evaluate(ITimedValue value);
}
public interface ITimedValueEvaluator<T>:ITimedValueEvaluator
{
void Evaluate(ITimedValue<T> value);
}
//each implementation is responsible for implementing both interfaces' methods,
//much like implementing IEnumerable<> requires implementing IEnumerable
class NumericEvaluator: ITimedValueEvaluator<int> ...
class DateTimeEvaluator: ITimedValueEvaluator<DateTime> ...
public class Evaluator
{
private Dictionary<Type, ITimedValueEvaluator> Implementations;
public Evaluator()
{
//find all implementations of ITimedValueEvaluator, instantiate one of each
//and store in a Dictionary
Implementations = (from t in Assembly.GetCurrentAssembly().GetTypes()
where t.IsAssignableFrom(typeof(ITimedValueEvaluator<>)
and !t.IsInterface
select new KeyValuePair<Type, ITimedValueEvaluator>(t.GetGenericArguments()[0], (ITimedValueEvaluator)Activator.CreateInstance(t)))
.ToDictionary(kvp=>kvp.Key, kvp=>kvp.Value);
}
public void Evaluate(ITimedValue value)
{
//find the ITimedValue's true type's GTA, and look up the implementation
var genType = value.GetType().GetGenericArguments()[0];
//Since we're passing a reference to the base ITimedValue interface,
//we will call the Evaluate overload from the base ITimedValueEvaluator interface,
//and each implementation should cast value to the correct generic type.
Implementations[genType].Evaluate(value);
}
public void Evaluate(IEnumerable<ITimedValue> values)
{
foreach(var value in values) Evaluate(value);
}
}
Notice that the main Evaluator is the only one that can handle an IEnumerable; each ITimedValueEvaluator implementation should handle values one at a time. If this isn't feasible (say you need to consider all values of a particular type), then this gets really easy; just loop through every implementation in the Dictionary, passing it the full IEnumerable, and have those implementations filter the list to only objects of the particular closed generic type using the OfType() Linq method. This will require you to run all ITimedValueEvaluator implementations you find on the list, which is wasted effort if there are no items of a particular type in a list.
The beauty of this is its extensibility; to support a new generic closure of ITimedValue, just add a new implementation of ITimedValueEvaluator of the same type. The Evaluator class will find it, instantiate a copy, and use it. Like most reflective algorithms, it's slow, but the actual reflective part is a one-time deal.
Why not just implement the interface that you actually want, and allow the implementing type to define what the value is? For example:
class NumericValue : ITimedValue<float> {
public TimeSpan TimeStamp { get; private set; }
public float Value { get; private set; }
}
class DateTimeValue : ITimedValue<DateTime>, ITimedValue<float> {
public TimeSpan TimeStamp { get; private set; }
public DateTime Value { get; private set; }
public Float ITimedValue<Float>.Value { get { return 0; } }
}
class NumericEvaluator {
public void Evaluate(IEnumerable<ITimedValue<float>> values) ...
}
If you want the behavior of the DateTime implementation to vary based on the particular usage (say, alternate implementations of Evaluate functions), then they by definition need to be aware of ITimedValue<DateTime>. You can get to a good statically-typed solution by providing one or more Converter delegates, for example.
Finally, if you really only want to handle the NumericValue instances, just filter out anything that isn't a NumericValue instance:
class NumericEvaluator {
public void Evaluate(IEnumerable<ITimedValue> values) {
foreach (NumericValue value in values.OfType<NumericValue>()) {
....
}
}
}
Short Version
The MSDN documentation for Type.GetProperties states that the collection it returns is not guaranteed to be in alphabetical or declaration order, though running a simple test shows that in general it is returned in declaration order. Are there specific scenarios that you know of where this is not the case? Beyond that, what is the suggested alternative?
Detailed Version
I realize the MSDN documentation for Type.GetProperties states:
The GetProperties method does not return properties in a particular
order, such as alphabetical or declaration order. Your code must not
depend on the order in which properties are returned, because that
order varies.
so there is no guarantee that the collection returned by the method will be ordered any specific way. Based on some tests, I've found to the contrary that the properties returned appear in the order they're defined in the type.
Example:
class Simple
{
public int FieldB { get; set; }
public string FieldA { get; set; }
public byte FieldC { get; set; }
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Simple Properties:");
foreach (var propInfo in typeof(Simple).GetProperties())
Console.WriteLine("\t{0}", propInfo.Name);
}
}
Output:
Simple Properties:
FieldB
FieldA
FieldC
One such case that this differs only slightly is when the type in question has a parent who also has properties:
class Parent
{
public int ParentFieldB { get; set; }
public string ParentFieldA { get; set; }
public byte ParentFieldC { get; set; }
}
class Child : Parent
{
public int ChildFieldB { get; set; }
public string ChildFieldA { get; set; }
public byte ChildFieldC { get; set; }
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Parent Properties:");
foreach (var propInfo in typeof(Parent).GetProperties())
Console.WriteLine("\t{0}", propInfo.Name);
Console.WriteLine("Child Properties:");
foreach (var propInfo in typeof(Child).GetProperties())
Console.WriteLine("\t{0}", propInfo.Name);
}
}
Output:
Parent Properties:
ParentFieldB
ParentFieldA
ParentFieldC
Child Properties:
ChildFieldB
ChildFieldA
ChildFieldC
ParentFieldB
ParentFieldA
ParentFieldC
Which means the GetProperties method walks up the inheritance chain from bottom up when discovering the properties. That's fine and can be handled as such.
Questions:
Are there specific situations where the described behavior would differ that I've missed?
If depending on the order is not recommended then what is the recommended approach?
One seemingly obvious solution would be to define a custom attribute which indicates the order in which the properties should appear (Similar to the Order property on the DataMember attribute). Something like:
public class PropOrderAttribute : Attribute
{
public int SeqNbr { get; set; }
}
And then implement such as:
class Simple
{
[PropOrder(SeqNbr = 0)]
public int FieldB { get; set; }
[PropOrder(SeqNbr = 1)]
public string FieldA { get; set; }
[PropOrder(SeqNbr = 2)]
public byte FieldC { get; set; }
}
But as many have found, this becomes a serious maintenance problem if your type has 100 properties and you need to add one between the first 2.
UPDATE
The examples shown here are simply for demonstrative purposes. In my specific scenario, I define a message format using a class, then iterate through the properties of the class and grab their attributes to see how a specific field in the message should be demarshaled. The order of the fields in the message is significant so the order of the properties in my class needs to be significant.
It works currently by just iterating over the return collection from GetProperties, but since the documentation states it is not recommended I was looking to understand why and what other option do I have?
The order simply isn't guaranteed; whatever happens.... Happens.
Obvious cases where it could change:
anything that implements ICustomTypeDescriptor
anything with a TypeDescriptionProvider
But a more subtle case: partial classes. If a class is split over multiple files, the order of their usage is not defined at all. See Is the "textual order" across partial classes formally defined?
Of course, it isn't defined even for a single (non-partial) definition ;p
But imagine
File 1
partial class Foo {
public int A {get;set;}
}
File 2
partial class Foo {
public int B {get;set:}
}
There is no formal declaration order here between A and B. See the linked post to see how it tends to happen, though.
Re your edit; the best approach there is to specify the marshal info separately; a common approach would be to use a custom attribute that takes a numeric order, and decorate the members with that. You can then order based on this number. protobuf-net does something very similar, and frankly I'd suggest using an existing serialization library here:
[ProtoMember(n)]
public int Foo {get;set;}
Where "n" is an integer. In the case of protobuf-net specifically, there is also an API to specify these numbers separately, which is useful when the type is not under your direct control.
For what it's worth, sorting by MetadataToken seemed to work for me.
GetType().GetProperties().OrderBy(x => x.MetadataToken)
Original Article (broken link, just listed here for attribution):
http://www.sebastienmahe.com/v3/seb.blog/2010/03/08/c-reflection-getproperties-kept-in-declaration-order/
I use custom attributes to add the necessary metadata myself (it's used with a REST like service which consumes and returns CRLF delimited Key=Value pairs.
First, a custom attribute:
class ParameterOrderAttribute : Attribute
{
public int Order { get; private set; }
public ParameterOrderAttribute(int order)
{
Order = order;
}
}
Then, decorate your classes:
class Response : Message
{
[ParameterOrder(0)]
public int Code { get; set; }
}
class RegionsResponse : Response
{
[ParameterOrder(1)]
public string Regions { get; set; }
}
class HousesResponse : Response
{
public string Houses { get; set; }
}
A handy method for converting a PropertyInfo into a sortable int:
private int PropertyOrder(PropertyInfo propInfo)
{
int output;
var orderAttr = (ParameterOrderAttribute)propInfo.GetCustomAttributes(typeof(ParameterOrderAttribute), true).SingleOrDefault();
output = orderAttr != null ? orderAttr.Order : Int32.MaxValue;
return output;
}
Even better, write is as an extension:
static class PropertyInfoExtensions
{
private static int PropertyOrder(this PropertyInfo propInfo)
{
int output;
var orderAttr = (ParameterOrderAttribute)propInfo.GetCustomAttributes(typeof(ParameterOrderAttribute), true).SingleOrDefault();
output = orderAttr != null ? orderAttr.Order : Int32.MaxValue;
return output;
}
}
Finally you can now query your Type object with:
var props = from p in type.GetProperties()
where p.CanWrite
orderby p.PropertyOrder() ascending
select p;
Relying on an implementation detail that is explicitly documented as being not guaranteed is a recipe for disaster.
The 'recommended approach' would vary depending on what you want to do with these properties once you have them. Just displaying them on the screen? MSDN docs group by member type (property, field, function) and then alphabetize within the groups.
If your message format relies on the order of the fields, then you'd need to either:
Specify the expected order in some sort of message definition. Google protocol buffers works this way if I recall- the message definition is compiled in that case from a .proto file into a code file for use in whatever language you happen to be working with.
Rely on an order that can be independently generated, e.g. alphabetical order.
1:
I've spent the last day troubleshooting a problem in an MVC 3 project, and it all came down to this particular problem. It basically relied on the property order being the same throughout the session, but on some occations a few of the properties switched places, messing up the site.
First the code called Type.GetProperties() to define column names in a dynamic jqGrid table, something that in this case occurs once per page_load. Subsequent times the Type.GetProperties() method was called was to populate the actual data for the table, and in some rare instances the properties switched places and messed up the presentation completely. In some instances other properties that the site relied upon for a hierarchical subgrid got switched, i.e. you could no longer see the sub data because the ID column contained erroneous data. In other words: yes, this can definitely happen. Beware.
2:
If you need consistent order throughout the system session but not nessecarily exactly the same order for all sessions the workaround is dead simple: store the PropertyInfo[] array you get from Type.GetProperties() as a value in the webcache or in a dictionary with the type (or typename) as the cache/dictionary key. Subsequently, whenever you're about to do a Type.GetProperties(), instead substitute it for HttpRuntime.Cache.Get(Type/Typename) or Dictionary.TryGetValue(Type/Typename, out PropertyInfo[]). In this way you'll be guaranteed to always get the order you encountered the first time.
If you always need the same order (i.e. for all system sessions) I suggest you combine the above approach with some type of configuration mechanism, i.e. specify the order in the web.config/app.config, sort the PropertyInfo[] array you get from Type.GetProperties() according to the specified order, and then store it in cache/static dictionary.
I have a web method which calls a method in the DAL to execute a procedure by id and returns an object of type MyData.
[WebMethod]
public MyData GetDataById(int id)
{
DAL myDAL = new DAL();
return myDAL.GetDataById(id);
}
The class MyData looks like the following
public class MyData
{
public string Name;
public Data[] DataItems;
}
and the class Data,
public class Data
{
public string key;
public string value;
}
Now this worked fine for until we wanted to return a bit of complex types.
For an example, a DataTable, or perhaps something like a structure (or class) containing latitude, longitude and a value. So obviously, class Data cannot hold multiple values or a DataTable. (It contains two strings, key and value).
So what I actually want is the type to be Generic. So I changed it to...
public class MyData<T>
{
public string Name;
public T[] DataItems;
}
So I'll be doing something like this inside the myDAL.GetDataById because what type of data is returned differs according to the type.
if (GetTypeOfId(id) == "NormalData")
{
MyData<Data> result = new MyData<Data>();
}
else if (GetTypeOfId(id) == "Map")
{
MyData<MapData> result = new MyData<MapData>();
}
But I need to specify a type for the method signature as well which unfortunately is found out ONLY at run time.
How do I handle such a situation ?
I feel like I am using Generics for something I shouldn't be using it for.
Or how is usually a situation where the type is found out only at run time resolved?
UPDATE: The worst case scenario is having different web service calls for getting normal data and map data which I would like to avoid.
You can only use generics in circumstances where you can specify the type at compile time, so I don't think they're suitable for your situation.
I would recommend having two web service calls, that's the easiest way to handle this.
If you really want only one web service call you could have your web method simply return a byte[] (created using BinaryFormatter) or a string (created using, say, an XmlSerializer) and then deserialise that on your client side, but it means you have to have the same classes on both sides (or you have to have custom deserialisation code) and your web service can't easily be consumed by multiple clients.
I'm not sure what you are asking for but i have a feeling that using an interface with a generic method could help you pass return values around and call the GetValue generic method on that.
If you use IData instead of a generic type as return value you will be able to extract the embedded data with ret.GetValue<MyData>(). And if you set the Type when creating the Data<T> you will be able to query on that too.
Maybe you can adapt the following snippet to your needs.
public interface IData {
type Type { get; set; }
string Name { get; set; }
T GetValue<T>();
}
public class Data<T> : IData
{
public Type Type { get; set; }
public string Name { get; set; }
public T Value { get; set; }
public Tret GetValue<Tret>() {
return (Tret)(Object)Value;
}
}
The answer was pretty easy and stupid of me not to think of it before.
I just created a parent class and made the Data and all the other required classes inherit from it.
I have a Report Interface which has a Run method.
There are different types of reports which implement this interface and each run their own kind of report, getting data from different tables.
Each report, using its own data context, gets data which then populates Business Objects with and at the moment they are returned as an array (I would like to be able to at least return something like a list but because you have to define the list type it makes it a bit more difficult).
Reflection is then used to find out the properties of the returned data.
I hope I have explained this well enough!
Is there a better way of doing this?
By request:
public interface IReport
{
int CustomerID { get; set; }
Array Run();
}
public class BasicReport : IReport
{
public int CustomerID { get; set; }
public virtual Array Run()
{
Array result = null;
using (BasicReportsDataContext brdc = new BasicReportsDataContext())
{
var queryResult = from j in brdc.Jobs
where j.CustomerID == CustomerID
select new JobRecord
{
JobNumber = j.JobNumber,
CustomerName = c.CustomerName
};
result = queryResult.ToArray();
}
}
}
The other class then does a foreach over the data, and uses reflection to find out the field names and values and puts that in an xml file.
As it stands everything works - I just can't help thinking there is a better way of doing it - that perhaps my limited understanding of C# doesn't allow me to see yet.
Personnally I would first ask myself if I Really need an interface. It would be the case if the classes implementing it are Really different by nature (not only by report kind).
If not, i.e all the implementing classes are basically "Reporters", then yes, there is a more convenient way to do this which is :
Writing a parent abstract Report
Having a virtual Run method and the CustomerID accessor
inheriting your "Reporter" classes from it
I have the following class:
public class Item
{
public Dictionary<string, string> Data
{
get;
set;
}
}
and a list of it:
List<Item> items;
I need to filter and order this list dynamically using SQL-Like strings. The catch is, that I need to order it by the Data dictionary.
For example: Order By Data["lastname"] or Where Data["Name"].StartsWith("a"). I thought to use the dynamic linq library, but is there any way that my clients can write without the Data[]? For example:
Name.StartsWith("abc")
instead of
Data["Name"].StartsWith("abc")
?
You could add a property like this:
public class Item
{
public Dictionary<string, string> Data
{ get; set; }
public string Name { get { return Data["lastname"]; } }
}
//Call by: i.Name.StartsWith("abc");
Or an extension method:
public static class ItemExtensions
{
public static string Name(this Item item)
{
return item.Data["lastname"];
}
}
//Call by: i.Name().StartsWith("abc");
Or if it's a very commonly used method, you could add something like a .NameStartsWith():
public static string NameStartsWith(this Item item, stirng start)
{
return item.Data["lastname"].StartsWith(start);
}
//Call by: i.NameStartsWith("abc");
This doesn't have anything to do with the Linq Dynamic Query unit. That unit is for when you have actual fields/properties and the names of them will be given to you at runtime. In other words, you have a class like this:
public class Person
{
public int ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
And you want to be able to write a query like this:
var sortedPeople = people.OrderBy("FirstName");
You are trying to do the exact opposite of this - you have a class that does not have any actual properties, just an attribute dictionary, and you want compile-time safety. You can't have it; there's no way to guarantee that an item will be in the dictionary, especially when the dictionary is public and anyone can add/remove directly from it!
If there's some reason that you must use that specific class design, then you could conceivably write some wrappers as Nick has presented, but I wouldn't even bother - they're not actually providing any encapsulation because the Data dictionary is still wide open to the whole world. Instead, I would just provide a single safe getter method or indexer property and create a few constants (or an enum) with the names of properties you expect to be in there.
public class Item
{
public Dictionary<string, string> Data { get; set; }
public string GetValue(string key)
{
if (Data == null)
return null;
string result;
Data.TryGetValue(key, out result);
return result;
}
}
public class ItemKeys
{
public const string Name = "Name";
public const string Foo = "Foo";
}
And so on. Really the ItemKeys isn't that important, the safe GetValue method is what's important, because otherwise you run the risk of a NullReferenceException if Data hasn't been assigned, or a KeyNotFoundException if even one Item instance doesn't have that property. Using the GetValue method here will succeed no matter what:
var myItems = items.OrderBy(i => i.GetValue(ItemKeys.Name));
If you find you're writing a lot of repetitive code for the same attributes, then start worrying about adding shortcut properties or extension methods to the class.
I assume that you don't know the names of the properties at compile-time (in which case, you could simply define properties and wouldn't have this problem). I have two suggestions that you could try, but I didn't implement any of them myself, so I can't guarantee that it will work.
If you can use .NET 4.0, you could inherit from DynamicObject and implement TryGetMember method (which is called when you use o.Foo on an object that is declared as dynamic). Assuming that Dynamic LINQ works with DLR, it should automatically invoke this method for objects that inherit from DynamicObject. Inside the TryGetMember method, you would get a name of the accessed property, so you could perform a dictionary lookup. (However, this solution would work only if Dynamic LINQ integrates well with DLR).
In any case, you could do some basic parsing of the string entered by the user and replace for example Name with Data["Name"]. This would definitely work, but it may be a bit difficult (because you should probably at least check that you're doing the replace in correct context - e.g. not inside a string constant).
Regarding extension methods - I'm not sure if Dynamic LINQ handles extension methods (but, I don't think so, because that would require searching all referenced assemblies)