C# Indexer on Named Property Wrapper - c#

I have legacy code that I'm trying to obsolete that I cannot change. Its a column-based data storage class that can be indexed based on the name of the column. Something like this:
StorageClassName scn = new StorageClassName("Property_Name",new double[]{1,2,3});
double[] d = scn["Property_Name"];
I'm trying to create some sort of wrapper class that will allow me to implement interfaces/class inheritance.
BetterStorageClassName bscn = scn;
double[] d = bscn.PropertyName;
What is the best way to accomplish this wrapper class? It doesn't necessarily need to be implicit.
Edit: I left off the main part of this question. The answers I got for the first part are good though. How would I do the conversion the other way?
double[] d = bscn["PropertyName"];
I'm assuming this uses reflection in some capacity.

If you have a class with string indexer and you want to translate that into properties, you could do that using dynamic:
class StorageClassName : Dictionary<string, double[]>
{}
class DynamicStorageClassName : DynamicObject
{
private readonly StorageClassName m_storageClassName;
public DynamicStorageClassName(StorageClassName storageClassName)
{
m_storageClassName = storageClassName;
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
if (m_storageClassName.ContainsKey(binder.Name))
{
result = m_storageClassName[binder.Name];
return true;
}
return base.TryGetMember(binder, out result);
}
}
Usage:
var scn = new StorageClassName { { "PropertyName", new double[] { 1, 2, 3 } } };
dynamic dscn = new DynamicStorageClassName(scn);
Console.WriteLine(dscn.PropertyName[1]);
Keep in mind that you pay some performance penalty for using dynamic and if the set of properties won't change, you should probably use ordinary properties as others suggested.
If, on the other hand, you had a class with ordinary properties and wanted to translate that to using indexer, you can use reflection:
class StaticStorageClassName
{
public double[] PropertyName { get; set; }
public StaticStorageClassName()
{
PropertyName = new double[] { 1, 2, 3 };
}
}
class ReverseStorageClassName
{
private readonly StaticStorageClassName m_staticStorageClassName;
public ReverseStorageClassName(StaticStorageClassName staticStorageClassName)
{
m_staticStorageClassName = staticStorageClassName;
}
public double[] this[string name]
{
get
{
var propertyInfo = typeof(StaticStorageClassName).GetProperty(name);
if (propertyInfo == null)
throw new ArgumentException();
return (double[])propertyInfo.GetValue(m_staticStorageClassName, null);
}
}
}
Usage:
var sscn = new StaticStorageClassName();
var rscn = new ReverseStorageClassName(sscn);
Console.WriteLine(rscn["PropertyName"][2]);
If the various properties have different types, you'd have to make the return type of the indexer either object or dynamic.
Note that using reflection wouldn't work if StaticStorageClassName was implemented using DynamicObject.

For the example given, I would imagine it implemented like this:
public double[] PropertyName
{
get { return wrapped["Property_Name"]; }
set { wrapped["Property_Name"] = value; }
}
Are you trying to avoid writing all these wrappers? Or do type conversions?

From your question I guess you want to have full named properties instead of string based keys. In that case you can just provide properties for the access:
class BetterStorageClassName : StorageClassName
{
public double[] PropertyName
{
get { return this["Property_Name"]; }
set { this["Property_Name"] = value; }
}
}
However that method has several caveats:
It implies that the properties are fixed and don't really change because otherwise you end up constantly modifying your wrapper.
The properties can't be dynamically defined at runtime.
You have to have a wrapper class for each set of properties.

Related

Why Can't .NET Object Property Values Be Set Via Dictionary Keys and Object References?

