I have these interfaces:
public interface IParameter
{
string Name { get; }
object UntypedValue { get; set; }
}
public interface IValidationPolicy<T>
{
bool Validate(T toValidate);
T Default();
}
A parameter base class
[Serializable]
public abstract class ParameterBase : IParameter
{
public abstract string Name { get; protected set; }
public abstract object UntypedValue { get; set; }
}
A parameter concrete class (I have more but them are quite similar):
public class Parameter<T, V> : ParameterBase where V : IValidationPolicy<T>
{
[XmlAttribute("Name")]
public override string Name { get; protected set; }
[XmlIgnore]
protected V validation_policy_;
[XmlElement("AnyValidation", Type = typeof(AnyValidation<>))]
[XmlElement("MultiOptionsValidation", Type = typeof(MultiOptionsValidation<>))]
[XmlElement("RangeValidation", Type = typeof(RangeValidation<>))]
[XmlElement("TextValidation", Type = typeof(TextValidation))]
public V Validation
{
get
{
return validation_policy_;
}
}
[XmlIgnore]
protected T value_;
[XmlElement("Value")]
public T Value
{
get
{
return value_;
}
set
{
if (validation_policy_.Validate(value))
{
value_ = value;
}
}
}
[XmlIgnore]
public object UntypedValue
{
get
{
return Value;
}
set
{
throw new NotImplementedException();
}
}
}
And an XMLParameter class:
public class XMLParameter : INotifyPropertyChanged
{
public string Description { get; set; }
public int PasswordLevel { get; set; }
public bool Enabled { get; set; }
public ParameterBase Parameter { get; set; }
}
How can I serialize and deserialize a list of XMLParameters?
In particular I have problem on serializing the IParameter objects.
Since the interface is not serializable as first attempt I created a base abstract class ParameterBase and derive the Parameter from it.
But when I try to serialize it in a test method:
var validation = new RangeValidation<int>() { MinValue = 1, MaxValue = 6 };
var parameter = new Parameter<int, RangeValidation<int>>();
parameter.Initialize("NumberOfTrays", validation);
parameter.Value = 6;
XElement par = validation.ToXElement<Parameter<int, RangeValidation<int>>>();
I got an exception: Error at reflection of type 'ConfigurableLibray.Parameter'2[System.Int32,ConfigurableLibray.RangeValidation'1[System.Int32]]'
The inner exception says that ConfigurableLibray.Parameter'2[T,V] is not supported
What am I doing wrong?
Thanks in advance for any suggestion!
I solved implementing manually the serialization and deserialization of the classes using reflection.
Related
Say I have a class like...
public abstract class Base
{
public abstract IAttributes Attributes{ get; set; }
}
public interface IAttributes
{
string GlobalId { get; set; }
}
And a class like this...
public class ImplementAttributes : IAttributes
{
public string GlobalId { get; set; } = "";
public string LocalId { get; set; } = "";
// Other Properties and Methods....
}
And then I implement it like...
public class Derived: Base
{
public new ImplementAttributes Attributes { get; set; }
}
Now, I realise the above will not work because I can't override the property Attributes and if I hide it with new then the following bellow is null because the Base property does not get written.
public void DoSomethingWithAttributes(Base base)
{
var Foo = FindFoo(base.Attributes.GlobalId); // Null because its hidden
}
But I would like to be able to access the Base and Derived property attributes eventually like Above.
Can this be accomplished? Is there a better way?
You can use generics:
public abstract class Base<T> where T: IAttributes
{
public abstract T Attributes{ get; set; }
}
public interface IAttributes
{
string GlobalId { get; set; }
}
And
public class Derived: Base<ImplementAttributes>
{
public override ImplementAttributes Attributes { get; set; }
}
And then:
public void DoSomethingWithAttributes<T>(Base<T> b) where T : IAttributes
{
var Foo = FindFoo(b.Attributes.GlobalId);
}
You can pass Derived instances without specifying a type parameter explicitly:
Derived d = new Derived();
DoSomethingWithAttributes(d);
This is my model Heirarchy :
public interface INodeModel<T> : INodeModel
where T : struct
{
new T? ID { get; set; }
}
public interface INodeModel
{
object ID { get; set; }
string Name { get; set; }
}
public class NodeModel<T> : INodeModel<T>
where T : struct
{
public T? ID { get; set; }
public string Name { get; set; }
object INodeModel.ID
{
get
{
return ID;
}
set
{
ID = value as T?;
}
}
}
public class NodeDto<T> where T : struct
{
public T? ID { get; set; }
public string Name { get; set; }
}
and these are my mappings and test :
class Program
{
private static MapperConfiguration _mapperConfiguration;
static void Main(string[] args)
{
_mapperConfiguration = new MapperConfiguration(cfg =>
{
cfg.CreateMap(typeof(NodeDto<>), typeof(NodeModel<>));
cfg.CreateMap(typeof(NodeDto<>), typeof(INodeModel<>));
cfg.CreateMap(typeof(INodeModel<>), typeof(NodeModel<>));
});
var dto = new NodeDto<int> { ID = 1, Name = "Hi" };
var obj = _mapperConfiguration.CreateMapper().Map<INodeModel<int>>(dto);
Console.Write(obj.ID);
Console.ReadLine();
}
}
and here is the exception :
AutoMapper.AutoMapperMappingException:
Mapping types:
NodeDto1 -> INodeModel1 NodeDto`1[[System.Int32] ->
INodeModel`1[[System.Int32]
Message:
The interface has a conflicting property ID Parameter name: interfaceType
Stack:
at AutoMapper.Internal.ProxyGenerator.CreateProxyType(Type interfaceType)
at AutoMapper.Internal.ProxyGenerator.GetProxyType(Type interfaceType)
at AutoMapper.MappingEngine.CreateObject(ResolutionContext context)
AutoMapper is confused when creating a proxy implementation that you have two members with the same name in your interfaces. You're using shadowing, which is even harder. Rather than assume AutoMapper can make sense of this, which, good luck explaining to a new team member, I would instead make the interface class implementation explicit:
cfg.CreateMap(typeof(NodeDto<>), typeof(NodeModel<>));
cfg.CreateMap(typeof(NodeDto<>), typeof(INodeModel<>))
.ConvertUsing(typeof(NodeModelConverter<>));
cfg.CreateMap(typeof(INodeModel<>), typeof(NodeModel<>));
public class NodeModelConverter<T> :
ITypeConverter<NodeModel<T>, INodeModel<T>> where T : struct
{
public INodeModel<T> Convert(NodeModel<T> source, ResolutionContext context)
=> new NodeModelImpl {ID = source.ID, Name = source.Name};
private class NodeModelImpl : INodeModel<T>
{
public T? ID { get; set; }
public string Name { get; set; }
object INodeModel.ID
{
get { return ID; }
set { ID = (T?) value; }
}
}
}
No magic and completely explicit and obvious!
I'm trying to cache some classes in a List.
Because this class has a generic Property, I created a none-generic Type of the class which is the Type of this List.
So my BOs looks like this:
public class Model<T> : Model where T : class
{
public T Cls
{
get { return (T) ClsObject; }
set { ClsObject = value; }
}
}
public class Model
{
public List<ModelProperty> Properties { get; set; }
public string ModelName { get; set; }
public Type ClsType { get; set; }
public object ClsObject { get; set; }
}
So here's the Caching-Class:
private static List<Model> CachedModels {get; set;}
public static Model<T> GetCachedVersion<T>(this T cls) where T : class
{
var ret = CachedModels.FirstOrDefault(x => x.ClsType == typeof(T));
return ret != null ? (Model<T>)ret : null;
}
But the casting from the GetCachedVersion-Method crashes and I don't understand why.
Thanks for any tips!
If you are looking for the first object of type Model<T> you could change your code to
public static Model<T> GetCachedVersion<T>(this T cls) where T : class
{
return CachedModels.OfType<T>.FirstOrDefault();
}
There are a number of things you might wish to consider. Because if things were as you expected them to be your code should work no different from this.
1) tie the ClsType to the ClsObject or T
2) remove the setter (or otherwise hide it from external code) of ClsObject since it violates the invariant of Cls. You can set the Cls property to something that's not a T
public class Model {
public List<ModelProperty> Properties { get; set; }
public string ModelName { get; set; }
public virtual Type ClsType { get {
ClsObject.GetType();
} }
public object ClsObject { get; protected set; }
}
public class Model<T> : Model {
public override Type ClsType { get{
return typeof(T);
}}
public T Cls
{
get { return (T) ClsObject; }
set { ClsObject = value; }
}
}
1st guesses:
Are you by any chance using a nullable type anywhere in your code like Model?
See if you are setting ClsType properly.
It looks like you would have to create a Helper-Class which created the generic Type through reflections. There's no other way to downcast besides hardcode it.
I would like to have this kind of design :
public interface IDifferentTypes
{
}
public class IntegerType : IDifferentTypes
{
public int value { get; set; }
}
public class StringType : IDifferentTypes
{
public string value { get; set; }
}
public class DateTimeType : IDifferentTypes
{
public DateTime value { get; set; }
}
but with the property 'value' defined in the interface.
So I can call something like that :
IDifferentTypes someInt = GetSomeInt(); // GetSomeInt() returns a IntegerType object
Assert.AreEqual(5, someInt.value);
IDifferentTypes someString = GetSomeString(); // GetSomeString() returns a StringType object
Assert.AreEqual("ok", someString.value);
Problem is that the type of value is different for each implementation, what is the best way to deal with that?
You could define a generic interface (but it will have to be a property, or, more strictly, it can't be a field):
public interface IHasValue<T> {
T Value { get; }
}
Where T is the type, a placeholder, if you will, and you can do:
public class HasStringValue : IHasValue<string> {
public string Value { get; private set; }
}
Use generics if you can:
var someInt = GetSomeInt();
Assert.AreEqual(5, someInt.Value);
var someString = GetSomeString();
Assert.AreEqual("ok", someString.Value);
// ...
public interface IDifferentTypes<T>
{
T Value { get; set; }
}
public class IntegerType : IDifferentTypes<int>
{
public int Value { get; set; }
}
public class StringType : IDifferentTypes<string>
{
public string Value { get; set; }
}
public class DateTimeType : IDifferentTypes<DateTime>
{
public DateTime Value { get; set; }
}
interface IDifferentTypes
{
Object Value { get; set; }
}
class StringType : IDifferentTypes
{
string _value;
public Object Value
{
get
{
return _value;
}
set
{
_value = value as string;
}
}
}
But this means that every time you use StringType.Value you're going to need to recast it. You may want to also expose a public accessor of the specific type. You also may want to add some protections against assigning the wrong type:
class StringType : IDifferentTypes
{
public String StringProperty { get; set; }
public Object Value
{
get
{
// works with any type that can auto cast to `Object`
return StringProperty;
}
set
{
// Optional
if( typeof(string) != value.GetType() )
{
throw new MyException();
}
// works for any nullable type
StringProperty = value as string;
// OR
// throws an exception if conversion fails
StringProperty = (string)value;
}
}
}
I have a generic class
public class MetadataDifference<T>
{
public T NewMetadata { get; private set; }
public T OldMetadata { get; private set; }
// Other useful properties
public MetadataDifference(T newMetadata, T oldMetadata)
{
NewMetadata = newMetadata;
OldMetadata = oldMetadata;
}
}
I have wrapper class which has a list of MetadataDifference<> as a property.
This doesn't work:
The type or namespace name 'T' could not be found
Code:
public class DifferencesResult
{
public IEnumerable<MetadataDifference<T>> MetadataChanges { get; set; }
// other fields
}
How can I initialize a list of a generic object? Is it possible?
Either enclosing type must be opened generic:
public class DifferencesResult<T>
{
public IEnumerable<MetadataDifference<T>> MetadataChanges { get; set; }
// other fields
}
or you should use methods instead of property:
public class DifferencesResult
{
public IEnumerable<MetadataDifference<T>> GetMetadataChanges<T>();
private void SetMetadataChanges<T>(IEnumerable<MetadataDifference<T>> value)
// other fields
}
In C#, you can't hold generic property in non-generic class.
It depends on what result you want to achieve.
Here you should use a closed type, for example:
public class DifferencesResult
{
public IEnumerable<MetadataDifference<string>> MetadataChanges { get; set; }
// other fields
}
As you cannot have a generic property in a non-generic class.
You could either close it:
public class DifferencesResult
{
public IEnumerable<MetadataDifference<{sometype}>> MetadataChanges { get; set; }
// other fields
}
or use dynamic:
public class DifferencesResult
{
public IEnumerable<MetadataDifference<dynamic>> MetadataChanges { get; set; }
// other fields
}
Define an interface that doesn't have any generic types which MetadataDifference implements to provide untyped access to the underlying object:
public interface IMetadataDifference
{
object NewMetadata { get; }
object OldMetadata { get; }
}
public interface IMetadataDifference<out T> : IMetadataDifference
{
new T NewMetadata { get; }
new T OldMetadata { get; }
}
public class MetadataDifference<T> : IMetadataDifference<T>
{
object IMetadataDifference.NewMetadata { get { return NewMetadata; } }
object IMetadataDifference.OldMetadata { get { return OldMetadata; } }
public T NewMetadata { get; private set; }
public T OldMetadata { get; private set; }
// Other useful properties
public MetadataDifference(T newMetadata, T oldMetadata)
{
NewMetadata = newMetadata;
OldMetadata = oldMetadata;
}
}
public class DifferencesResult
{
public IEnumerable<IMetadataDifference> MetadataChanges { get; set; }
// other fields
}