tags:

views:

69

answers:

3

Hi,

I have certain classes that have common feature - class factory that I need to put into base class.

// This class needs to be designed
public class Base
{
    // this function is no good because it returns object, and needs to return derived class
    static object Create(byte[] data)
    {
        MemoryStream ms = new MemoryStream(data);
        BinaryFormatter sf = new BinaryFormatter();

        object result = sf.Deserialize(ms);
        ms.Close();

        return result;
    }

    public virtual byte[] Serialize()
    {
        MemoryStream ms = new MemoryStream();
        BinaryFormatter bf = new BinaryFormatter();
        bf.Serialize(ms, this);
        byte[] result = ms.ToArray();
        ms.Close();
        return result;
    }

}

// for this class Create() must return Derived1
public Derived1 : Base
{
}

// for this class Create() must return Derived2
public Derived2 : Base
{
}

I need to be able to use derived class factory like that

Derived1 d1 = Derived1.Create(data1);

Derived2 d2 = Derived2.Create(data2);

Please advice solution. The templates are ok

UPDATE

I update the code and showed how objects are serialized and deserialized

+2  A: 
public class Base<T>
{
    public static T Create(byte[] data)
    {
        // create instance of T from data
    }
}

public Derived1 : Base<Derived1>
{
}

public Derived2 : Base<Derived2>
{
}
LukeH
You probably need `where T : new()`.
SLaks
@SLaks: Probably, but without more details it's impossible to say for sure.
LukeH
@LukeH: But it's clear that he wants to create objects in the factory, which means at some point the factory will need `new()`
chiccodoro
@chiccodoro: Not necessarily. Many factories use reflection to do their thing using private and/or non-default constructors etc. I'm sure that some kind of generic constraint will probably be required, and it most probably will be `new()`, but that's not certain from the information given in the question.
LukeH
@chiccodoro: There you go... The OP has edited the question and they're deserialising using `BinaryFormatter`, so no `new()` constraint needed.
LukeH
Actually I need "where T : class" constraint to be able to use T result = sf.Deserialize(ms) as T;
Captain Comic
@Captain Comic: Or you could just do `T result = (T)sf.Deserialize(ms);` instead.
LukeH
You'll probably also want Base<T> to inherit from a non-generic Base, or you are going to run into polymorphism problems.
DanDan
@LukeH, agree but then I have to care about exceptions
Captain Comic
@Captain Comic: True. How you do it is up to you. My own preference would usually be an exception when the construction failed, rather than silently returning null.
LukeH
@LukeH: Wow, I was thinking you need a new() even for deserializing an object. Silly me, of course not, otherwise all objects without a default constructor wouldn't be serializable.
chiccodoro
+1  A: 

Your design is fine, you just need just add a Template(with class constraint)

public class Base<T> where T: class
{
  public   static T Create(byte[] data)
  {
    MemoryStream ms = new MemoryStream(data);
    BinaryFormatter sf = new BinaryFormatter();

    T result = sf.Deserialize(ms) as T;
    ms.Close();

    return result;
  }
}

public Derived1 : Base<Derived1>
{
}

public Derived2 : Base<Derived2>
{
}
Nix
+1  A: 

If what you want is to create a persisten object using dot Net Serialization you could use the following code to achieve the same result. Notice that the CSSerialize defines the two methods for serializing objects using a BinaryFormatter and a SoapFormatter:

namespace TheCompany.Common
{
    public interface IGenericFormatter
    {
        T Deserialize<T>(Stream serializationStream);
        void Serialize<T>(Stream serializationStream, T graph);
    }
    public class GenericFormatter<F> : IGenericFormatter where F : IFormatter, new()
    {
        private IFormatter _Formatter = new F();
        public T Deserialize<T>(Stream serializationStream) { return (T)_Formatter.Deserialize(serializationStream); }
        public void Serialize<T>(Stream serializationStream, T graphObject) { _Formatter.Serialize(serializationStream, graphObject); }
    }
    public class GenericBinaryFormatter : GenericFormatter<BinaryFormatter> { }
    public class GenericSoapFormatter : GenericFormatter<SoapFormatter> { }

    public static partial class CSSerialize
    {
        public static T Clone<T>(T source)
        {   
            Debug.Assert(typeof(T).IsSerializable);
            if (!typeof(T).IsSerializable) { throw new SerializationException(ExceptionMessages.ObjectNoSerializable); }

            T result;
            IGenericFormatter formatter = new GenericBinaryFormatter();            
            using(MemoryStream stream = new MemoryStream())
            {                
                formatter.Serialize(stream, source);
                stream.Seek(0, SeekOrigin.Begin);
                result = formatter.Deserialize<T>(stream);
            }
            return result;
        }
        public static T CloneXml<T>(T source)
        {
            T result;
            DataContractSerializer serializer = new DataContractSerializer(typeof(T));
            using (MemoryStream memory = new MemoryStream())
            {
                serializer.WriteObject(memory, source);
                memory.Position = 0;
                result = (T)serializer.ReadObject(memory);             
            }
            return result;
        }       
    }
}
ArceBrito