I have the following
public enum MessageType
{
Warning,
Info,
Error
}
public class CalculationMessage
{
public string Message { get; set; }
public MessageType Type { get; set; }
}
public class ValidationMessage
{
public string Message { get; set; }
public MessageType Type { get; set; }
public string ErrorValue { get; set; }
}
I am trying to create a base class from which both of these classes are derived, however I have a problem with the enum as a ValidationMessage can be Error / Warning / Info but a CalculationMessage can only be Warning or Info.
How is this best achieved?
Thanks in advance.
You could add a parameter validation in the setter:
set
{
if(value == MessageType.Warning || value == MessageType.Info)
{
this.messageType = value;
}
else
{
throw new ArgumentOutOfRangeException();
}
}
This is, however, a violation of the Liskov Substitution Principle. Therefore be careful and think if there may be a way around (e.g. not making the setter public at all, but determing the MessageType internally).
Related
I have the following data object.
public class Response<T> where T : MyBaseDTO
{
public bool result
{
get; set;
}
public List<Message> messages
{
get; set;
}
public List<T> data
{
get; set;
}
}
public class Message
{
public Message(MessageTypeEnum type)
{
this.typeEnum = type;
}
public string type
{
get
{
return typeEnum.ToString();
}
}
public MessageTypeEnum typeEnum
{
get; set;
}
public int index
{
get; set;
}
public string field
{
get; set;
}
public string code
{
get; set;
}
public string message
{
get; set;
}
public string messageValue
{
get; set;
}
public enum MessageTypeEnum
{
WARNING,
INFO,
ERROR
}
When I use RestSharp to call the API, the deserialized Data is null with following error(Content contains correct response in string):
" ErrorMessage "Each parameter in the deserialization constructor on type 'Response.Message' must bind to an object property or field on deserialization."
I found the following post and added empty constructor to my object.
Error: Each parameter in constructor must bind to an object property or field on deserialization
public class Message
{
public Message()
{
}
public Message(MessageTypeEnum type)
{
this.typeEnum = type;
}
public string type
{
get
{
return typeEnum.ToString();
}
}
public MessageTypeEnum typeEnum
{
get; set;
}
public int index
{
get; set;
}
public string field
{
get; set;
}
public string code
{
get; set;
}
public string message
{
get; set;
}
public string messageValue
{
get; set;
}
public enum MessageTypeEnum
{
WARNING,
INFO,
ERROR
}
Added empty constructor resolved my issue with RestSharp. However I just noticed it failed some unit tests in my other project that uses Message Object.
Here is the code
using var reader = new StreamReader(result.ResponseMessage.Content.ReadAsStream());
body = reader.ReadToEnd();
Response<Test> responseObject = JsonConvert.DeserializeObject<Response<Test>>(body);
"body" looks like something below which is expected.
body "{\"result\":true,\"messages\":[{\"type\":\"ERROR\",\"index\":0,\"field\":\"ID\",\"code\":\"MISSING-ID\",\"message\":\"The entry is incomplete.",\"messageValue\":null}],\"data\":[{\"....
However, after the deserialization, "Type" became WARNING instead ERROR and hence it failed the unit test.
Looks like it defaults to first one of the Enum.
public enum MessageTypeEnum
{
WARNING,
INFO,
ERROR
}
Does anyone knows what's going on here and how to fix the issue?
since you have type as string too, you have to fix your Message costructor by adding attribute
[JsonConstructor]
public Message(MessageTypeEnum type)
{
this.typeEnum = type;
}
after this everything is working properly
Your code is not complete and your JSON example is malformed, so I am unable to provide an example with your exact code. That said, you should be able to suss out the details you need to fix your particular issue.
First, when you are deserializing to a class you must have an empty constructor as required by the deserializer. The deserializer will not be passing any parameters to your constructor, so you can't depend on them.
Second, to read/write a class property it must have both a get and set. The deserializer will not be able to fully work with properties that do not have both get and set.
One possible solution, is to create a string property that contains both get and set, and then create an additional property with only the get that is typed to the Enum.
The root object is basically your Response object, but as you didn't provide that code I made the RootObject.
public class RootObject
{
public bool result { get; set; }
public Message[] messages { get; set; }
}
public class Message
{
// string property to allow deserialization
public string type
{
get; set;
}
// read only property typed to the enum that will
// refer to the 'type' property for conversion to the enum
public MessageTypeEnum typeEnum
{
get
{
switch (type.ToUpper())
{
case nameof(MessageTypeEnum.WARNING):
return MessageTypeEnum.WARNING;
case nameof(MessageTypeEnum.INFO):
return MessageTypeEnum.INFO;
case nameof(MessageTypeEnum.ERROR):
return MessageTypeEnum.ERROR;
default:
return MessageTypeEnum.UNKNOWN;
// return UNKNOWN or throw an out of range exception?
}
}
}
public int index
{
get; set;
}
public string field
{
get; set;
}
public string code
{
get; set;
}
public enum MessageTypeEnum
{
WARNING,
INFO,
ERROR
}
}
I created the GenericAttribute.cs file in my Models
public class GenericAttributes<T>
{
public T Id { get; set; }
public bool IsActive { get; set; }
public DateTime CreatedDate { get; set; }
}
Now I want to add 'int id' field in my User Model
public class User
{
//here I want to add 'Id' field
public string UserId { get; set; }
public string password { get; set; }
public string UserType { get; set; }
public int EmployeeId { get; set; }
public virtual Employee employee { get; set; }
}
How should I do this? Please help
You can make GenericAttributes an interface so you can implement it where ever.
Such as;
public interface IGenericAttributes<T>
{
//properties
}
And use in your class declaration;
public class User : IGenericAttributes<int>
{
//properties
}
This will force your concrete type User to implement the properties of the interface.
You are getting some conflicting answers due to your naming convention. Any class of the form xxxAttribute is expected to be a subclass of the Attribute class. Attributes are metadata that you can attach to classes, fields, etc. Using reflection you can read these attributes, which is a powerful way to inform various APIs about how to interact with your custom classes - without inheritance or an interface.
If this sort of metadata is your intent, then Barr J's answer is correct. However, if your intent is for the GenericAttributes class to serve as a base class that you can inherit these properties from, then Tom Johnson is correct (although he did change GenericAttributes into an interface instead of a base class, but same result if all you have are properties like this). The latter is most likely what you are looking for.
I would suggest renaming GenericAttributes to something more descriptive, like BaseRecord or IRecord (as an interface), since User looks like data coming from or going to a database.
It would also be handy to have a non-generic version of the class/interface so that you can non-generically reference such records.
public class BaseRecord {
public Type IdType { get; }
private Object _id = null;
public Object Id {
get {
return _id;
}
set {
if(value != null) {
if(!IdType.IsAssignableFrom(value.GetType()))
throw new Exception("IdType mismatch");
}
_id = value;
}
}
public bool IsActive { get; set; }
public DateTime CreatedTime { get; set; }
public BaseRecord(Type idType)
{
if(idType == null) throw new ArgumentNullException("idType");
this.IdType = idType;
}
}
namespace Generic {
public class BaseRecord<T> : BaseRecord
{
new public T Id {
get { return (T)base.Id; }
set { base.Id = value; }
}
public BaseRecord() : base(typeof(T))
{
}
}
}
public class User : Generic.BaseRecord<int>
{}
public class OtherRecord : Generic.BaseRecord<string>
{}
// This inheritence scheme gives you the flexibility to non-generically reference record objects
// which can't be done if you only have generic base classes
BaseRecord r = new User();
r = new OtherRecord();
BaseRecord records[] = { new User(), new OtherRecord() };
To access the id for GenericAttributes class, you'll have to cast User object as base class type.
namespace SampleApp
{
class SampleProgram
{
static void Main(string[] args)
{
User User = new User() { Id = 1 };
var genericAttribute = (User as GenericAttributes<int>);
genericAttribute.Id = 2;
var genericAttributeId = genericAttribute.Id;
var classId = User.Id;
}
}
public class GenericAttributes<T>
{
public T Id { get; set; }
}
public class User : GenericAttributes<int>
{
public new int Id { get; set; }
}
}
What i want to achieve is simple, i have an Interface IDatasource, which has a property called DatasourceSettings
public interface IDatasource
{
DatasourceSettings DatasourceSettings { get; set; }
}
The implementing Class looks like this
public class TestDatasource : IDatasource
{
public DatasourceSettings IDatasource.DatasourceSettings { get { return DatasourceSettings; } set { DatasourceSettings = (TestDatasourceSettings)value; } }
public TestDatasourceSettings DatasourceSettings { get; set; }
}
As you may possibly see, the property is first implemented explicit, and it should return the DatasourceSettings Property of the class itself
So on, here is what i want to achieve
var ds = new TestDatasource();
if (ds.DatasourceSettings is TestDatasourceSettings &&
((IDatasource)ds).DatasourceSettings is DatasourceSettings)
{
// should be true
}
The Error i get :
The modifier 'public' is not valid for this item
So What's wrong here?
Remove the public from
public DatasourceSettings IDatasource.DatasourceSettings
Because it is explicitly implementing an interface method it is a-priori public
public class TestDatasource : IDatasource
{
DatasourceSettings IDatasource.DatasourceSettings { get { return DatasourceSettings; } set { DatasourceSettings = (TestDatasourceSettings)value; } }
public TestDatasourceSettings DatasourceSettings { get; set; }
}
Had the same mistake recently... turns out if the implementation is explicit you don't write access modifier.
I'm sure this is just a matter of me not understanding something completely obvious, but I seem to be hopefully stuck on this.
I have an abstract base class that is inherited by a large amount of other classes, to maintain security information across my application. I'll simplify for this question though.
public abstract class ModelBase
{
public int UserID { get; set; }
public string UserName { get; set; }
}
public class SpecificModel : ModelBase
{
public int specificInt { get; set; }
public string specificString { get; set; }
}
In this case, about 30 different classes all inherit from ModelBase.
I would like to create a method that can accept any object who's class inherits from ModelBase. So I created something like this:
public bool TestIt (ref ModelBase BaseModel)
{
BaseModel.UserID = 10;
BaseModel.UserName = "Evan";
return true;
}
However, if I try to pass in an object of type SpecificModel, I get an error.
SpecificModel hiThere = new SpecificModel();
hiThere.specificInt = 5;
hiThere.specificString = "Oh well";
bool retVal = TestMethods.TestIt(ref hiThere);
The error I see on the last line is: The best overloaded method match for 'TestMethods.TestIt(ref ModelBase)' has some invalid arguments
What am I not "getting" here?
Thanks
You have it right, except you don't want to be passing by ref (likely the source of your error). Your class is already a reference type, you probably don't need to pass a reference to it. Given the function definition in the question;
public bool TestIt (ModelBase BaseModel)
{
BaseModel.UserID = 10;
BaseModel.UserName = "Evan";
return true;
}
Will be perfect (except for the weird "always return true" but perhaps thats because this is demo code).
whats the error it throwing?
I have tried it myself its nothing look wrong in your code. might be your calling mechanism is not correct. here is the sample code.
class Program
{
static void Main(string[] args)
{
ModelBase sp = new SpecificModel2();
TestIt(ref sp);
}
public static bool TestIt(ref ModelBase BaseModel)
{
BaseModel.UserID = 10;
BaseModel.UserName = "Evan";
return true;
}
}
public abstract class ModelBase
{
public int UserID { get; set; }
public string UserName { get; set; }
}
public class SpecificModel : ModelBase
{
public int specificInt { get; set; }
public string specificString { get; set; }
}
public class SpecificModel2 : ModelBase
{
public int specificInt { get; set; }
public string specificString { get; set; }
}
}
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.