3

クレジットカードの詳細を表すクラスがあります。有効な開始日と有効期限の月と年を表すために、 type の 4 つのプロパティを使用していますint

public int ValidFromMonth { get; set; }
public int ValidFromYear { get; set; }
public int ExpiresEndMonth { get; set; }
public int ExpiresEndYear { get; set; }

サードパーティが使用できるように、このクラスを XML シリアライズしています。そのサード パーティは、値が 10 未満の場合、月と年の値の前に 0 を付ける必要があります。

<validFromMonth>02</validFromMonth>
<validFromYear>09</validFromYear>
<expiresEndMonth>10</expiresEndMonth>
<expiresEndYear>14</expiresEndYear>

.NET は、おそらくフォーマット文字列 (例: ) を使用して、この規則を適用する属性をサポートしていますか (またはカスタム属性を作成することは可能{0:00}ですか)?

注:string内部で書式設定を行う独自のプロパティを追加[XmlIgnore]し、プロパティに属性を追加できることはわかっていintますが、これは二流のソリューションのように感じます。

編集: いくつかの検討の後、これが実際に実現可能ではないかどうか疑問に思っています. シリアル化は問題ありませんが、逆シリアル化が機能するには、シリアル化された文字列のフォーマットを解除する必要があります。上記の些細な例では、これは簡単ですが、より一般的なケースで機能するようになるかどうかはわかりません。

Edit2: 2 桁の要件を定義する XML スキーマは以下のとおりです。

単純型定義:

<xs:simpleType name="CreditCardMonthType">
  <xs:annotation>
   <xs:documentation>Two digit month</xs:documentation>
  </xs:annotation>
  <xs:restriction base="xs:string">
   <xs:minLength value="2" />
   <xs:maxLength value="2" />
  </xs:restriction>
 </xs:simpleType>
<xs:simpleType name="CreditCardYearType">
  <xs:annotation>
   <xs:documentation>Two digit year</xs:documentation>
  </xs:annotation>
  <xs:restriction base="xs:string">
   <xs:minLength value="2" />
   <xs:maxLength value="2" />
  </xs:restriction>
</xs:simpleType>

これらのタイプを使用するクレジット カードの定義:

<xs:attribute name="ExpiryMonth" type="CreditCardMonthType" use="required">
 <xs:annotation>
  <xs:documentation>Credit/debt card's expiry month.</xs:documentation>
 </xs:annotation>
</xs:attribute>
<xs:attribute name="ExpiryYear" type="CreditCardYearType" use="required">
 <xs:annotation>
  <xs:documentation>Credit/debt card's expiry year.</xs:documentation>
 </xs:annotation>
</xs:attribute>
<xs:attribute name="StartMonth" type="CreditCardMonthType" use="optional">
 <xs:annotation>
  <xs:documentation>Switch card's start month.</xs:documentation>
 </xs:annotation>
</xs:attribute>
<xs:attribute name="StartYear" type="CreditCardYearType" use="optional">
 <xs:annotation>
  <xs:documentation>Switch card's start year.</xs:documentation>
 </xs:annotation>
</xs:attribute>
4

4 に答える 4

3

これは多くのコードですが、必要なことは実行します。要点は、新しいクラス (LeadingZeroこの例では) をIXmlSerializable作成し、XML ストリームからの読み取り/書き込み方法を制御するために実装できることです。お役に立てれば:

    using System;
    using System.IO;
    using System.Xml.Serialization;

namespace StackOverflow
{
    [Serializable]
    public class LeadingZero : IXmlSerializable
    {
        public int Value { get; set; }

        public LeadingZero()
        {
            Value = 0;
        }

        public LeadingZero(int value)
        {
            this.Value = value;
        }

        public override string ToString()
        {
            return Value.ToString("00");
        }

        #region IXmlSerializable Members

        public System.Xml.Schema.XmlSchema GetSchema()
        {
            return null;
        }

        public void ReadXml(System.Xml.XmlReader reader)
        {
            string s = reader.ReadElementString();
            int i;
            if (int.TryParse(s, out i))
            {
                Value = i;
            }
        }

