DateTime을 위한 사용자 지정 자바스크립트 컨버터?
개체가 있습니다. DateTime 속성이 있습니다..ashx 핸들러에서 AJAX/JSON을 통해 웹 페이지로 해당 개체를 전달합니다.제3자 통제를 사용하고 싶지 않아요
이 작업을 수행할 때:
new JavaScriptSerializer().Serialize(DateTime.Now);
이해합니다.
"\/Date(1251385232334)\/"
하지만 "8/26/2009"을 원합니다. (현지화는 신경쓰지 마시고...제 앱은 매우 지역화되어 있기 때문에 날짜 형식에 대한 가정은 이 질문에서 논의할 만한 것이 아닙니다.사용자 지정 변환기를 만들거나 등록하는 경우
public class DateTimeConverter : JavaScriptConverter
{
public override IEnumerable<Type> SupportedTypes
{
get { return new List<Type>() { typeof(DateTime), typeof(DateTime?) }; }
}
public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
{
Dictionary<string, object> result = new Dictionary<string, object>();
if (obj == null) return result;
result["DateTime"] = ((DateTime)obj).ToShortDateString();
return result;
}
public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
{
if (dictionary.ContainsKey("DateTime"))
return new DateTime(long.Parse(dictionary["DateTime"].ToString()), DateTimeKind.Unspecified);
return null;
}
}
그러면 다음과 같은 결과가 나타납니다(사용자 지정 직렬화 메서드의 반환 값은 사전이므로).
{"DateTime":"8/27/2009"}
그래서 이제 내 자바스크립트에서 대신에
somePerson.Birthday
저는 해야합니다.
somePerson.Birthday.DateTime
or
somePerson.Birthday["DateTime"]
커스텀 컨버터가 직접 문자열을 반환하게 해서 깨끗한 자바스크립트를 가질 수 있도록 하려면 어떻게 해야 합니까?
자바스크립트 직렬화기는 확실히 당신이 원하는 것을 할 수 있습니다.
사용자 지정 변환기를 만들어 직렬화기에 등록하면 자바스크립트 직렬화기에서 수행하는 직렬화를 어떤 유형이든 사용자 지정할 수 있습니다.Person이라는 클래스가 있다면 다음과 같은 변환기를 만들 수 있습니다.
public class Person
{
public string Name { get; set; }
public DateTime Birthday { get; set; }
}
public class PersonConverter : JavaScriptConverter
{
private const string _dateFormat = "MM/dd/yyyy";
public override IEnumerable<Type> SupportedTypes
{
get
{
return new[] { typeof(Person) };
}
}
public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
{
Person p = new Person();
foreach (string key in dictionary.Keys)
{
switch (key)
{
case "Name":
p.Name = (string)dictionary[key];
break;
case "Birthday":
p.Birthday = DateTime.ParseExact(dictionary[key] as string, _dateFormat, DateTimeFormatInfo.InvariantInfo);
break;
}
}
return p;
}
public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
{
Person p = (Person)obj;
IDictionary<string, object> serialized = new Dictionary<string, object>();
serialized["Name"] = p.Name;
serialized["Birthday"] = p.Birthday.ToString(_dateFormat);
return serialized;
}
}
그리고 이렇게 사용합니다.
JavaScriptSerializer serializer = new JavaScriptSerializer();
serializer.RegisterConverters(new[] { new PersonConverter() });
Person p = new Person
{
Name = "User Name",
Birthday = DateTime.Now
};
string json = serializer.Serialize(p);
Console.WriteLine(json);
// {"Name":"User Name","Birthday":"12/20/2010"}
Person fromJson = serializer.Deserialize<Person>(json);
Console.WriteLine(String.Format("{0}, {1}", fromJson.Name, fromJson.Birthday));
// User Name, 12/20/2010 12:00:00 AM
승인된 답변에 대한 개선 사항이 있습니다.
제네릭을 사용하고 유형을 전달하고 반사를 사용하여 날짜 시간 속성을 결정합니다.
public class ExtendedJavaScriptConverter<T> : JavaScriptConverter where T : new()
{
private const string _dateFormat = "dd/MM/yyyy";
public override IEnumerable<Type> SupportedTypes
{
get
{
return new[] { typeof(T) };
}
}
public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
{
T p = new T();
var props = typeof(T).GetProperties();
foreach (string key in dictionary.Keys)
{
var prop = props.Where(t => t.Name == key).FirstOrDefault();
if (prop != null)
{
if (prop.PropertyType == typeof(DateTime))
{
prop.SetValue(p, DateTime.ParseExact(dictionary[key] as string, _dateFormat, DateTimeFormatInfo.InvariantInfo), null);
}
else
{
prop.SetValue(p, dictionary[key], null);
}
}
}
return p;
}
public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
{
T p = (T)obj;
IDictionary<string, object> serialized = new Dictionary<string, object>();
foreach (PropertyInfo pi in typeof(T).GetProperties())
{
if (pi.PropertyType == typeof(DateTime))
{
serialized[pi.Name] = ((DateTime)pi.GetValue(p, null)).ToString(_dateFormat);
}
else
{
serialized[pi.Name] = pi.GetValue(p, null);
}
}
return serialized;
}
public static JavaScriptSerializer GetSerializer()
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
serializer.RegisterConverters(new[] { new ExtendedJavaScriptConverter<T>() });
return serializer;
}
}
사용 방법은 간단합니다.
JavaScriptSerializer serialiser = ExtendedJavaScriptConverter<Task>.GetSerializer();
누군가에게 도움이 되길 바랍니다.
실제로 포장지 유형을 모르거나 포장지 개체를 필요로 하지 않고도 이 작업을 수행할 수 있는 좋은 깨끗한 방법이 있습니다.
JavaScript Converter를 사용하여 개체를 ID 사전을 구현하는 URI로 변환합니다.JavaScript Serializer는 이것을 문자열로 직렬화합니다.
이 해킹은 다음과 같이 설명되어 있습니다: Custom DateTime JSON Format for.NET 자바스크립트 직렬화기
실제로 추한 방법이 있습니다. 컨테이너(Person/Article/Whatever) 클래스를 위한 JavaScript Converter를 만듭니다.
컨테이너:
public class Article
{
public int Id { get; set; }
public string Title { get; set; }
public DateTime Date { get; set; }
}
변환기:
public class ArticleJavaScriptConverter : JavaScriptConverter
{
public override IEnumerable<Type> SupportedTypes
{
get { return new Type[] { typeof(Article) }; }
}
public override object Deserialize(
IDictionary<string, object> dictionary,
Type type, JavaScriptSerializer serializer)
{
DateTime date =
DateTime.ParseExact(dictionary["date"] as string, "s", null);
return
new Article()
{
Id = (int)dictionary["id"],
Title = dictionary["title"] as string,
Date = date
};
}
public override IDictionary<string, object> Serialize(
object obj, JavaScriptSerializer serializer)
{
var article = obj as Article;
var result = new Dictionary<string,object>();
if (article != null)
{
this.SerializeInternal(article, result);
}
return result;
}
private void SerializeInternal(
Article article, IDictionary<string, object> result)
{
result.Add("id", article.Id);
result.Add("title", article.Title);
result.Add("date", article.Date.ToString("s"));
}
}
행복하게도...
var serializer = new JavaScriptSerializer();
serializer.RegisterConverters(
new JavaScriptConverter[] {
new ArticleJavaScriptConverter()
});
var expected = new Article()
{
Id = 3,
Title = "test",
Date = DateTime.Now
};
// {"id":3,"title":"test","date":"2009-12-02T05:12:00"}
var json = serializer.Serialize(article);
var actual = serializer.Deserialize<Article>(json);
Assert.AreEqual(expected, actual);
대답은, 자바스크립트 컨버터를 이런 식으로 사용할 수 없다는 것입니다.그것은 능력이 없습니다.
참고로:
Microsoft JSON 날짜를 포맷하려면 어떻게 해야 합니까? http://blog.stevenlevithan.com/archives/date-time-format
신경 쓰시겠지만, 제가 한 일은 자바스크립트 문자열 프로토타입에 이것을 코드로 쉽게 만들 수 있는 방법을 추가한 것입니다.
String.prototype.dateFromJSON = function () {
return eval(this.replace(/\/Date\((\d+)\)\//gi, "new Date($1)"));
};
이것은 코드의 고기에 사용하기에는 여전히 고통스럽습니다. 왜냐하면 당신은 항상 도처에 dateFromJSON()을 호출해야 하기 때문입니다.말도 안 되는 소리지
이것이 답을 하기에는 좀 늦었다는 것을 알고 있지만 최근에 이 문제에 대해 정말 좋은 해결책을 찾았습니다.다른 사람이 유용하다고 생각할 경우를 대비해 이 블로그 게시물에 기록되어 있습니다. http://icanmakethiswork.blogspot.co.uk/2012/04/beg-steal-or-borrow-decent-javascript.html
정말 바보같다는건 알지만 지금까지 이보다 더 좋은건...그래도 아직 알아보고 있으니 댓글은 환영입니다.
new JavaScriptSerializer().Serialize(DateTime.Now).Replace("\"\\/", "").Replace("\\/\"", "");
이렇게 하면 따옴표와 슬래시가 제거되므로 출력이 단순합니다.Date(123456789)
이것은 엄밀히 말하면 리터럴은 아니지만 브라우저는 문자열이 아닌 실제 날짜 값으로 이해합니다.
JSON에서는 이렇게 보일 겁니다.
{"myDate":Date(123456789)}
해킹 같은 거죠?만약 이것이 실제로 프로덕션 코드에 구현된다면, 저는 개인적으로 그것을 FormatForDates()와 같은 확장 방식으로 포장하거나, 직렬화기 자체를 장식자 패턴으로 포장하거나, 이 경우에는 "미장식자"로 포장할 것입니다.왜 이렇게 힘들어 보이는지 정말로 배를 놓쳤나 봅니다.나는 단지 데이트를 하고 싶어요, 여러분! :-p
@sambomartin의 답변을 vb.net 에서 변환했습니다.이 모든 공은 그에게 있습니다.vb.net 에 필요한 사람이 있을 경우를 대비해 여기에 붙여 넣었습니다.
재귀적으로 만들고 XmlElement 데이터 주석으로 기본 속성 이름을 재정의하는 기능도 추가했습니다. (XmlElementAttribute)
Imports System.Web.Script.Serialization
Imports System.Linq
Imports System.Globalization
Imports System.Xml.Serialization
Public Class ExtendedJavaScriptSerializer(Of T As New)
Inherits JavaScriptConverter
Private Const _dateFormat As String = "dd/MM/yyyy"
Public Overrides Function Deserialize(dictionary As IDictionary(Of String, Object), type As Type, serializer As JavaScriptSerializer) As Object
Dim p As New T()
Dim props = GetType(T).GetProperties()
For Each key As String In dictionary.Keys
Dim prop = props.Where(Function(x) x.Name = key).FirstOrDefault()
If prop IsNot Nothing Then
If prop.PropertyType = GetType(DateTime) Then
prop.SetValue(p, DateTime.ParseExact(CStr(dictionary(key)), _dateFormat, DateTimeFormatInfo.InvariantInfo), Nothing)
Else
prop.SetValue(p, dictionary(key), Nothing)
End If
End If
Next
Return p
End Function
Public Overrides Function Serialize(obj As Object, serializer As JavaScriptSerializer) As IDictionary(Of String, Object)
Dim serialized As IDictionary(Of String, Object) = New Dictionary(Of String, Object)
CheckProperties(obj, serialized)
Return serialized
End Function
Public Overrides ReadOnly Property SupportedTypes As IEnumerable(Of Type)
Get
Return {GetType(T)}
End Get
End Property
Private Sub CheckProperties(obj As Object, ByRef serialized As IDictionary(Of String, Object))
If obj Is Nothing Then Return
Dim objType As Type = obj.GetType()
For Each pi In objType.GetProperties()
' define serialization attribute name from '
' xmlelement dataannotation'
Dim displayname As String = pi.Name
Dim attrs() As Object = pi.GetCustomAttributes(True)
For Each attr In attrs
If GetType(XmlElementAttribute) = attr.GetType() Then
displayname = CType(attr, XmlElementAttribute).ElementName
End If
Next
' fix date format'
If pi.PropertyType = GetType(DateTime) Then
serialized(displayname) = CType(pi.GetValue(obj, Nothing), DateTime).ToString(_dateFormat)
Else
' recursive'
If pi.PropertyType.Assembly = objType.Assembly Then
CheckProperties(pi.GetValue(obj, Nothing), serialized)
Else
If pi.GetValue(obj, Nothing) IsNot Nothing Then
serialized(displayname) = pi.GetValue(obj, Nothing)
End If
End If
End If
Next
End Sub
Public Shared Function GetSerializer() As JavaScriptSerializer
Dim serializer As New JavaScriptSerializer
serializer.RegisterConverters({New ExtendedJavaScriptSerializer(Of T)})
Return serializer
End Function
End Class
Enum 속성 'type'과 'unit'을 가진 SensorReading 클래스가 Enum 값의 이름으로 직렬화되기를 원하는 비슷한 문제가 있었습니다. (Enum에 명시적인 숫자 값이 없는 경우 기본 결과는 0입니다.)
직렬화된 결과가 나오기 전에는 다음과 같이 표시됩니다.
[{"id":"0","type":0,"value":"44.00","unit":0}]
제가 원했던 것은 이것이었습니다.
[{"id":"0","type":"temperature","value":"44.00","unit":"C"}]
아래 예제 기능에서 객체를 직렬화하기 전에 커스텀 직렬화기 'EnumConverter<SensorReading>'을 등록합니다.
public static string ToSJSon(object obj)
{
var jss = new JavaScriptSerializer();
jss.RegisterConverters(new[] { new EnumConverter<SensorReading>() });
return jss.Serialize(obj);
}
다음은 일반 Enum Converter입니다.
public class EnumConverter<T> : JavaScriptConverter
{
public override IEnumerable<Type> SupportedTypes
{
get
{
return new[] { typeof(T) };
}
}
public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
{
throw new NotImplementedException(String.Format("'{0}' does not yet implement 'Deserialize", this.GetType().Name));
}
public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
{
IDictionary<string, object> serialized = new Dictionary<string, object>();
if (obj.GetType() == typeof(T))
{
if (obj.GetType().IsEnum)
{
serialized[obj.GetType().Name] = Enum.GetName(obj.GetType(), obj); ;
}
else
{
var sourceType = obj.GetType();
var properties = sourceType.GetProperties();
foreach (PropertyInfo property in properties)
{
if (property.CanRead)
{
if (property.PropertyType.IsEnum)
{
var str = Enum.GetName(property.PropertyType, property.GetValue(obj, null));
serialized[property.Name] = str;
}
else
{
serialized[property.Name] = property.GetValue(obj, null);
}
}
}
}
}
return serialized;
}
}
사용자 지정 직렬화기는 T 유형의 개체를 직렬화하고 직렬화에서 모든 판독 가능한 속성을 루프화한다고 알립니다.속성이 Enum일 경우 값 대신 이름을 사전으로 반환합니다.
이는 당사가 원하는 방식으로 직렬화되지 않는 다른 유형의 자산으로 확장될 수 있습니다.
사용자 지정 serializer(들) T가 Enum일 경우 별도의 테스트를 추가했습니다.그런 다음 대신 Enum 클래스의 이름과 그 값을 출력합니다.결과는 다음과 같습니다.
[{"id":"0","type":{"ReadingType":"temperature"},"value":"44.00","unit":{"ReadingUnit":"C"}}]
역직렬화를 계획하고 값이 어떤 Enum 유형에 속하는지 알고 싶다면 더 나은 출력이 될 수 있습니다.
link text 이 예제는 작동합니다.
JavaScriptSerializer serializer = new JavaScriptSerializer();
DateTime dt = DateTime.Now;
DateTime dt1 = dt;
string jsonDateNow = serializer.Serialize(dt1);
언급URL : https://stackoverflow.com/questions/1341719/custom-javascriptconverter-for-datetime
'programing' 카테고리의 다른 글
워드프레스 MYSQL 오류 (0) | 2023.10.24 |
---|---|
MySQL 보기만 볼 수 있고 다른 보기는 볼 수 없는 권한을 사용자에게 부여합니다. (0) | 2023.10.24 |
정적인 방법으로 캐시나 세션에 접근할 수 있는 방법이 있습니까? (0) | 2023.10.24 |
AngularJS 브라우저 언어 탐지를 사용하는 방법? (0) | 2023.10.24 |
SQL Server에서 latin1 varchar의 문자를 MariaDButf8에 삽입하려면 어떻게 인코딩해야 합니까? (0) | 2023.10.24 |