I was wondering if it's possible to run the following code but without the unboxing line:-
t.Value = (T)x;
Or maybe if there is another way to do this kind of operation?
Here is the full code:-
public class ValueWrapper<T>
{
public T Value { get; set; }
public bool HasValue { get; set; }
public ValueWrapper()
{
HasValue = false;
}
}
class Program
{
static void Main(string[] args)
{
Dictionary<string, object> myDictionary = new Dictionary<string, object>();
myDictionary.Add("key1", 6);
myDictionary.Add("key2", "a string");
var x2 = GetValue<int>(myDictionary, "key1");
if (x2.HasValue)
Console.WriteLine("'{0}' = {1}", "key1", x2.Value);
else
Console.WriteLine("No value found");
Console.ReadLine();
}
static ValueWrapper<T> GetValue<T>(IDictionary<string, object> dictionary, string key)
{
ValueWrapper<T> t = new ValueWrapper<T>();
object x = null;
if (dictionary.TryGetValue(key, out x))
{
if (x.GetType() == typeof(T))
{
t.Value = (T)x;
t.HasValue = true;
}
}
return t;
}
}
Thanks in advance!!
Richard.
A few comments:
t.Value = (T)x;
The cast is necessary. This is because t.Value is of type T and x is of type object. The strongly-typed nature of C# requires that you tell the compiler "look, I know this might unsafe but can you just try to do it for me anyway, either by conversion or unboxing or whatever? Thanks!"
2.
object x = null;
if (dictionary.TryGetValue(key, out x)) {
if (x.GetType() == typeof(T)) {
t.Value = (T)x;
t.HasValue = true;
}
}
return t;
What if x is an instance of a class that derives from T? Or if x is an instance of a class that implements an interface and T is that interface? Right now, you will return a instance of ValueWrapper<T> that indicates there was no object in the dictionary with the key key. I would argue this is very counterintuitive to what most people expect.
Additionally, if you're not going to throw up when dictionary does not contain a value matching the key key, I think you should rename your method to TryGetValue, accept a out parameter of type ValueWrapper<T>, and return a bool indicating success/failure.
3.
Responding to your comment, here's one solution.
public interface IValueWrapper {
object Value { get; set; }
bool HasValue { get; set; }
}
public class ValueWrapper<T> : IValueWrapper {
public T Value { get; set; }
object IValueWrapper.Value {
get { return Value; }
set { this.Value = (T)value; }
}
public bool HasValue { get; set; }
public ValueWrapper() {
this.HasValue = false;
}
public ValueWrapper(T value) {
this.Value = value;
this.HasValue = value != null;
}
}
public static class DictionaryExtensions {
public static void Add<T>(
this IDictionary<string, IValueWrapper> dictionary,
string key,
T value
) {
ValueWrapper<T> valueWrapper = new ValueWrapper<T>(value);
dictionary.Add(key, valueWrapper);
}
public static bool TryGetWrappedValue<T>(
IDictionary<string, IValueWrapper> dictionary,
string key,
out ValueWrapper<T> value
) {
IValueWrapper valueWrapper;
if (dictionary.TryGetValue(key, out valueWrapper)) {
value = (ValueWrapper<T>)valueWrapper;
return true;
}
else {
value = null;
return false;
}
}
}
Usage:
var dict = new Dictionary<string, IValueWrapper>();
dict.Add("hello", 5);
ValueWrapper<int> value;
dict.TryGetWrappedValue("hello", out value);
You'll have to add parameter checking etc.
Related
Is there a way to do something like "string.Compare()", but for generic types. I want to check the range of some property values.
Here is what I am doing as a work around, but it is pretty ugly:
public class SomeClass<T>
{
public T MinValue { get; set; }
public T MaxValue { get; set; }
private T _value;
public T Value
{
get { return _value; }
set
{
_value = value;
// Restrict range to Min/Max
if (Comparer<T>.Default.Compare(MaxValue, value) < 0)
_value = MaxValue;
if (Comparer<T>.Default.Compare(MinValue, value) > 0)
_value = MinValue;
}
}
}
This code demonstates what I was talking about in my comment. Of course you will have to modify it to fit with your precise paradigm, of using it in a comparer, but this should be clear enough...
public class Program
{
public static void Main(string[] args)
{
System.Console.WriteLine("Hello World!");
TestObject testObject = new TestObject(15);
TestObject testObject2 = new TestObject(9);
TestObject testObject3 = new TestObject(31);
System.Console.ReadLine();
}
}
public class TestObject
{
[ValidateIntMin(Min = 10)]
[ValidateIntMax(30)]
public int SomeInt { get; set; }
public TestObject(int value)
{
SomeInt = value;
if (!Validator.Validate(this))
{
System.Console.WriteLine("Invalid Value assigned: " + value);
}
else
{
System.Console.WriteLine("" + SomeInt + " was a valid value");
}
}
}
public class ValidateIntMax : Attribute
{
public int Max { get; set; }
public ValidateIntMax(int MaxValue)
{
Max = MaxValue;
}
}
public class ValidateIntMin: Attribute
{
public int Min { get; set; }
}
public static class Validator
{
public static bool Validate<T>(T input) {
var attrType = typeof(T);
var properties = attrType.GetProperties();
bool isValid = true;
foreach (PropertyInfo propertyInfo in properties)
{
var customerMaxValueInt = propertyInfo.GetCustomAttributes(typeof(ValidateIntMax), false).FirstOrDefault();
var customerMinValueInt = propertyInfo.GetCustomAttributes(typeof(ValidateIntMin), false).FirstOrDefault();
if (customerMaxValueInt != null)
{
if (propertyInfo.PropertyType == typeof(int))
{
var currentPropertyInfoBeingTested = (int)propertyInfo.GetValue(input);
var currentMaxValueToVerifyAgainst = ((ValidateIntMax)customerMaxValueInt).Max;
if (currentPropertyInfoBeingTested > currentMaxValueToVerifyAgainst)
{
isValid = false;
}
}
}
if (customerMinValueInt != null)
{
if (propertyInfo.PropertyType == typeof(int))
{
var currentPropertyInfoBeingTested = (int)propertyInfo.GetValue(input);
var currentMaxValueToVerifyAgainst = ((ValidateIntMin)customerMinValueInt).Min;
if (currentPropertyInfoBeingTested < currentMaxValueToVerifyAgainst)
{
isValid = false;
}
}
}
}
return isValid;
}
}
Should give the output:
Hello World!
15 was a valid value
Invalid Value assigned: 9
Invalid Value assigned: 31
Of course you can add validation for different types, etc.
This is just to show a totally custom way of setting up your attributes.
I recommend you read up on the ValidationAttribute however, to see if you can't use the implemented functionality.
But this is just a PoC piece.
I have the following classes domain and Dto classes:
public class Profile
{
public string Name { get; set; }
public string SchoolGrade { get; set; }
}
public class ProfileDTO
{
public string Name { get; set; }
public SchoolGradeDTO SchoolGrade { get; set; }
}
public enum SchoolGradeDTO
{
[Display(Name = "Level One"]
LevelOne,
[Display(Name = "Level Two"]
LevelTwo,
}
I used the following method:
Mapper.CreateMap<Profile, ProfileDTO>()
.ForMember(d => d.SchoolGrade , op => op.MapFrom(o => o.SchoolGrade))
Afterwards, I get the following error:
Requested value 'Level Two' was not found.
How do I map it correctly?
Since you're mapping from the display name and not the enum name you'll need to build a custom mapping function to scan the attributes to find the enum with that display name. You can use ResolveUsing instead of MapFrom to use a custom mapping function:
Mapper.CreateMap<Profile, ProfileDTO>()
.ForMember(d => d.SchoolGrade,
op => op.ResolveUsing(o=> MapGrade(o.SchoolGrade)));
public static SchoolGradeDTO MapGrade(string grade)
{
//TODO: function to map a string to a SchoolGradeDTO
}
You could cache the names in a static dictionary so you don't use reflection every time.
A few methods of doing that can be found here.
Expanding on D Stanley's answer from above in a little more detail, and modified the EnumHelper class from this other discussion to focus on your specific situation as this question really spans two areas, AutoMapper and correctly obtaining an Enum's value from a string.
Enhancing D Stanley's original answer:
public static class QuestionAutoMapperConfig
{
public static void ConfigureAutoMapper()
{
Mapper.CreateMap<Profile, ProfileDTO>()
.ForMember(d => d.SchoolGrade,
op => op.ResolveUsing(o => MapGrade(o.SchoolGrade)));
}
public static SchoolGradeDTO MapGrade(string grade)
{
//TODO: function to map a string to a SchoolGradeDTO
return EnumHelper<SchoolGradeDTO>.Parse(grade);
}
}
I have adjusted the EnumHelper from the mentioned example to quickly show an option where by you could modify the Parse method to first try the standard Enum.Parse(), and failing that to try to do a more detailed comparison of the Enum type by creating a dictionary of the values based either on the enum value name, or it's Display attribute text (if used).
public static class EnumHelper<T>
{
public static IDictionary<string, T> GetValues(bool ignoreCase)
{
var enumValues = new Dictionary<string, T>();
foreach (FieldInfo fi in typeof(T).GetFields(BindingFlags.Static | BindingFlags.Public))
{
string key = fi.Name;
var display = fi.GetCustomAttributes(typeof(DisplayAttribute), false) as DisplayAttribute[];
if (display != null)
key = (display.Length > 0) ? display[0].Name : fi.Name;
if (ignoreCase)
key = key.ToLower();
if (!enumValues.ContainsKey(key))
enumValues[key] = (T)fi.GetRawConstantValue();
}
return enumValues;
}
public static T Parse(string value)
{
T result;
try
{
result = (T)Enum.Parse(typeof(T), value, true);
}
catch (Exception)
{
result = ParseDisplayValues(value, true);
}
return result;
}
private static T ParseDisplayValues(string value, bool ignoreCase)
{
IDictionary<string, T> values = GetValues(ignoreCase);
string key = null;
if (ignoreCase)
key = value.ToLower();
else
key = value;
if (values.ContainsKey(key))
return values[key];
throw new ArgumentException(value);
}
}
in mapping configuration
{
CreateMap<string, CUSTOM_ENUM>().ConvertUsing<StringToEnumConverter<CUSTOM_ENUM>>();
}
converters
public class StringToEnumConverter<T> : ITypeConverter<string, T>, ITypeConverter<string, T?> where T : struct
{
public T Convert(ResolutionContext context)
{
T t;
if (Enum.TryParse(source, out t))
{
return t;
}
var source = (string)context.SourceValue;
if (StringToEnumBase<T>.HasDisplayAttribute())
{
var result = StringToEnumBase<T>.Parse(source);
return result;
}
throw new ConverterException();
}
T? ITypeConverter<string, T?>.Convert(ResolutionContext context)
{
var source = (string)context.SourceValue;
if (source == null) return null;
return Convert(context);
}
}
public static class StringToEnumBase<T> where T:struct
{
public static T Parse(string str)
{
var type = typeof (T);
var enumMembers = type.GetMembers(BindingFlags.Public | BindingFlags.Static);
var enumMembersCollection = enumMembers
.Select(enumMember => new
{
enumMember,
attributes = enumMember.GetCustomAttributes(typeof(DisplayAttribute), false)
})
.Select(t1 => new
{
t1, value = ((DisplayAttribute) t1.attributes[0]).Name
})
.Select(t1 => new Tuple<string, string>(t1.value, t1.t1.enumMember.Name))
.ToList();
var currentMember = enumMembersCollection.FirstOrDefault(item => item.Item1 == str);
if (currentMember == null) throw new ConverterException();
T t;
if (Enum.TryParse(currentMember.Item2, out t))
{
return t;
}
throw new ConverterException();
}
public static bool HasDisplayAttribute()
{
var type = typeof (T);
var attributes = type.GetCustomAttributes(typeof(DisplayAttribute), false);
return attributes.Length > 0;
}
}
Normally when I want for example to find the first or default item of a List I use this way:
myList.SingleOrDefault(x=>x.MyPropery01 == "myCondition");
However, I would like to know if it is possible, for example by reflection, if I set the the property MyProperty dynamically, something like:
myList.SingleOrDefault(x=>x.GetType().GetProperty("MyProperty01") == "myCondition");
Because sometimes I need to search for MyProperty01, sometimes for MyProperty02, MyProperty03, etc..
EDIT: in visual studio I get this error:
"Operator '==' can't be applied to operands of type System.reflection.PropertyInfo and string".
Yeah you can do that. You were pretty close, here is a demo you can drop in linqpad. Note that the important part is
Single(l => l.GetType().GetProperty(prop).GetValue(l).ToString() == "Condition")
void Main()
{
var myList = Enumerable.Range(0,10).Select(i => new Xmas(i,"name"+i)).ToList();
string prop = "name";
Console.WriteLine(myList.Single(l => l.GetType().GetProperty(prop).GetValue(l).ToString() == "name6").name);
}
public class Xmas
{
public int id { get; set; }
public string name { get; set; }
public Xmas( int id, string name )
{
this.id = id;
this.name = name;
}
}
Working example:
public class Apple
{
public string Color { get; set; }
}
public List<Apple> ApplesList {get;set;}
public void Process()
{
PropertyInfo pi = typeof(Apple).GetProperty("Color");
ApplesList = ApplesList.Where(r => (string)pi.GetValue(r) == "Red").ToList();
}
You could also write an Extension method, that allow to get the property on every object, returning null when it doesn't exist, or doesn't have a GetMethod. You could keep a Cache if you want
public static class ObjectExtension
{
static IDictionary<KeyValuePair<Type, string>, PropertyInfo> propertyCache = new Dictionary<KeyValuePair<Type, string>, PropertyInfo>();
public static object GetProperty(this object source, string propertyName, bool useCache = true)
{
if (source == null)
{
return null;
}
var sourceType = source.GetType();
KeyValuePair<Type, string> kvp = new KeyValuePair<Type, string>(sourceType, propertyName);
PropertyInfo property = null;
if (!useCache || !propertyCache.ContainsKey(kvp))
{
property = sourceType.GetProperty(propertyName);
if (property == null)
{
return null;
}
var get = property.GetGetMethod();
if (get == null)
{
return null;
}
if (useCache)
{
propertyCache.Add(kvp, property);
}
}
else
{
property = propertyCache[kvp];
}
return property.GetValue(source, null);
}
public static T GetProperty<T>(this object source, string propertyName)
{
object value = GetProperty((object)source, propertyName);
if (value == null)
{
return default(T);
}
return (T)value;
}
}
A small test class could then be:
public class Item
{
public string MyProperty { get; set; }
public string MyProperty3 { get; set; }
public string MyProperty2 { protected get; set; }
public Item()
{
MyProperty = "Test propery";
MyProperty3 = "Test property 3";
MyProperty2 = "Yoohoo";
}
}
With a main class for testing
class Program
{
static void Main(string[] args)
{
Item item = new Item();
for (int x = 0; x < 4; x++)
{
string key = "MyProperty" + (x > 0 ? x.ToString() : "");
string value = item.GetProperty<string>(key);
Console.WriteLine("Getting {0} = {1}", key, value);
}
Console.ReadLine();
}
}
which gives the expectable output of:
Getting MyProperty = Test propery
Getting MyProperty1 =
Getting MyProperty2 =
Getting MyProperty3 = Test property 3
I have a problem trying to properly serialize/deserialize object with inner dictionary. Dictionary has some custom type PairIntKey as a key.
Code is the following:
public class MyClassWithDictionary
{
private Dictionary<PairIntKey, List<int>> _myDictionary = new Dictionary<PairIntKey, List<int>>();
public Dictionary<PairIntKey, List<int>> MyDictionary
{
set { _myDictionary = value; }
}
public void AddElementsToMyDictionary(PairIntKey key, List<int> value)
{
_myDictionary.Add(key, value);
}
}
public class PairIntKey : IEquatable<PairIntKey>
{
private int _value1;
private int _value2;
public int Value1
{
get { return _value1; }
}
public int Value2
{
get { return _value2; }
}
public PairIntKey(int value1, int value2)
{
_value1 = value1;
_value2 = value2;
}
public override int GetHashCode()
{
return _value1 + 29 * _value2;
}
public bool Equals(PairIntKey other)
{
if (this == other) return true;
if (other == null) return false;
if (_value1 != other._value1) return false;
if (_value2 != other._value2) return false;
return true;
}
public override string ToString()
{
return String.Format("({0},{1})", _value1, _value2);
}
}
I serialize like this
public void SerializeAndDeserializeMyObject()
{
var myObject = new MyClassWithDictionary();
myObject.AddElementsToMyDictionary(new PairIntKey(1, 1), new List<int> {5});
var contractResolver = new DefaultContractResolver();
contractResolver.DefaultMembersSearchFlags |= BindingFlags.NonPublic;
string serializedItem = JsonConvert.SerializeObject(myObject,
Formatting.Indented,
new JsonSerializerSettings()
{
ContractResolver = contractResolver,
});
var deserializedItem = JsonConvert.DeserializeObject(serializedItem, typeof(MyClassWithDictionary), new JsonSerializerSettings()
{
ContractResolver = contractResolver,
});
}
serializedItem looks like
{
"_myDictionary": {
"(1,1)": [
5
]
}
}
The problem is that deserializedItem has empty MyDictionary member. Its pretty obvious as soon as Json.Net doesn't know how to convert string "(1,1)" into PairIntKey class instance.
How to do a proper converter for that case? Or it should not be a converter?
I have a simple object
[ProtoContract]
public class DataChangedEventArgs<T> : EventArgs
{
private readonly object key;
private readonly T data;
private readonly DataChangeType changeType;
///<summary>
/// Key to identify the data item
///</summary>
public object Key
{
get { return key; }
}
[ProtoMember(2, IsRequired = true)]
public T Data
{
get { return data; }
}
[ProtoMember(3, IsRequired = true)]
public DataChangeType ChangeType
{
get { return changeType; }
}
and I have a problem with the key. Its type is object, but it can be either int, long or string.
I would intuitively use a ProtoInclude attribute to say "expect these types" but unfortunately they are class only attribute.
Does anybody has any idea how I could work around this ?
For background, the public object Key is here for historical reasons (and all over the place) so I would very much like to avoid the mother of all refactorings ;-)
Any chance I could get this to Serialize, even force it to Serialize as a string ?
There are indeed a few tricks that might work; the string one you mention is pretty simple (by using a private property marked with [ProtoMember]), but I'm not sure how you would know what type to convert it back to.
There is, however, an inheritance-based ([ProtoInclude]) way to handle a finite number of types (known in advance). Here's a related example, but I'll see I can make it more specific to this case...
With regard to string-based approaches, you could use a prefix? i.e. something like:
public object Key {get;set;}
[ProtoMember(1)]
private object KeyString {
get {
if(Key == null) return null;
if(Key is string) return "s:"+(string)Key;
if(Key is int) return "i:"+Key.ToString();
// etc
}
set {
if(value == null) { Key = null; }
else if(value.StartsWith("s:")) {...}
// etc
}
}
OK; here's an example; I stress that it would be much better to work with fixed keys; the following is a bit ugly, but most of the code can be hidden away and re-used, so maybe not too bad. I'd prefer more strongly-typed keys, though. I might have mentioned that ;-p
using System;
using ProtoBuf;
static class Program
{
static void Main()
{
var message1 = new SomeMessageWithVariableKey<string>(123456, "abcdef");
var clone1 = Serializer.DeepClone(message1);
Console.WriteLine(clone1.Key);
Console.WriteLine(clone1.SomeOtherValue);
var message2 = new SomeMessageWithVariableKey<int>("abcdef", 123456);
var clone2 = Serializer.DeepClone(message2);
Console.WriteLine(clone2.Key);
Console.WriteLine(clone2.SomeOtherValue);
}
}
[ProtoContract]
[ProtoInclude(1, typeof(ProtoKey<int>))]
[ProtoInclude(2, typeof(ProtoKey<string>))]
abstract class ProtoKey
{
public static ProtoKey Create(object key)
{
if (key == null) return null;
if (key is string) return new ProtoKey<string> { Value = key };
if (key is int) return new ProtoKey<int> { Value = key };
throw new ArgumentException("Unexpected key type: " + key.GetType().Name);
}
public abstract object Value { get; protected set;}
public override string ToString()
{
return Convert.ToString(Value);
}
public override bool Equals(object obj)
{
ProtoKey other = obj as ProtoKey;
if (other == null) return false;
return object.Equals(Value, other.Value);
}
public override int GetHashCode()
{
object val = Value;
return val == null ? 0 : val.GetHashCode();
}
}
[ProtoContract]
sealed class ProtoKey<T> : ProtoKey
{
[ProtoMember(1)]
public T TypedValue { get; set; }
public override object Value
{
get { return TypedValue; }
protected set { TypedValue = (T)value; }
}
}
[ProtoContract]
public class SomeMessageWithVariableKey<T>
{
private SomeMessageWithVariableKey() { }
public SomeMessageWithVariableKey(object key, T someOtherValue) {
Key = key;
SomeOtherValue = someOtherValue;
}
public object Key { get; private set; }
[ProtoMember(1)]
private ProtoKey SerializationKey
{
get { return ProtoKey.Create(Key); }
set { Key = value == null ? null : value.Value; }
}
[ProtoMember(2)]
public T SomeOtherValue { get; set; }
}