I've created a data class that I plan to use to send data to be persisted in the database and to return data from the database in a strongly typed way. In addition to its properties, the class contains a Dictionary that I populate in the constructor with the name of and reference to each property. This makes the properties enumerable and enables me to iterate through them using 'foreach'.
This works great when setting property values and sending the object to be persisted in the database. I can iterate through the Dictionary keys, get the value of each property, and add a SqlParameter for each property using the key as the parameter name and the property value as the parameter value.
However, going the other way doesn't work. I can iterate through the Dictionary keys and get the value of each column in each row of the SqlDataReader, but when I try to assign these values to my data object using the Dictionary's reference to the corresponding object property, a curious thing occurs. The assignments succeed, BUT the data object properties all retain their initial, default values. I can view the data object properties and see these initial, default values. I can also view the Dictionary entry values and see the updated values that were read and assigned from the SqlDataReader.
This makes no sense. The Dictionary is supposed to provide access to each property (the 'object' generic type) via its key (the 'string' generic type), but its acting like its maintaining a separate copy of each Dictionary 'KeyValuePair'.
What gives?
I'm doing all this in C# in the context of an ASP.NET Core 2.1.1 project running on macOS 10.13.6 High Sierra.
I've searched StackOverflow extensively, and I see lots of recommendations for using reflection to do this type of thing. I'll refactor my code to use reflection if necessary, but I'd really like to understand where and how my mental model for what's happening is off.
An explanation of what's happening and why would be MOST appreciated.
Example Data Class with Property Dictionary
using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Runtime.Serialization;
using Newtonsoft.Json;
namespace MyOrg.MyProj.Data
{
[DataContract]
public class DataObj
{
#region Attributes
[Required]
[DataMember(Name = "dataObjectId")]
public Int64 DataObjectId { get; set; }
[Required]
[DataMember(Name = "guid")]
public Guid Guid { get; set; }
public virtual Dictionary<string, object> DataMembers { get; set; } //NOTE: Implements the IEnumerable interface in order to support 'foreach' operations, etc on 'DataObj' class attributes
#endregion Attributes
#region Constructors
public DataObj(Int64 dataObjectId, Guid guid)
{
try
{
DataObjectId = dataObjectId;
Guid = guid;
DataMembers = new Dictionary<string, object>
{
{ "DataObjectId", DataObjectId },
{ "Guid", Guid }
};
}
catch (Exception e)
{
Console.WriteLine($"RUNTIME EXCEPTION while INSTANTIATEing DataObj, " + e.Message + ", " + e.StackTrace);
}
}
#endregion Constructors
#region Methods
/// <summary>
/// Implements the IEnumerable interface in order to support 'foreach' operations, etc on 'DataObj' class attributes
/// </summary>
/// <returns>Enumerator</returns>
public Dictionary<string, object>.Enumerator Enumerator()
{
return DataMembers.GetEnumerator(); //NOTE: Return the Dictionary object's IEnumerator rather than implementing IEnumerable for the 'DataObj' class itself
}
#endregion Methods
Example Data Access Class (excerpt)
reader = command.ExecuteReader();
dataObjList = new List<DataObj>();
if (reader.HasRows)
{
while (reader.Read())
{
tempDataObj = new DataObj(-1, new Guid("00000000-0000-0000-0000-000000000000"));
keys = new List<String>(tempDataObj.DataMembers.Keys); //NOTE: Can't modify a Dictionary while iterating through it. See the 'Why This Error?' section of https://stackoverflow.com/questions/604831/collection-was-modified-enumeration-operation-may-not-execute
foreach (String key in keys)
{
tempDataObj.DataMembers[key] = reader[key];
}
dataObjList.Add(tempDataObj);
For 'key' = 'DataObjectId', 'Guid', etc, I expect the value of tempDataObj.DataObjectId, tempDataObj.Guid, etc to be set to the value returned from the database in 'reader[key]'.
Instead, it retains its initial, default value as set in the constructor, i.e. '-1'. This is true for both value and reference data types.
However, when I inspect tempDataObj.DataMembers["DataObjectId"], it has been set to the value returned from the database in 'reader[key]'.
Inspecting the Object Property and Dictionary Values
tempDataObj.DataMembers["DataObjectId"] should be referencing the tempDataObj.DataObjectId property, etc, but the Dictionary appears to be maintaining its own value rather than providing an object reference to the 'DataObjectId' property.
What's going on here? Thank you!
You're storing the data twice - once in a Dictionary, and a second time in a field. There's no need to store it twice. Just do this:
[DataContract]
public class DataObj
{
[Required]
[DataMember(Name = "dataObjectId")]
public Int64 DataObjectId
{
get => (long)DataMembers[nameof(DataObjectId)];
set => DataMembers[nameof(DataObjectId)] = value;
}
[Required]
[DataMember(Name = "guid")]
public Guid Guid
{
get => (Guid)DataMembers[nameof(Guid)];
set => DataMembers[nameof(Guid)] = value;
}
public Dictionary<string, object> DataMembers { get; } = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
public DataObj(Int64 dataObjectId, Guid guid)
{
DataObjectId = dataObjectId;
Guid = guid;
}
public Dictionary<string, object>.Enumerator Enumerator()
{
return DataMembers.GetEnumerator();
}
}
FYI, you can also look at using an ExpandoObject, which lets you access something in a way that looks like a class, but is really just a Dictionary. https://learn.microsoft.com/en-us/dotnet/api/system.dynamic.expandoobject?view=netframework-4.7.2
I have never used an ExpandoObject and I think the whole idea is as perverse as VBA's default of option explicit being off and On Error Resume Next. On the other hand, I don't deal with databases much.
I see two (main) routes to do what you want. In both cases you should implement a custom indexer.
In the indexer explicitly check the name given to it and get or set the field or property accordingly.
Use reflection, i.e. GetField() or GetProperty(), to get the field or property and GetValue() or SetValue() to get or set the values.
Below is a demonstration where ExposeByExplicitIndexer0 and its descendants use way 1 and ExposeByIndexerUsingReflection0 and its descendants use way 2.
public class ExposeByExplicitIndexer0
{
public int Int0 = 1;
public string String0 = "A";
public virtual object this[string name]
{
get
{
switch (name)
{
case "Int0":
return this.Int0;
case "String0":
return this.String0;
default:
throw new IndexOutOfRangeException();
}
}
set
{
switch (name)
{
case "Int0":
this.Int0 = (int)value;
break;
case "String0":
this.String0 = (string)value;
break;
default:
throw new IndexOutOfRangeException();
}
}
}
}
public class ExposeByExplicitIndexer1 : ExposeByExplicitIndexer0
{
protected Guid _Guid1 = Guid.Empty;
public Guid Guid1
{
get
{
return this._Guid1;
}
set
{
this._Guid1 = value;
}
}
public override object this[string name]
{
get
{
switch (name)
{
case "Guid1":
return this.Guid1;
default:
return base[name];
}
}
set
{
switch (name)
{
case "Guid1":
this.Guid1 = (Guid)value;
break;
default:
base[name] = value;
break;
}
}
}
}
public class ExposeByIndexerUsingReflection0
{
public object this[string name]
{
get
{
FieldInfo fieldInfo;
if ((fieldInfo = this.GetType().GetField(name)) != null)
{
return fieldInfo.GetValue(this);
}
PropertyInfo propertyInfo;
if ((propertyInfo = this.GetType().GetProperty(name)) != null)
{
return propertyInfo.GetValue(this);
}
throw new IndexOutOfRangeException();
}
set
{
FieldInfo fieldInfo;
if ((fieldInfo = this.GetType().GetField(name)) != null)
{
fieldInfo.SetValue(this, value);
return;
}
PropertyInfo propertyInfo;
if ((propertyInfo = this.GetType().GetProperty(name)) != null)
{
propertyInfo.SetValue(this, value);
return;
}
throw new IndexOutOfRangeException();
}
}
}
public class ExposeByIndexerUsingReflection1 : ExposeByIndexerUsingReflection0
{
public int Int1 = 1;
public string String1 = "A";
}
public class ExposeByIndexerUsingReflection2 : ExposeByIndexerUsingReflection1
{
protected Guid _Guid2 = Guid.Empty;
public Guid Guid2
{
get
{
return this._Guid2;
}
set
{
this._Guid2 = value;
}
}
}
public class Program
{
static void Main(string[] args)
{
Guid newGuid = Guid.NewGuid();
Console.WriteLine("Expose by explicit indexer:");
ExposeByExplicitIndexer1 exposeByExplicitIndexer1 = new ExposeByExplicitIndexer1();
exposeByExplicitIndexer1["Int0"] = 10;
exposeByExplicitIndexer1["String0"] = "AAA";
exposeByExplicitIndexer1["Guid1"] = newGuid;
Console.WriteLine("output via indexer:");
Console.WriteLine(exposeByExplicitIndexer1["Int0"]);
Console.WriteLine(exposeByExplicitIndexer1["String0"]);
Console.WriteLine(exposeByExplicitIndexer1["Guid1"]);
Console.WriteLine("output via fields or properties:");
Console.WriteLine(exposeByExplicitIndexer1.Int0);
Console.WriteLine(exposeByExplicitIndexer1.String0);
Console.WriteLine(exposeByExplicitIndexer1.Guid1);
Console.WriteLine("Expose by indexer using reflection:");
ExposeByIndexerUsingReflection2 exposeByIndexerUsingReflection2 = new ExposeByIndexerUsingReflection2();
exposeByIndexerUsingReflection2["Int1"] = 10;
exposeByIndexerUsingReflection2["String1"] = "AAA";
exposeByIndexerUsingReflection2["Guid2"] = newGuid;
Console.WriteLine("output via indexer:");
Console.WriteLine(exposeByIndexerUsingReflection2["Int1"]);
Console.WriteLine(exposeByIndexerUsingReflection2["String1"]);
Console.WriteLine(exposeByIndexerUsingReflection2["Guid2"]);
Console.WriteLine("output via fields or properties:");
Console.WriteLine(exposeByIndexerUsingReflection2.Int1);
Console.WriteLine(exposeByIndexerUsingReflection2.String1);
Console.WriteLine(exposeByIndexerUsingReflection2.Guid2);
Console.Read();
}
}
In way 1 every descendant that adds new fields or properties has to extend the indexer. That's more work in general but also offers an easy way of flexibility i.e. for adding some casts or expose some field or property via an alias, etc.
Way 2 needs less effort in the descendants. But being as flexible as in way 1 may become more difficult in turn. Maybe some mixed solution is also possible overriding the indexer in some descendant to inject special logic.

Creating a non-static version of compiler-based "dictionary" where keys are types

There is a very easy trick which creates a dictionary-like structure where keys are types.
The structure acts like a Dictionary<Type, T?> where keys are Type objects and values are instances of the corresponding types.
This wonderful structure is as fast as just a variable or array since the "lookup" is only done once by the compiler/JITter and the proper value reference is compiled into your program.
public static class MyDict<T> {
public static T Value { get; set; }
}
You can work with that structure like this:
MyDict<string>.Value = MyDict<int>.Value.ToString();
The problem is that this "dictionary" is global. The only way to create different dictionaries is to create different classes.
How can create a similar (fastest "lookup", no boxing) non-static structure? (Without code generation.)
Simply said: I want to have multiple Dictionary<Type, object>-like objects without lookup costs, casting and boxing.
Here's an approach that extends the method described in the question:
public class TypeDict
{
public T Get<T>()
{
return MyDict<T>.Values[this];
}
public void Set<T>(T value)
{
MyDict<T>.Values[this] = value;
}
private static class MyDict<T>
{
public static Dictionary<TypeDict, T> Values { get; private set; }
static MyDict()
{
Values = new Dictionary<TypeDict, T>();
}
}
}
Now we can use the TypeDict like this:
void X()
{
var a = new TypeDict();
var b = new TypeDict();
a.Set<int>(1);
a.Set<double>(3.14);
a.Set("Hello, world!");
//Note that type inference allows us to omit the type argument
b.Set(10);
b.Set(31.4);
b.Set("Hello, world, times ten!");
Console.WriteLine(a.Get<int>());
Console.WriteLine(a.Get<double>());
Console.WriteLine(a.Get<string>());
Console.WriteLine();
Console.WriteLine(b.Get<int>());
Console.WriteLine(b.Get<double>());
Console.WriteLine(b.Get<string>());
}
Ark-kun is using generics to essentially generate unique types at compile time. With a generic type, any static members are unique to that specific closed generic type. This way it's processed as fast as a standard static member lookup.
The above usage is equivalent to something like this:
public static class MyDict_String
{
public static string Value { get; set; }
}
public static class MyDict_Int32
{
public static int Value { get; set; }
}
MyDict_String.Value = MyDict_Int32.Value.ToString();
AFAIK, types are "static" (in that you can't define more than one that way) so I don't know of a way to cheat around this and maintain the same performance of a statically compiled member lookup.
Your best bet otherwise (I think) is to create a generic instance type that wraps its own dictionary that uses System.Type for its keys and System.Object for its values to which you have to perform boxing/casting when inserting/retrieving values.
EDIT: Here's a simple implementation wrapping a dictionary:
public class MyTypedDict
{
private Dictionary<Type, object> Values = new Dictionary<Type, object>();
public T Get<T>()
{
object untypedValue;
if (Values.TryGetValue(typeof(T), out untypedValue))
return (T)untypedValue;
return default(T);
}
public void Set<T>(T value)
{
Values[typeof(T)] = value;
}
}
Thinking about it more, it might be possible to achieve a more property-like syntax using an ExpandoObject (http://msdn.microsoft.com/en-us/library/system.dynamic.expandoobject.aspx) through some tomfoolery, but I feel like this would be pretty abusive and I can only assume terribly prone to runtime errors. (plus it would afford you nothing at compile time)
EDITx2: If you really want to have different sets of values, you could nest it within another generic type:
public static class ValueSets<T>
{
public static class MyDict<U>
{
public static U Value { get; set; }
}
}
With usage like:
ValueSets<int>.MyDict<string>.Value = "Hello ";
ValueSets<bool>.MyDict<string>.Value = "World!";
string helloworld = ValueSets<int>.MyDict<string>.Value + ValueSets<bool>.MyDict<string>.Value;
Console.WriteLine(helloworld);//Hello World!
But then the initial type int and bool in this case become "magical" and without meaning, plus you would need to provide a unique type per distinct set of values you'd like to use. Plus you could not pass it around and modify as an instance variable, rather it'd be statically accessible (so long as you have access to use the type T). So perhaps you could declare minimally visible types that are named with meaning and use those:
internal class MyFirstWords {}
internal class MySecondWords {}
ValueSets<MyFirstWords>.MyDict<string>.Value = "Hello ";
ValueSets<MySecondWords>.MyDict<string>.Value = "World!";
string helloworld = ValueSets<MyFirstWords>.MyDict<string>.Value + ValueSets<MySecondWords>.MyDict<string>.Value;
Console.WriteLine(helloworld);//Hello World!
Regardless, I think this is quite wacky and I wouldn't recommend it.
A more complicated version. Don't know if it's closer:
Define a generic dictionary:
public class MyDictionary<T>
{
Dictionary<string, T> dict;
public MyDictionary()
{
dict = new Dictionary<string, T>();
}
public T this[string name]
{
get
{
if (dict.ContainsKey(name))
return dict[name];
else
return default(T);//or throw
}
set
{
dict[name] = value;
}
}
}
Then a repository to store those dictionaries:
public class MyRepository
{
List<object> repo;
public MyRepository()
{
repo = new List<object>();
}
public void Add<T>(string name, T value)
{
if (!repo.OfType<MyDictionary<T>>().Any())
repo.Add(new MyDictionary<T>());
var dict = repo.OfType<MyDictionary<T>>().FirstOrDefault();
dict[name] = value;
}
public T GetValue<T>(string name)
{
if (!repo.OfType<MyDictionary<T>>().Any())
return default(T);//or throw
else
{
var dict = repo.OfType<MyDictionary<T>>().FirstOrDefault();
return dict[name];
}
}
}
And finally you may use this repository:
MyRepository repo = new MyRepository();
repo.Add("A", 1);
repo.Add("B", 1);
int i = repo.GetValue<int>("A") + repo.GetValue<int>("B");
In this example, there is MyDictionary<T> boxing to object is left.
From the other side, if your are working with some certain types you may not use thie repository class at all. But utilize separate dictionaties.
MyDictionary<int> intDict = new MyDictionary<int>();
intDict["A"] = 1;
intDict["B"] = 2;
int i = intDict["A"] + intDict["B"];
However it's the same as working with
Dictionary<string, int> intDict = new Dictionary<string, int>();
So the MyRepository class may be edited to use Dictionary<string, T> instead of MyDictionary<T>.
#Konstantin's answer made me remember that there is actually a very fast lookup method - array indexing. This crude PoC code shows a variant of the required structure.
public class TypeDictionary {
static int _maxId = 0;
int _id;
static class Store<T>{
internal static List<T> Values = new List<T>();
}
public TypeDictionary() {
_id = _maxId++;
}
public T GetValue<T>() {
return Store<T>.Values[_id];
}
public void SetValue<T>(T value) {
while(Store<T>.Values.Count < _id) {
Store<T>.Values.Add(default(T));
}
Store<T>.Values[_id] = value;
}
}
This code can be used as follows:
var dict1 = new TypeDictionary();
dict1.SetValue("my string");
string result = dict1.GetValue<string>();
The problem with this solution is it's memory usage caused by the repository being not sparse. This also makes first time value setting more expensive.
Try this:
public class MyDictionary
{
List<object> values;
public MyDictionary()
{
values = new List<object>();
}
public T GetValue<T>()
{
return values.OfType<T>().FirstOrDefault();
}
public bool Add<T>(T value)
{
if (values.OfType<T>().Any())
return false;
else
{
values.Add(value);
return true;
}
}
}
and use it:
var md = new MyDictionary();
md.Add("!!!");
string s = md.GetValue<string>();
This class may store up to one value of type T. But there could corner cases with derived classes and interfaces I guess. You may check, if it suits your need, and probably modify it as you need, if it's close to what you need in general.
What you are looking for is impossible in C#. The language does not support a container that could store multiple objects of different types yet provides a look up method that does not involve casting, boxing or unboxing. You could accomplish something like this with macros in C++, or via a language like javascript where the structure of types can be changed at run-time.
The usage case you are describing fits quite closely with the purpose for which ConditionalWeakTable<TKey,TValue> was added to .NET 4.0. For the purpose you describe, you would include such a table in a static generic class, and then for every class object that's supposed to contain a reference to an item of a particular type you would store into that type's table a reference to object that's supposed to contain the item along with either a reference to the item, or else a reference to a simple item-holder object (note that entries in ConditionalWeakTable will evaporate when an object ceases to exist, but are otherwise immutable, so if you want a mutable association you'll need to create an object to hold it).
Building on #phoog's example with #supercat's suggestion
public class TypeDict
{
public T Get<T>() where T : class
{
T value;
InnerDict<T>.Values.TryGetValue(this, out value);
return value;
}
public void Set<T>(T value) where T : class
{
var cwt = InnerDict<T>.Values;
// lock+remove+add https://github.com/dotnet/coreclr/issues/4545
lock (cwt)
{
cwt.Remove(this);
cwt.Add(this, value);
}
}
private static class InnerDict<T> where T : class
{
public static ConditionalWeakTable<TypeDict, T> Values { get; private set; }
static InnerDict()
{
Values = new ConditionalWeakTable<TypeDict, T>();
}
}
}

C#: Properties with different return types on derived classes

I tried to search for an answer for this problem but could not find much, most probably because I do not know how to look for it properly, so here it goes. All help is very much appreciated.
With the base class that looks like
abstract public class Property
{
private String name;
public Property(String propertyName)
{
name = propertyName;
}
public String Name
{
get { return name; }
}
abstract public override String ToString();
}
And derived classes that look like
public class StringProperty : Property
{
private String value; // different properties for different types
public StringProperty(String propertyName, String value) : base(propertyName)
{
this.value = value;
}
public String Value // different signature for different properties
{
get { return value; }
}
public override String ToString()
{
return base.Name + ": " + value;
}
}
During runtime, the function receives a collection of "Property" objects. What do I need to do to be able to obtain the "Value" of each? Do I need to have a big if statement to query the type of each "Property" object? If not, is there a more elegant solution?
I tried to define an abstract "Value" property to be overridden but since the return types are different, it did not work. I also tried playing with shadowing the "Value" property, but I could not make it work. The idea of using an COM-like Variant does not sound very appropriate, either.
Thanks a lot in advance.
EDIT:
I should have added details as to what I am trying to do. The properties are displayed in a Winforms app. Different "TextBox"es represent different properties and are filtered for proper input (depending on the type). The updated values are read back and stored. The container object will be serialized into JSON and deserialized on an Android and iPhone client and eventually these values will be passed into a layer running native C++ code doing OpenGL stuff. I don't know in advance the kind of all needed properties so as the middleman, I wanted to make my code as robust as possible while being able to feed the OpenGL engine.
You can use a generic class:
public class AnyProperty<T> : Property
{
private T value;
// ... etc
I'd really recommend making the base class an Interface by now:
public interface IProperty
{
public String Name { get; }
}
public class Property<T> : IProperty
{
public Property(String name, T value)
{
Name = name;
Value = value;
}
public String Name { get; private set; }
public T Value { get; private set; }
public override String ToString()
{
return string.Format("{0}: {1}", Name, Value)
}
}
Here is sample usage:
var intProp = new Property<int> ("age", 32);
var strProp = new Property<string> ("name", "Earl");
var enumProp = new Property<ColorEnum> ("eye color", ColorEnum.Magenta);
To make the construction even simpler, you could have a factory method:
public static Property<T> MakeProperty(string name, T value)
{
return new Property<T>(name,value);
}
var intProp = MakeProperty("age", 32);
var strProp = MakeProperty("name", "Earl");
var enumProp = MakeProperty("eye color", ColorEnum.Magenta);
Not necessarily recommended, and a bit OT:
You could make it even funkier with an extension method:
public static Property<T> AsProp<T>(this T value, string name)
{
return new Property<T>(name,value);
}
var intProp = 32.AsProp("age");
var strProp = "Earl".AsProp("name");
var enumProp = ColorEnum.Magenta.AsProp("eye color");
You would have to simply use the object type. What are you trying to accomplish? The problem here isn't the structure of your classes, it's the function that receives the collection of Property objects. It's impossible to even cast something to an unknown type, since you don't know what type of variable it needs to be stored in.
So basically, your Property.Value property needs to be of type object. In your method that uses the Property objects, you need to do something with them, and what you're doing will decide how it should be structured. Are you printing values out? Have a *Value class inheriting from an abstract PropertyValue class and override ToString() to return an appropriate string represention.
I made a few changes to your sample code and got this result...
abstract public class Property
{
private readonly String _name;
public Property(String propertyName)
{
_name = propertyName;
}
public String Name
{
get { return _name; }
}
abstract public override String ToString();
}
public class StringProperty : Property
{
private readonly dynamic _value; // different properties for different types
public StringProperty(String propertyName, dynamic value)
: base(propertyName)
{
this._value = value;
}
public dynamic Value // different signature for different properties
{
get { return _value; }
}
public override String ToString()
{
return base.Name + ": " + _value;
}
}
static void Main(string[] args)
{
StringProperty sp = new StringProperty("A double", 3.444);
StringProperty sp2 = new StringProperty("My int", 4343);
StringProperty sp3 = new StringProperty("My directory", new DirectoryInfo("Some directory"));
StringProperty sp4 = new StringProperty("My null", null);
Console.WriteLine(sp);
Console.WriteLine(sp2);
Console.WriteLine(sp3);
Console.WriteLine(sp4);
}
}
Values are properly printed to the console in the expected way.
It would require a bit of a rethink, but have you considered using the dynamic type (introduced in .net4)
Doesn't really solve your problem, but sidespteps it.
Your properties can bascically just be a
Dictionary<String, dynamic>
, the gotcha is they don't get evaluated until runtime, so you get no compiler support for typing.
so given you want
int SomeValue = MyProperties[SomePropertyName] + 10;
So if
MyProperties[SomePropertyName] = 10; // all is good
if its 76.52 or Fred, the addition will throw an exception at the point it executes.
Code is much simpler and cleaner, no extra casting and the amount of scaffolding required is minimal, BUT, you'll need to unit test code that uses the dictionary extensively and religiously.

Using LINQ to create a List<T> where T : someClass<U>

This is related to a prior question of mine C# Generic List conversion to Class implementing List<T>
I have the following code:
public abstract class DataField
{
public string Name { get; set; }
}
public class DataField<T> : DataField
{
public T Value { get; set; }
}
public static List<DataField> ConvertXML(XMLDocument data) {
result = (from d in XDocument.Parse(data.OuterXML).Root.Decendendants()
select new DataField<string>
{
Name = d.Name.ToString(),
Value = d.Value
}).Cast<DataField>().ToList();
return result;
}
This works however I would like to be able to modify the select portion of the LINQ query to be something like this:
select new DataField<[type defined in attribute of XML Element]>
{
Name = d.Name.ToString(),
Value = d.Value
}
Is this just a poor approach? is it possible? Any suggestions?
Here is a working solution: (You must specify fully qualified type names for your Type attribute otherwise you have to configure a mapping somehow...)
I used the dynamic keyword, you can use reflection to set the value instead if you do not have C# 4...
public static void Test()
{
string xmlData = "<root><Name1 Type=\"System.String\">Value1</Name1><Name2 Type=\"System.Int32\">324</Name2></root>";
List<DataField> dataFieldList = DataField.ConvertXML(xmlData);
Debug.Assert(dataFieldList.Count == 2);
Debug.Assert(dataFieldList[0].GetType() == typeof(DataField<string>));
Debug.Assert(dataFieldList[1].GetType() == typeof(DataField<int>));
}
public abstract class DataField
{
public string Name { get; set; }
/// <summary>
/// Instanciate a generic DataField<T> given an XElement
/// </summary>
public static DataField CreateDataField(XElement element)
{
//Determine the type of element we deal with
string elementTypeName = element.Attribute("Type").Value;
Type elementType = Type.GetType(elementTypeName);
//Instanciate a new Generic element of type: DataField<T>
dynamic dataField = Activator.CreateInstance(typeof(DataField<>).MakeGenericType(elementType));
dataField.Name = element.Name.ToString();
//Convert the inner value to the target element type
dynamic value = Convert.ChangeType(element.Value, elementType);
//Set the value into DataField
dataField.Value = value;
return dataField;
}
/// <summary>
/// Take all the descendant of the root node and creates a DataField for each
/// </summary>
public static List<DataField> ConvertXML(string xmlData)
{
var result = (from d in XDocument.Parse(xmlData).Root.DescendantNodes().OfType<XElement>()
select CreateDataField(d)).ToList();
return result;
}
}
public class DataField<T> : DataField
{
public T Value { get; set; }
}
You cannot do this easily in C#. The generic type argument has to specified at compile time. You can use reflection to do otherwise
int X = 1;
Type listype = typeof(List<>);
Type constructed = listype.MakeGenericType( X.GetType() );
object runtimeList = Activator.CreateInstance(constructed);
Here we have just created a List<int>. You can do it with your type
Different instances of a generic class are actually different classes.
I.e. DataField<string> and DataField<int> are not the same class at all(!)
This means, that you can not define the generic parameter during run-time, as it has to be determined during compile-time.
I would say this is a poor approach. In reality, even after you parse your XML file, you're not going to know what types of "DataFields" you have. You might as well just parse them as objects.
However, if you know that you're only ever going to have x number of types, you can do like so:
var Dictionary<string, Func<string, string, DataField>> myFactoryMaps =
{
{"Type1", (name, value) => { return new DataField<Type1>(name, Type1.Parse(value); } },
{"Type2", (name, value) => { return new DataField<Type2>(name, Type2.Parse(value); } },
};
Termit's answer is certainly excellent. Here is a little variant.
public abstract class DataField
{
public string Name { get; set; }
}
public class DataField<T> : DataField
{
public T Value { get; set; }
public Type GenericType { get { return this.Value.GetType(); } }
}
static Func<XElement , DataField> dfSelector = new Func<XElement , DataField>( e =>
{
string strType = e.Attribute( "type" ).Value;
//if you dont have an attribute type, you could call an extension method to figure out the type (with regex patterns)
//that would only work for struct
Type type = Type.GetType( strType );
dynamic df = Activator.CreateInstance( typeof( DataField<>).MakeGenericType( type ) );
df.Name = e.Attribute( "name" ).Value;
dynamic value = Convert.ChangeType( e.Value , type );
df.Value = value;
return df;
} );
public static List<DataField> ConvertXML( string xmlstring )
{
var result = XDocument.Parse( xmlstring )
.Root.Descendants("object")
.Select( dfSelector )
.ToList();
return result;
}
static void Main( string[] args )
{
string xml = "<root><object name=\"im1\" type=\"System.String\">HelloWorld!</object><object name=\"im2\" type=\"System.Int32\">324</object></root>";
List<DataField> dfs = ConvertXML( xml );
}
you can create generic type by reflection
var instance = Activator.CreateInstance( typeof(DataField)
.MakeGenericType(Type.GetType(typeNameFromAttribute) );
// and here set properties also by reflection
#Termit and #Burnzy put forward good solutions involving factory methods.
The problem with that is that you're loading up your parsing routine with a bunch of extra logic (more testing, more errors) for dubious returns.
Another way to do it would be to use a simplified string-based DataField with typed read methods - the top answer for this question.
An implementation of a typed-value method that would be nice but only works for value types (which does not include strings but does include DateTimes):
public T? TypedValue<T>()
where T : struct
{
try { return (T?) Convert.ChangeType(this.Value, typeof(T)); }
catch { return null; }
}
I'm assuming that you're wanting to use the type information to do things like dynamically assigning user-controls to the field, validation rules, correct SQL types for persistence etc.
I've done a lot of this sort of thing with approaches that seem a bit like yours.
At the end of the day you should seperate your metadata from your code - #Burnzy's answer chooses the code based on the metadata (a "type" attribute of the DataField element) and is a very simple example of this.
If you're dealing with XML, XSDs are a very useful and extensible form of metadata.
As far as what you store each field's data in - use strings because:
they are nullable
they can store partial values
they can store invalid values (makes telling the user to sort their act out more transparent)
they can store lists
special cases won't invade unrelated code because there aren't any
learn regular expressions, validate, be happy
you can convert them to stronger types really easily
I found it very rewarding to develop little frameworks like this - it is a learning experience and you'll come out understanding a lot more about UX and the reality of modelling from it.
There are four groups of test cases that I would advise you to tackle first:
Dates, Times, Timestamps (what I call DateTime), Periods (Timespan)
in particular, make sure you test having a different server locality from the client's.
lists - multi-select foreign keys etc
null values
invalid input - this generally involves retaining the original value
Using strings simplifies all this greatly because it allows you to clearly demarcate responsibilities within your framework. Think about doing fields containing lists in your generic model - it gets hairy rather quickly and it is easy to end up with a special case for lists in pretty much every method. With strings, the buck stops there.
Finally, if you want a solid implementation of this sort of stuff without having to do anything much, consider DataSets - old school I know - they do all sorts of wonderful things you wouldn't expect but you do have to RTFM.
The main downfall of that idea would be that it isn't compatible with WPF data binding - though my experience has been that reality isn't compatible with WPF data binding.
I hope I interpreted your intentions correctly - good luck either way :)
Unfortunately, there no inheritance relation between C<T> and C<string> for instance.
However, you can inherit from a common non-generic class and in addition to this implement a generic interface.
Here I use explicit interface implementation in order to be able to declare a Value property typed as object, as well as a more specifically typed Value property.
The Values are read-only and can only be assigned through a typed constructor parameter. My construction is not perfect, but type safe and doesn't use reflection.
public interface IValue<T>
{
T Value { get; }
}
public abstract class DataField
{
public DataField(string name, object value)
{
Name = name;
Value = value;
}
public string Name { get; private set; }
public object Value { get; private set; }
}
public class StringDataField : DataField, IValue<string>
{
public StringDataField(string name, string value)
: base(name, value)
{
}
string IValue<string>.Value
{
get { return (string)Value; }
}
}
public class IntDataField : DataField, IValue<int>
{
public IntDataField(string name, int value)
: base(name, value)
{
}
int IValue<int>.Value
{
get { return (int)Value; }
}
}
The list can then be declared with the abstract base class DataField as generic parameter:
var list = new List<DataField>();
switch (fieldType) {
case "string":
list.Add(new StringDataField("Item", "Apple"));
break;
case "int":
list.Add(new IntDataField("Count", 12));
break;
}
Access the strongly typed field through the interface:
public void ProcessDataField(DataField field)
{
var stringField = field as IValue<string>;
if (stringField != null) {
string s = stringField.Value;
}
}
While the other questions mostly proposed an elegant solution to convert your XML elements to a generic class instance, I'm going to deal with the consequences of taking the approach to model the DataField class as a generic like DataField<[type defined in attribute of XML Element]>.
After selecting your DataField instance into the list you want to use these fields. Her polymorphism comes into play! You want to iterate your DataFields an treat them in a uniform way. Solutions that use generics often end up in a weird switch/if orgy since there is no easy way to associate behavior based on the generic type in c#.
You might have seen code like this (I'm trying to calculate the sum of all numeric DataField instances)
var list = new List<DataField>()
{
new DataField<int>() {Name = "int", Value = 2},
new DataField<string>() {Name = "string", Value = "stringValue"},
new DataField<float>() {Name = "string", Value = 2f},
};
var sum = 0.0;
foreach (var dataField in list)
{
if (dataField.GetType().IsGenericType)
{
if (dataField.GetType().GetGenericArguments()[0] == typeof(int))
{
sum += ((DataField<int>) dataField).Value;
}
else if (dataField.GetType().GetGenericArguments()[0] == typeof(float))
{
sum += ((DataField<float>)dataField).Value;
}
// ..
}
}
This code is a complete mess!
Let's go try the polymorphic implementation with your generic type DataField and add some method Sum to it that accepts the old some and returns the (possibly modified) new sum:
public class DataField<T> : DataField
{
public T Value { get; set; }
public override double Sum(double sum)
{
if (typeof(T) == typeof(int))
{
return sum + (int)Value; // Cannot really cast here!
}
else if (typeof(T) == typeof(float))
{
return sum + (float)Value; // Cannot really cast here!
}
// ...
return sum;
}
}
You can imagine that your iteration code gets a lot clearer now but you still have this weird switch/if statement in you code. And here comes the point: Generics do not help you here it's the wrong tool at the wrong place. Generics are designed in C# for giving you compile time type safety to avoid potential unsafe cast operations. They additionally add to code readability but that's not the case here :)
Let's take a look at the polymorphic solution:
public abstract class DataField
{
public string Name { get; set; }
public object Value { get; set; }
public abstract double Sum(double sum);
}
public class IntDataField : DataField
{
public override double Sum(double sum)
{
return (int)Value + sum;
}
}
public class FloatDataField : DataField
{
public override double Sum(double sum)
{
return (float)Value + sum;
}
}
I guess you will not need too much fantasy to imagine how much adds to your code's readability/quality.
The last point is how to create instances of these classes. Simply by using some convention TypeName + "DataField" and Activator:
Activator.CreateInstance("assemblyName", typeName);
Short Version:
Generics is not the appropriate approach for your problem because it does not add value to the handling of DataField instances. With the polymorphic approach you can work easily with the instances of DataField!
It's not impossible as you can do this with reflection. But this isn't what generics were designed for and isn't how it should be done. If you're going to use reflection to make the generic type, you may as well not use a generic type at all and just use the following class:
public class DataField
{
public string Name { get; set; }
public object Value { get; set; }
}
You'll need to insert the logic for determining the data type from your XML and add all the types you need to use but this should work:
result = (from d in XDocument.Parse(data.OuterXML).Root.Descendants()
let isString = true //Replace true with your logic to determine if it is a string.
let isInt = false //Replace false with your logic to determine if it is an integer.
let stringValue = isString ? (DataField)new DataField<string>
{
Name = d.Name.ToString(),
Value = d.Value
} : null
let intValue = isInt ? (DataField)new DataField<int>
{
Name = d.Name.ToString(),
Value = Int32.Parse(d.Value)
} : null
select stringValue ?? intValue).ToList();

C# casting and inheritance

I have an object that I pass around a lot.
I need to add a piece of data to it and cannot modify the base class
So I have
static OriginalThing GetNewThing()
{
return new OriginalThing();
}
Now i want to add my piece of data
class EnhancedThing : OriginalThing
{
string name;
static EnhancedThing GetNewThing(string name)
{
EnhancedThing ething = new OriginalThing(); <---doesnt work even if i cast it
ething.Name = name;
}
}
How do I do this?
You can't assign an OriginalThing to a NewThing because it simply is not a NewThing. The other way around works fine because a NewThing is capable of everything an OriginalThing is, but the reverse is not true.
Just create an instance of EnhancedThing, assign the name, and return it. You can treat the EnhancedThing as if it were an OriginalThing because it is an OriginalThing.
class EnhancedThing : OriginalThing
{
public string Name { get; private set; }
static EnhancedThing GetNewThing(string name)
{
EnhanedThing thing = new EnhancedThing();
thing.Name = name;
return thing;
}
}
// ...
OriginalThing foo = EnhancedThing.GetNewThing( "someName" );
Also realize that doesn't buy you much as name is currently a private member variable (in your example), and you won't be able to access any additional functionality of NewThing objects unless you treat them as NewThings (as opposed to OriginalThings, but you can pass them around as OriginalThings if needed)
You need to do this:
EnhancedThing ething = new EnhancedThing();
This is because an OriginalThing is not an EnhancedThing, but an EnhancedThing is an OriginalThing.
One thing you could do is have a constructor for EnhancedThing that takes an OriginalThing and copies over the members that apply.
class EnhancedThing : OriginalThing
{
public EnhancedThing()
{
// default constructor
}
public EnhancedThing( OriginalThing src )
{
// copy over the significant items
}
}
If the other class is sealed you can use encapsulation in your new class, and then modify/extend the API. You can then define a implicit cast from one object to the other and use these types interchangeably without casting.
Whether this is suitable in your case comes down to what you intend to do, and what you are trying to achieve but it's a valuable technique. It's more useful for hiding some/all members of the original and redefining an API.
// no need to cast
EnhancedThing thing = new OriginalThing();
var result = thing.NewMethod();
// again no need to cast, treat as original when passing around
OriginalThing original = thing;
public class EnhancedThing
{
private readonly OriginalThing originalThing;
public static implicit operator OriginalThing(EnhancedThing enhancedThing)
{
return enhancedThing.originalThing;
}
public static implicit operator EnhancedThing(OriginalThing originalThing)
{
return new EnhancedThing(originalThing);
}
private EnhancedThing(OriginalThing originalThing)
{
this.originalThing = originalThing;
}
public string OriginalMethod()
{
return originalThing.OriginalMethod();
}
public string NewMethod()
{
var value = originalThing.OriginalMethod();
// extra processing ...
return value;
}
}
This technique is used extensively in Sitecore to provide different data type Models from a common base implementation. One caveat if you intend to add a new data field, it will be lost on upcast.

Categories