        public void WriteXml(System.Xml.XmlWriter writer)
        {
            writer.WriteString(Value.ToString("00"));
        }

        #endregion
    }

    [Serializable]
    public class Complex
    {
        public LeadingZero ValidFromMonth { get; set; }
        public LeadingZero ValidFromYear { get; set; }
        public LeadingZero ExpiresEndMonth { get; set; }
        public LeadingZero ExpiresEndYear { get; set; }
    }

    class Program
    {
        static void Main()
        {
            var seven = new LeadingZero(7);

            XmlSerializer xml = new XmlSerializer(typeof(LeadingZero));

            StringWriter writer;

            writer = new StringWriter();
            xml.Serialize(writer, seven);

            string s = writer.ToString();

            Console.WriteLine(seven);
            Console.WriteLine();
            Console.WriteLine(s);

            Console.WriteLine();
            var newSeven = xml.Deserialize(new StringReader(s)) as LeadingZero;
            Console.WriteLine(newSeven ?? new LeadingZero(0));

            var complicated = new Complex()
            {
                ValidFromMonth = new LeadingZero(7),
                ValidFromYear = new LeadingZero(2009),
                ExpiresEndMonth = new LeadingZero(6),
                ExpiresEndYear = new LeadingZero(2010)
            };

            Console.WriteLine();
            writer = new StringWriter();

            xml = new XmlSerializer(typeof(Complex));
            xml.Serialize(writer, complicated);
            s = writer.ToString();
            Console.WriteLine(s);

            var newComplicated = xml.Deserialize(new StringReader(s)) as Complex;
            if (newComplicated != null)
            {
                Console.WriteLine();
                Console.WriteLine("Woo hoo!");
            }

            Console.ReadLine();
        }
    }
}

これは私が得た出力です:

07

<?xml version="1.0" encoding="utf-16"?>
<LeadingZero>07</LeadingZero>

07

<?xml version="1.0" encoding="utf-16"?>
<Complex xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http:/
/www.w3.org/2001/XMLSchema">
  <ValidFromMonth>07</ValidFromMonth>
  <ValidFromYear>2009</ValidFromYear>
  <ExpiresEndMonth>06</ExpiresEndMonth>
  <ExpiresEndYear>2010</ExpiresEndYear>
</Complex>

Woo hoo!
于 2009-04-24T16:48:13.493 に答える
3

OK、以前のコード サンプルは無視してください (ただし、他の人の役に立つかもしれないのでそのままにしておきます)。XmlEnumAttributeを使用してこれを行うことができることを思い出しました:

public enum LeadingZeroMonth
{
    [XmlEnum("01")]
    January,

    ...

    [XmlEnum("12")]
    December
}

次に、使用法を列挙型に変更します。

public LeadingZeroMonth ValidFromMonth { get; set; }

月の列挙型ができたので、これは実際には非常に良い方法です (これは実際に最初から行うべきことです)。

于 2009-04-26T04:49:57.197 に答える
1

この種の要件は、多くの場合、XML を理解していない企業からもたらされます。ここでこれが事実であると仮定するのではなく、私は尋ねます: 彼らは先行ゼロ日フォーマットを記述する XML スキーマを提供しましたか? もしそうなら、その日を定義する部分を投稿していただけますか?


編集に基づく編集

スキーマを投稿していただきありがとうございます。それは私が心配していたもう一つのことを確認しました。あなたの整数は整数ではありません。に注意してください<restriction base="xs:string"/>。これらは整数ではなく文字列です。

于 2009-04-27T08:52:15.483 に答える
1

XmlEnum を使用する欠点は、null を許容できないことです。

私はお勧めします

    [XmlIgnore]
    private int? _startMonth;

    /// <remarks/>
    [XmlAttributeAttribute]
    public string StartMonth
    {
        get { return _startMonth == null ? null : _startMonth.ToString().PadLeft(2, '0'); }
        set { _startMonth = string.IsNullOrEmpty(value) ? (int?)null : int.Parse(value); }
    }

これにより、属性をヌル可能にすることができます

于 2009-04-30T11:29:19.870 に答える