3
votes

Programming is fun!

I have created my own nullable class implementation as follows:

[DataContract]
public class Nullable<T> where T : struct
{
    public Nullable()
    {
    }

    internal T value;

    [DataMember]
    public bool HasValue { get; set; }

    [DataMember]
    public T Value
    {
        get
        {
            if (!this.HasValue)
                throw new Exception("Property have  no value");
            return this.value;
        }
        set
        {
            this.value = value;
            this.HasValue = true;
        }
    }

    public Nullable(T value)
    {
        Value = value;
    }

    public T GetValueOrDefault()
    {
        return this.value;
    }

    public T GetValueOrDefault(T defaultValue)
    {
        if (!this.HasValue)
            return defaultValue;
        return this.value;
    }

    public override bool Equals(object other)
    {
        if (!this.HasValue)
            return other == null;
        if (other == null)
            return false;
        return this.value.Equals(other);
    }

    public override int GetHashCode()
    {
        if (!this.HasValue)
            return 0;
        return this.Value.GetHashCode();
    }

    public override string ToString()
    {
        if (!this.HasValue)
            return "";
        return this.Value.ToString();
    }
}

Now in my WCF service when I create function which uses List of my custom nullable types,

[ServiceContract]
[XmlSerializerFormat]
public interface IService
{
    [OperationContract]
    List<Nullable<DateTime>> NullTest();
}

public class MyService : IService
{
    public List<Nullable<DateTime>> NullTest()
    {
        return new List<Nullable<DateTime>>()
        {
            new Nullable<DateTime>(DateTime.Now),
            new Nullable<DateTime>(DateTime.Now.AddDays(2))
        }; 
    }
}

I get following issue when above function gets called:

Managed Debugging Assistant 'FatalExecutionEngineError' has detected a problem in 'C:\Program Files (x86)\IIS Express\iisexpress.exe'.

Additional information: The runtime has encountered a fatal error. The address of the error was at 0x5bd1399e, on thread 0x2568. The error code is 0xc0000005. This error may be a bug in the CLR or in the unsafe or non-verifiable portions of user code. Common sources of this bug include user marshaling errors for COM-interop or PInvoke, which may corrupt the stack.

Help appreciated

I am using BasicHttpBinding

  <service name="MyService">
    <endpoint 
      address="" 
      binding="basicHttpBinding"
      name="BasicHttpEndpoint"
      bindingConfiguration=""
      contract="IMyService">
      <identity>
        <dns value="localhost" />
      </identity>
    </endpoint>
    <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
  </service>
1
System.Nullabe<T> is a struct, not a class. Not much point in having HasValue when you could have a variable of your type just assigned to null.juharr
But cshtml5 supports Nullable<T>Rabban

1 Answers

2
votes

EDIT:

It works with [XmlSerializerFormat] as long as you simply use Nullable<DateTime>, but NOT your implementation of Nullable<T>. So, the DataContractSerializer is giving your Nullable<T> implementation a pass, but the XmlSerializer is not.

Put another way, you have two options:

1) use DataContractSerializer + your Nullable<T> implementation;

2) use XmlSerializer + Nullable<DateTime>.

IService:

[ServiceContract]
[XmlSerializerFormat]
public interface IService1
{
    [OperationContract]
    List<Nullable<DateTime>> NullTest();
}

Service:

public class Service1 : IService1
{
    public List<Nullable<DateTime>> NullTest()
    {
        return new List<Nullable<DateTime>>()
        {
            new Nullable<DateTime>(DateTime.Now),
            new Nullable<DateTime>(DateTime.Now.AddDays(2))
        };
    }
}

Client:

class Program
{
    static void Main(string[] args)
    {
        try
        {
            Service1Client client = new Service1Client();

            ArrayOfDateTime result = client.NullTest();

            foreach (DateTime dt in result)
                Console.WriteLine(dt);

            Console.ReadLine();
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }
}

enter image description here


It works as long as you properly decorate your Nullable<T> with [DataContract] and [DataMember].

enter image description here

IService:

[ServiceContract]
public interface IService1
{

    [OperationContract]
    List<Nullable<DateTime>> NullTest();
}

[DataContract]
public class Nullable<T> where T : struct
{
    public Nullable()
    {
    }

    internal T value;

    [DataMember]
    public bool HasValue { get; set; }

    [DataMember]
    public T Value
    {
        get
        {
            if (!this.HasValue)
                throw new Exception("Property have  no value");
            return this.value;
        }
        set
        {
            this.value = value;
            this.HasValue = true;
        }
    }

    public Nullable(T value)
    {
        Value = value;
    }

    public T GetValueOrDefault()
    {
        return this.value;
    }

    public T GetValueOrDefault(T defaultValue)
    {
        if (!this.HasValue)
            return defaultValue;
        return this.value;
    }

    public override bool Equals(object other)
    {
        if (!this.HasValue)
            return other == null;
        if (other == null)
            return false;
        return this.value.Equals(other);
    }

    public override int GetHashCode()
    {
        if (!this.HasValue)
            return 0;
        return this.Value.GetHashCode();
    }

    public override string ToString()
    {
        if (!this.HasValue)
            return "";
        return this.Value.ToString();
    }
}

Service:

public class Service1 : IService1
{
    public List<Nullable<DateTime>> NullTest()
    {
        return new List<Nullable<DateTime>>()
        {
            new Nullable<DateTime>(DateTime.Now),
            new Nullable<DateTime>(DateTime.Now.AddDays(2))
        };
    }
}

Client:

class Program
{
    static void Main(string[] args)
    {
        Service1Client client = new Service1Client();

        NullableOfdateTime[] result = client.NullTest();

        foreach (NullableOfdateTime ndt in result)
            Console.WriteLine(ndt.Value);

        Console.ReadLine();
    }
}