I have a class that looks like this:
public class MyModel{
public int TheId { get; set; }
public int ....
public string ....
}
I have another class that take a list of several types, including MyModel, and serializes the lists in json. It has several methods, one for each type of list.
public class ToJson{
public string MyModelToJson (List<MyModel> TheListOfMyModel) {
string ListOfMyModelInJson = "";
JavascriptSerializer TheSerializer = new ....
TheSerializer.RegisterConverters(....
ListOfMyModelInJson = TheSerializer.Serialize(TheListOfMyModel);
return ListOfMyModelInJson;
}
public string MyOtherModelToJson (List<MyOtherModel> TheListOfOtherModel) {....}
public string YetAnotherModelToJson (List<YetAnotherModelToJson> TheListOfYetAnotherModelToJson) {....}
}
What I want to do is encapsulate the serializing into MyModel, something like this:
public class MyModel{
public int TheId { get; set; }
public int ....
public string ....
public string MyModelToJson()
}
How can I encapsulate a method into an object so that it's available for a list of objects?
I thought of doing a foreach loop but that gets messy because in the calling method, you have to manipulate the json strings of each object in the list and concatenate them.
Let me know of OO principles of encapsulation apply in this case.
Thanks for your suggestions.
One way would be to define your ToJson as accepting a generic type:
public class ToJson<T>{
public string MyModelToJson (List<T> TheListOfMyModel) {
string ListOfMyModelInJson = "";
JavascriptSerializer TheSerializer = new ....
TheSerializer.RegisterConverters(....
ListOfMyModelInJson = TheSerializer.Serialize(TheListOfMyModel);
return ListOfMyModelInJson;
}
}
extension methods!
public static class JsonExtensions
{
public static string ToJson<T>(this List<T> list)
{
}
}
I'm not sure that I understand your question, but I think that what you want to do is not return a String but a JsonObject, JsonArray, or JsonPrimitive:
public class MyModel {
public JsonObject myModelToJson() ... //this method implements the interface!
}
Where JsonObject is a class that represents a json object.
Make this class implement an interface where the contract is that the return value is a JsonValue.
Then, in the ToJson class, return a JsonArray:
public class ToJson
public JsonArray myModelToJson(List<things that can be json-ized> myList) ...
}
Don't serialize the objects/arrays/primitives to a String until you absolutely need to, and let a library take care of the actual serialization.
That was a confusing answer.
Here's what I think you should do:
get hold of a decent json library. Ideally, it should have JsonObjects, JsonArrays, and JsonPrimitives which are subclasses of JsonElement. I've used Google gson in java, but I don't know what an equivalent C# version would be.
create an interface, JsonAble with one method -- toJson -- that returns a JsonElement.
implement this interface for all concerned classes
serializing a list of JsonAble objects is then very easy -- it becomes a JsonArray.
a decent json library should have a serialize method -- so you'll never have to worry about throwing strings around yourself
For what it's worth, I wouldn't remove the class at all. What you're talking about doing is adding an additional responsibility to your model, and apparently going against SRP heuristic. That is, you have a class whose current responsibility is to model data, and you're going to make it responsible for modeling data and also converting its data to some form, using various service classes that it now needs to know about. If the model class encapsulates GUI concepts like raising events for GUI, then it has divergent reasons to change - if the scheme for notifying the GUI changes and if the scheme for converting to JSON changes.
If it were me, I'd have the models inherit from a base class or define an interface as mentioned by Matt Fenwick, and have your ToJson class take a batch of those as input, process them, and return the result.
I understand the desire to eliminate the extra class, and might advocate it if it were a simple conversion involving only data elements of the class, but as soon as you need a service class of some kind to do the operation, it seems a poor fit for the model object, as you now cannot model data without a JavascriptSerializer. That's awkward if you want to model data that you don't then serialize.
One final thing that I can think of is that you can build on a'b'c'd'e'f'g'h's suggestion and piggy back the method onto some existing service, thus eliminating the class. If you just have a generic method on that service that implements the serialization, you can eliminate the separate class, since you no longer need a separate method for each model object type.
Related
I'm using Redis Cache using Stack Exchange library.
I used cloudStructure library to use Redis Dictionary and Redis List.
Problem is when I try to retrieve values and if that model has a null
value for one list property it is throwing me below exception -
Jil.DeserializationException : Error occurred building a deserializer
for TestMainClass: Expected a
parameterless constructor for
System.Collections.Generic.ICollection1[TestChildClass]
---- Jil.Common.ConstructionException : Expected a parameterless constructor for
System.Collections.Generic.ICollection1[TestChildClass]
public class TestMainClass
{
public TestMainClass();
public int Id { get; set; }
public virtual ICollection<TestChildClass> Mydata { get; set; }
public string Title { get; set; }
}
public class TestChildClass
{
public TestChildClass();
public int Id { get; set; }
public string Value { get; set; }
}
Redis code for retrieve value:
RedisDictionary<int, TestMainClass> dictionary =
new RedisDictionary<int, TestMainClass>("localhost", "mylocaldictionary");
var result = await dictionary.Get(121);
What If I could not able to convert ICollection < T > into List < T >?
It might be a nice feature if the serialization library detected interfaces like ICollection<T> and IList<T> and implemented them with the concrete List<T> during deserialization, but ultimately: every feature needs to be thought of, considered (impact), designed, implemented, tested, documented and supported. It may be that the library author feels this is a great idea and should be implemented; it might not be high on the author's list, but they'd be more than happy to take a pull request; or there might be good reasons not to implement it.
In the interim, as a general rule that will solve virtually every serialization problem you will ever encounter with any library:
the moment the library doesn't work perfectly with your domain model: stop serializing your domain model - use a DTO instead
By which, I mean: create a separate class or classes that are designed with the specific choice of serializer in mind. If it wants List<T>: then use List<T>. If it wants public fields: use public fields. If it wants the types to be marked [Serializable]: mark the types [Serializable]. If it wants all type names to start with SuperMagic: then start the type name with SuperMagic. As soon as you divorce the domain model from the serialization model, all the problems go away. In addition: you can support multiple serializers in parallel, without getting into the scenario that A needs X and doesn't work with Y; B needs Y and doesn't work with X.
All you then need to do is write a few lines of code to map between the two similar models (or use libraries that do exactly that, like AutoMapper).
I am designing a 3 layer framework
I would like to know if It's possible to pass attribiutes of an object to a function without declaring them explicitly ?
For example If I want to pass Id,Name to personnelBL.ValidateInsert(...)
I don't want the ValidateInsert function interface look like this : ValidateInsert(Id,Name)
The reason for that is that I want to write a base abstract class to contain a ValidateInsert(...)
abstract function so I will Inherit from that class in my BL Layer classes and If the ValidateInsert input parameters could be declared in a way that I could pass an object attribiutes in a general form It would really be nice .
Note: Someone might say that I can pass an object to the function using generics but I really don't want to pass an object ! I want to pass any object's attribiutes so I can Inherit that abstract base class in any entityBL classes .
I really could not explain what I want better ! Sorry for that and thanks for understanding me .
not sure that I fully understand what you want , but I think the below can help
You can use reflection.You can avoid the performance issues, is you create method per class on the fly and compile it (can use compile expression tree). and add your own attribute that you put only on relevant attributes.
Create an Interface, It can return dictionary of column name and their values. your abstract class will implement this interface.
hope this answer your question
I am not sure if i understand your question correctly, but are you looking for something similar to this-
public class Base<T, TFiled>
{
public void ValidateInsert(TFiled filed)
{
}
}
public class Derived : Base<Derived, long>
{
public long Id { get; set; }
}
public class AnotherDerived : Base<Derived, string>
{
public string IdSring { get; set; }
}
public class MyObject
{
private Derived d = new Derived();
private AnotherDerived anotherIsntance = new AnotherDerived();
public MyObject()
{
d.ValidateInsert(10);
anotherIsntance.ValidateInsert("some string");
}
}
Well, not really.
But you can get very close to!
You can use the Expression API. It's awesome. The code I'll post here is just pseudocode but you'll get the idea. I'll not worry about syntax but I'll try the hardest I can.
public static bool ValidateInsert(params Expression<Func<object,object>>[] properties)
{
//Here you'll do some code to get every property. You can do a foreach loop.
//I think you will need to use reflection to get the property values
} //Change Func<Object,Object> accordingly. This represents a function that takes an object and returns another object.
This is how you can achieve the syntax, but I'm not sure about functionality.
You'll need an "instance" object where you'll get the properties values from.
So, you could call it like this:
ValidadeInsert(x => x.Id, x => x.Name, x => x.Whatever)
Here you can see how to get the Getter method of a property. I think you can get the PropertyInfo from the lambda expression, but I'm not sure. You'll have to do some research and adapt it to your code, if you decide to follow this way.
Sorry about my english, but I think you understood what I meant.
I've been searching for awhile to see if anyone was trying to do something close to this and I find a bunch of people trying to interact with a generically typed List. I instead need to interact with a List of complex objects who are generically typed. Here's the current code.
public class RequestBundleItem<T> where T : BaseJsonResponseMessage
{
public T Response { get; private set; }
//intializers - code not needed
public void SetResponse(String jsonResponse)
{
Response = (T)jsonResponse.JsonToObject<T>();
}
}
public class RequestBundleManager
{
private List<RequestBundleItem<T>> BundleItems;
public async Task<List<RequestBundleItem<T>>> ProcessItemsAsync()
{
List<Task<JsonValueEventArgs>> tasks = //create tasks from bundleitems;
for (var i = 0; i < tasks.Count(); i++)
{
Task<JsonValueEventArgs> curTask = tasks[i];
var args = await curTask;
BundleItems[i].SetResponse(args.ValueAsText);
}
return BundleItems;
}
public void AddItem<T>(RequestBundleItem<T> newItem) where T : BaseJsonResponseMessage
{
BundleItems.Add(newItem);
}
}
This line is what's causing the problem
private List<RequestBundleItem<T>> BundleItems;
I don't know how to define this list since T is generic and just needs to implement BaseJsonResponseMessage but I don't want to type the RequestBundleManager itself.
SOLUTION:
I ended up removing the generic from the RequestBundleItem and the consumer is responsible for knowing the response type it needs back.
Make RequestBundleManager generic also:
public class RequestBundleManager<T>
And now you list can be defined with type T. Of course, you have to make sure that the T you use when creating your RequestBundleManger is the same as the one you used for RequestBundleItem, and you list will be homogeneous.
If you want your RequestBundleManager to handle lists with mixed T, then you will need to have RequestBundleItem derive from a base class or else have it implement an interface.
Define the list in your RequestBundleManager like this:
private List<RequestBundleItem<BaseJsonResponseMessage>>
If you don't put a type on the RequestBundleManager, you don't know the specific type of the object inside the list except that it's a BaseJsonResponseMessage. Then it makes sense to just define it like that. It will give you access only to methods defined in BaseJsonResponseMessage though.
If that's not enough, consider defining an interface with all the methods you want to have access to in the RequestBundleManager and put it as a constraint on your type in RequestBundleItem. Something like this:
public class RequestBundleItem<T> where T : BaseJsonResponseMessage, IMyInterface
Then define the list in RequestBundleManager like:
private List<RequestBundleItem<IMyInterface>>
My application has n-tier architecture. I have different layers(Business Logic & Data Link & GUI). I am using some common classes to pass data from one layer to the other. I have a class(say RetrnValueCls) which has just two variables Return value and Return Message. While I am passing data from one layer to the other, I need to return this Return Value Class along with the other class(say MasterItemsCls) which has other variables.
Below are the methods
public MasterItemsCls GetMasterItemsMDL()
{
/* Does some computations and assign them to
attributes of MasterItemsCls and pass it other methods in other layers. */
}
public ReturnValueCls GetMasterItemsMDL()
{
/* Does some computations and assign them to
attributes of ReturnValueCls and pass it other methods in other layers. */
}
I want to return both the above classes(MasterItemsCls & ReturnValueCls) as return type for the method GetMasterItemsMDL at once and also I don't want to combine both the classes. Please let me know if there is any way I can do that.
A function can only return a single value, so in that sense the answer is no.
Functions can have out parameters, so you could return one of the two values via an out parameter.
The cleanest way to handle this in my opinion is to use a third class to contain the other two. Tuple<T1,T2> can be used for that purpose:
public Tuple<MasterItemsCls, ReturnValueCls> MyFunction()
{
// Do stuff
return new
Tuple<MasterItemsCls, ReturnValueCls>(myMasterItemsCls, myReturnValueCls);
}
One disadvantage of Tuple<T1,T2> is that the values are accessed as the rather unintuitive Item1 and Item2.
If you don't want to use Tuple<T1,T2>, it is easy to create your own class to contain MasterItemsCls and ReturnValueCls. That is my preferred approach.
You don't need to combine both classes but a possible and direct approach is to generate a class that contains one instance of each class you're trying to return.
public class YouClassName
{
public MasterItemsCls MasterItemsCls {get; set;}
public ReturnValueCls ReturnValueCls {get; set;}
}
A method can only return one object. You could possibly create some other class that has instances of each of these others.
Generics may be helpful as a wrapper for your return element.
You could do the following:
public ReturnValueCls<MasterItemsCls> GetMasterItemsMDL()
{
}
Your ReturnValueCls<T> expects a type parameter for its return type. So your retun type can would act as a wrapper for your desired return and be able to hold your return message.
Example of your class definition. May require some constraints:
public class ReturnValueCls<T>
{
public T Value { et; set;}
public string Message {get; set;}
}
I have a web method which calls a method in the DAL to execute a procedure by id and returns an object of type MyData.
[WebMethod]
public MyData GetDataById(int id)
{
DAL myDAL = new DAL();
return myDAL.GetDataById(id);
}
The class MyData looks like the following
public class MyData
{
public string Name;
public Data[] DataItems;
}
and the class Data,
public class Data
{
public string key;
public string value;
}
Now this worked fine for until we wanted to return a bit of complex types.
For an example, a DataTable, or perhaps something like a structure (or class) containing latitude, longitude and a value. So obviously, class Data cannot hold multiple values or a DataTable. (It contains two strings, key and value).
So what I actually want is the type to be Generic. So I changed it to...
public class MyData<T>
{
public string Name;
public T[] DataItems;
}
So I'll be doing something like this inside the myDAL.GetDataById because what type of data is returned differs according to the type.
if (GetTypeOfId(id) == "NormalData")
{
MyData<Data> result = new MyData<Data>();
}
else if (GetTypeOfId(id) == "Map")
{
MyData<MapData> result = new MyData<MapData>();
}
But I need to specify a type for the method signature as well which unfortunately is found out ONLY at run time.
How do I handle such a situation ?
I feel like I am using Generics for something I shouldn't be using it for.
Or how is usually a situation where the type is found out only at run time resolved?
UPDATE: The worst case scenario is having different web service calls for getting normal data and map data which I would like to avoid.
You can only use generics in circumstances where you can specify the type at compile time, so I don't think they're suitable for your situation.
I would recommend having two web service calls, that's the easiest way to handle this.
If you really want only one web service call you could have your web method simply return a byte[] (created using BinaryFormatter) or a string (created using, say, an XmlSerializer) and then deserialise that on your client side, but it means you have to have the same classes on both sides (or you have to have custom deserialisation code) and your web service can't easily be consumed by multiple clients.
I'm not sure what you are asking for but i have a feeling that using an interface with a generic method could help you pass return values around and call the GetValue generic method on that.
If you use IData instead of a generic type as return value you will be able to extract the embedded data with ret.GetValue<MyData>(). And if you set the Type when creating the Data<T> you will be able to query on that too.
Maybe you can adapt the following snippet to your needs.
public interface IData {
type Type { get; set; }
string Name { get; set; }
T GetValue<T>();
}
public class Data<T> : IData
{
public Type Type { get; set; }
public string Name { get; set; }
public T Value { get; set; }
public Tret GetValue<Tret>() {
return (Tret)(Object)Value;
}
}
The answer was pretty easy and stupid of me not to think of it before.
I just created a parent class and made the Data and all the other required classes inherit from it.