I have an enum
namespace Business
{
public enum Color
{
Red,Green,Blue
}
}
namespace DataContract
{
[DataContract]
public enum Color
{
[EnumMember]
Red,
[EnumMember]
Green,
[EnumMember]
Blue
}
}
I have the same enum as a datacontract in WCF with same values.
I need to convert the Business enum to the DataContract enum using a translator.
Hoe can I achieve this?
If you know both types at the time you need to do the conversion you can do something like:
Business.Color bc = Business.Color.Red;
DataContract.Color dcc = (DataContract.Color)Enum.Parse(typeof(DataContract.Color), bc.ToString())
Below, a more elegant style as the framework code.
public static class Enum<T> where T : struct
{
public static T Parse(string value)
{
return (T)Enum.Parse(typeof(T), value);
}
public static T Convert<U>(U value) where U : struct
{
if (!value.GetType().IsInstanceOfType(typeof(Enum)))
throw new ArgsValidationException("value");
var name = Enum.GetName(typeof (U), value);
return Parse(name);
}
}
//enum declaration
...
public void Main()
{
//Usage example
var p = Enum<DataContract.Priority>.Convert(myEntity.Priority);
}
And voilĂ !
You could use something like below:
public static class ColorTranslator
{
public static Business.Color TranslateColor(DataContract.Color from)
{
Business.Color to = new Business.Color();
to.Red = from.Red;
to.Green = from.Green;
to.Blue = from.Blue;
return to;
}
public static DataContract.Color TranslateColor(Business.Color from)
{
DataContract.Color to = new DataContract.Color();
to.Red = from.Red;
to.Green = from.Green;
to.Blue = from.Blue;
return to;
}
}
Related
I'm doing a little project for school where I try to do a spreadsheet program, and I have two classes, I will be simplifying this with pseudocode a little bit so it's not too messy.
class DocumentController {
Document doc // This is a class with a CRUD on a document (It haves
// Sheets and every Sheet haves a Table full of Cells)
Parser p
getValueOfCell (sheetName, positionX, positionY) {
returns value of a cell in a sheet in the position x,y
}
setCell (String expression, sheetName, positionX, positionY) {
//Somewhere here we need to use p.evaluate()
}
}
class Parser {
DocumentController docController;
evaluate (expression: String) {
//Somewhere here, I need to use method getCell from Document
// for evaluating the expression (The expressions have
// references to other cells so the Parser need to resolve
// these references)
...
return value of the expression (float, integer, string, whatever)
}
}
So apparently my teacher said to me that this is a bad design, because these classes are too coupled and this is a code smell. Can someone explain me why is this so bad? How can I make a better design?
Thank you, sorry if I made some typos or the code is not legible
I think you want something like:
Class Main{
public void main(){
DocumentController dc = new DocumentController();
//you can get ahold of the parser by
Parser p = dc.getParser();
}
}
Class Parser{
DocumentController dc;
public Parser(DocumentController dc){
this.dc = dc;
}
//your methods
}
Class DocumentController{
Parser p;
public DocumentController(){
this.p = new Parser(this);
}
public Parser getParser(){
return this.p;
}
//your methods
}
Although there are probably better ways of doing this instead like passing your object to the method when you need it. Something like
Class Main{
public void main(){
DocumentController dc = new DocumentController();
Parser p = new Parser();
p.myParserMethod(dc);
dc.myDocMethod(p);
}
}
Class Parser{
public myParserMethod(DocumentController dc){
//you can use the same documentController object here
}
}
Class DocumentController{
public myDocMethod(Parser p){
//you can use your parser object here
}
}
hope that helps
It looks like you want to format value by some key expression. If yes, then we can create mapping between this key expression and format classes. Then we can use Factory pattern to create desired objects to format your cell value.
Let me show a simple example via C#.
So this is a DocumentController:
public class DocumentController
{
private DocumentService _documentService;
public DocumentController()
{
_documentService = new DocumentService(); // this dependency can be
// resolved by IoC container
}
public void GetValueCell(int docId, string sheetName, int positionX,
int positionY)
{
_documentService.GetValueCell(docId, sheetName, positionX,
positionY);
}
public void SetCell(int docId, string expression, string sheetName, int
positionX, int positionY, object value)
{
_documentService.SetCell(docId, expression, sheetName, positionX,
positionY, value);
}
}
And this is a service which will execute logic related to Document:
public class DocumentService
{
private DocumentRepository _documentRepository;
public DocumentService()
{
_documentRepository = new DocumentRepository();
}
public string GetValueCell(int docId, string sheetName, int positionX, int positionY)
{
Document document = _documentRepository.GetById(docId);
return document.GetCellValue(sheetName, positionX, positionY);
}
public void SetCell(int docId, string expression, string sheetName, int
positionX, int positionY, object value)
{
Document document = _documentRepository.GetById(docId);
document.SetCellValue(expression, sheetName, positionX, positionY,
value);
}
}
It is unknown how you get Document, but it is possible to use repository pattern for that purpose.
public class DocumentRepository
{
public Document GetById(int id) { throw new NotImplementedException(); }
}
and this is a Document class:
public class Document
{
private object[][] _cells;
public Document(int x)
{
_cells = new object[x][];
}
public string GetCellValue(string sheetName, int positionX, int positionY)
{
return string.Empty;
}
public void SetCellValue(string expression, string sheetName, int
positionX, int positionY, object value)
{
FormatterType formatterType = new
FormatterTypeToExpression().FormatterByExpression[expression];
Formatter formatter = new FormatterFactory().
FormatterByFormatterType[formatterType];
object formattedCell = formatter.Format(value);
_cells[positionX][positionY] = formattedCell;
}
}
and this is a mapping between FormatterType and your key expression:
public class FormatterTypeToExpression
{
public Dictionary<string, FormatterType> FormatterByExpression { get; set; } =
new Dictionary<string, FormatterType>
{
{ "string", FormatterType.String}
// here you write expressions and foramtters
};
}
This is a formatter type:
public enum FormatterType
{
String, Number, Decimal, Whatever
}
Then you need something like factory to take a formatter:
public abstract class Formatter
{
public abstract object Format(object value);
}
And abstract class which will define behavior of derived formatter classes:
public class FormatterString : Formatter
{
public override object Format(object value)
{
return "I am a formatted string value";
}
}
An example how FormatterFactory could look like:
public class FormatterFactory
{
public Dictionary<FormatterType, Formatter> FormatterByFormatterType { get; set; }
= new Dictionary<FormatterType, Formatter>
{
{ FormatterType.String, new FormatterString()}
// here you write FormatterType and formatters
};
}
I have a simple polymorphic model like this
public class Foo {
private Bar bar1;
private Bar bar2;
public Bar getBar1() {
return bar1;
}
public Bar getBar2() {
return bar2;
}
public void setBar1(Bar bar1) {
this.bar1 = bar1;
}
public void setBar2(Bar bar2) {
this.bar2 = bar2;
}
}
#JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "#type")
public class Bar {
}
public class BarExpression extends Bar {
private String expression;
public String getExpression() {
return expression;
}
#JsonIgnore
public Object getValue() {
return null;
}
public void setExpression(String expression) {
this.expression = expression;
}
}
public class BarLiteral extends Bar {
private String value;
private String type;
public String getType() {
return type;
}
public Object getValue() {
return value;
}
public void setType(String type) {
this.type = type;
}
public void setValue(String value) {
this.value = value;
}
}
Serializing a simple example like this
public void run() throws Exception {
Foo foo;
BarLiteral bar1;
BarExpression bar2;
//
foo = new Foo();
bar1 = new BarLiteral();
bar1.setType("java.lang.String");
bar1.setValue("gnu");
foo.setBar1(bar1);
bar2 = new BarExpression();
bar2.setExpression("bean.property * 2");
foo.setBar2(bar2);
//
ObjectMapper mapper = new ObjectMapper();
mapper.enable(SerializationFeature.INDENT_OUTPUT);
StringWriter w = new StringWriter();
mapper.writeValue(w, foo);
System.out.println(w.toString());
}
gives the expected result:
{
"bar1" : {
"#type" : "de.mit.jackson.BarLiteral",
"value" : "gnu",
"type" : "java.lang.String"
},
"bar2" : {
"#type" : "de.mit.jackson.BarExpression",
"expression" : "bean.property * 2"
}
}
The question is now: I want to improve user experience when handwriting this "DSL" by supporting "primitive shortcuts" for the typed "Bar..." classes like this
{
"bar1" : "gnu",
"bar2" : "#{bean.property * 2}"
}
The solution that came closest was using a converter on Foo#bar1 and Foo#bar2, checking for either String or "Bar" input, but this solution requires decoration of every attribute definition.
Creating a deserializer with a comparable behavior did not work, as the #JsonTypeInfo is not compatible in the sense that i can have a #JsonDeserialize implementation that will check for a String event and then delegate to the standard #JsonTypeInfo process. The #JsonTypeInfo standard will check only for the #type and then delegate back to the (subtype) deserializer which is again my wrapper implementation.
The required process is
if input event is string {
parse and return string input
} else {
activate #type parsing delegate;
after #type parsing activate standard BeanDeserializer
(**not** my implementation)
}
Is there another hook i am missing?
My complex type wouldn't pass from Show to Init method even with configured MvxJsonNavigationSerializer as specified here Custom types in Navigation parameters in v3
public class A
{
public string String1 {get;set;}
public string String2 {get;set;}
public B ComplexObject1 {get;set;}
}
public class B
{
public double Double1 {get;set;}
public double Double2 {get;set;}
}
When I pass instance of object A to ShowViewModel method I receive this object with String1 & String2 deserialized correctly but CopmlexObject1 is null.
How to deal with complex object MvvmCross serialization?
I believe there may be some gremlins in that previous answer - will log as an issue :/
There are other possible routes to achieve this type of complex serializable object navigation still using Json and overriding parts of the framework, but actually I think that it might be better to just use your own BaseViewModel's to do serialization and deserialization - e.g. use serialization code like:
public class BaseViewModel
: MvxViewModel
{
private const string ParameterName = "parameter";
protected void ShowViewModel<TViewModel>(object parameter)
where TViewModel : IMvxViewModel
{
var text = Mvx.Resolve<IMvxJsonConverter>().SerializeObject(parameter);
base.ShowViewModel<TViewModel>(new Dictionary<string, string>()
{
{ParameterName, text}
});
}
}
with deserialization like:
public abstract class BaseViewModel<TInit>
: MvxViewModel
{
public void Init(string parameter)
{
var deserialized = Mvx.Resolve<IMvxJsonConverter>().DeserializeObject<TInit>(parameter);
RealInit(deserialized);
}
protected abstract void RealInit(TInit parameter);
}
then a viewModel like this:
public class FirstViewModel
: BaseViewModel
{
public IMvxCommand Go
{
get
{
return new MvxCommand(() =>
{
var parameter = new A()
{
String1 = "Hello",
String2 = "World",
ComplexObject = new B()
{
Double1 = 42.0,
Double2 = -1
}
};
ShowViewModel<SecondViewModel>(parameter);
});
}
}
}
can navigate to something like:
public class SecondViewModel
: BaseViewModel<A>
{
public A A { get; set; }
protected override void RealInit(A parameter)
{
A = parameter;
}
}
A small addition to Stuart's answer to add type safety:
public class BaseViewModel: MvxViewModel {
protected bool ShowViewModel<TViewModel, TInit>(TInit parameter) where TViewModel: BaseViewModel<TInit> {
var text = Mvx.Resolve<IMvxJsonConverter>().SerializeObject(parameter);
return base.ShowViewModel<TViewModel>(new Dictionary<string, string> { {"parameter", text} });
}
}
public abstract class BaseViewModel<TInit> : BaseViewModel {
public void Init(string parameter)
{
var deserialized = Mvx.Resolve<IMvxJsonConverter>().DeserializeObject<TInit>(parameter);
RealInit(deserialized);
}
protected abstract void RealInit(TInit parameter);
}
ShowViewModel method now takes the same parameter type that the RealInit method instead of an object type. Also, BaseViewModel<TInit> inherits from BaseViewModel so their instances can also call the new ShowViewModel method.
The only drawback is that you have to explicitly specify the parameter type in the call like this:
ShowViewModel<StoreInfoViewModel, Store>(store);
I can't seem to be able to read a custom enum attribute using the following code:
public class CustomAttribute : Attribute
{
public CultureAttribute (string value)
{
Value = value;
}
public string Value { get; private set; }
}
public enum EnumType
{
[Custom("value1")]
Value1,
[Custom("value2")]
Value2,
[Custom("value3")]
Value3
}
...
var memInfo = typeof(CustomAttribute).GetMember(EnumType.Value1.ToString());
// memInfo is always empty
var attributes = memInfo[0].GetCustomAttributes(typeof(CustomAttribute), false);
Not sure if I am just missing something obvious here or if there is an issue with reading custom attributes in Mono/MonoMac.
You should call the GetMember() on the type that has the given member of course :) In this case that's EnumType not CustomAttribute.
Also fixed what I assume to be copy-paste error with the attribute constructor.
Complete working test code (you should know with 23k reps that we prefer these to half-made programs that we have to complete ourselves ;)):
using System;
public class CustomAttribute : Attribute
{
public CustomAttribute (string value)
{
Value = value;
}
public string Value { get; private set; }
}
public enum EnumType
{
[Custom("value1")]
Value1,
[Custom("value2")]
Value2,
[Custom("value3")]
Value3
}
class MainClass
{
static void Main(string[] args)
{
var memInfo = typeof(EnumType).GetMember(EnumType.Value1.ToString());
Console.WriteLine("memInfo length is {0}", memInfo.Length);
var attributes = memInfo[0].GetCustomAttributes(typeof(CustomAttribute), false);
Console.WriteLine("attributes length is {0}", attributes.Length);
}
}
See in operation.
When I try to serialize and deserialize a Set<ClassA<?>> of generic objects that look as follows:
public class ClassA<T> {
private ClassB datum;
private T value;
...
}
If that T happens to be an enum, it gets written as a String value. This is fine for serialization, but when I deserialize, it's not possible to know if the String value is an enum or not. Jackson then turns the resulting object into a String and you get a ClassA<String> instead of ClassA<SomeEnumType>.
Is there a configuration in Jackson to have it create some hints that the value is an enum? Or perhaps turn the enum into a JSON object rather then a string value?
Is there a configuration in Jackson to have it create some hints that the value is an enum?
It's possible to deserialize to an enum instance from a matching JSON string value. Or is this somehow not applicable to your situation?
Here is an example.
import java.util.Set;
import java.util.TreeSet;
import org.codehaus.jackson.annotate.JsonAutoDetect.Visibility;
import org.codehaus.jackson.annotate.JsonMethod;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.type.TypeFactory;
public class JacksonFoo
{
public static void main(String[] args) throws Exception
{
ObjectMapper mapper = new ObjectMapper().setVisibility(JsonMethod.FIELD, Visibility.ANY);
String myEnumJson = mapper.writeValueAsString(MyEnum.MyEnum1);
System.out.println(myEnumJson);
MyEnum myEnum = mapper.readValue(myEnumJson, MyEnum.class);
System.out.println(myEnum);
Set<ClassA<MyEnum>> set = new TreeSet<ClassA<MyEnum>>();
set.add(new ClassA<MyEnum>(new ClassB("bValue7"), MyEnum.MyEnum1));
set.add(new ClassA<MyEnum>(new ClassB("bValue8"), MyEnum.MyEnum2));
String setJson = mapper.writeValueAsString(set);
System.out.println(setJson);
TypeFactory typeFactory = TypeFactory.defaultInstance();
Set<ClassA<MyEnum>> setCopy = mapper.readValue(setJson,
typeFactory.constructCollectionType(Set.class,
typeFactory.constructParametricType(ClassA.class, MyEnum.class)));
System.out.println(setCopy);
}
}
class ClassA<T> implements Comparable<ClassA<T>>
{
ClassB datum;
T value;
ClassA()
{
}
ClassA(ClassB datum, T value)
{
this.datum = datum;
this.value = value;
}
#Override
public int compareTo(ClassA<T> o)
{
return 42;
}
#Override
public String toString()
{
return String.format("ClassA: datum=%s, value=%s", datum, value);
}
}
class ClassB
{
String bValue;
ClassB()
{
}
ClassB(String bValue)
{
this.bValue = bValue;
}
#Override
public String toString()
{
return String.format("ClassB: bValue=%s", bValue);
}
}
enum MyEnum
{
MyEnum1("myEnum1", 1), MyEnum2("myEnum2", 2);
String name;
int id;
MyEnum(String name, int id)
{
this.name = name;
this.id = id;
}
}
Output:
"MyEnum1"
MyEnum1
[{"datum":{"bValue":"bValue7"},"value":"MyEnum1"},{"datum":{"bValue":"bValue8"},"value":"MyEnum2"}]
[ClassA: datum=ClassB: bValue=bValue7, value=MyEnum1, ClassA: datum=ClassB: bValue=bValue8, value=MyEnum2]
If for some reason it's necessary to have enums serialized as POJOs, then it appears custom serialization processing is required. Serializing enums with Jackson