none
Returning a derived type from an abstract class method RRS feed

  • Question

  • So, I have read similar threads on this forum and I do not believe that there is an alternative way to do this, but I am hoping to get a direct answer to my specific situation...

    I have a base interface and a base class that implements that interface.  Within the abstract class I have a method that performs a conversion that converts an external type (that is returned by an external API) to an "internal" base type.  I would like to keep this class abstract as there is no reason for the type to ever be directly instantiated, but allowing this particular method to be strongly typed in derived classed results is some "unclean" code that technically could lead to inconsistent return types.  However, I do not think there is any other way to design this method.

    Code is below:

    public abstract class ObjectRefBase : ObjectBase, IObjectRefBase 
        {
            public static T ConvertFromApiBaseRefType<T>(IApiBaseRef b) where T : IObjectRefBase
            {
                
                CustomerRef c = new CustomerRef();
                T r = (T)(IObjectRefBase) c;
                r.FullName = b.FullName.GetValue();
                r.ListId = b.ListID.GetValue();
                return r;
            }
    
    }

    In the method, I basically create an instance of an object that derives from this base class and then downcast to the interface type and recast to the generic type.  It does not seem efficient or clean, however, c# does not allow T r=new T(); with a simple method signature of public T Convert(IBaseRef othertype);.  I would prefer not to have to implement this method in each derived type as there are about a dozen derived types and there are a handful of these types of conversion functions.

    any thoughts/suggestions? 

    I am hoping I am missing a different way to do this.

    Wednesday, October 8, 2014 6:04 PM

Answers

All replies

  • Have you considered the signature that allows ‘T r = new T()’?

    Wednesday, October 8, 2014 7:17 PM
  • I have no idea what you are trying to do, but start with this code, and change it where necessary:

    public class ObjectBase { }
    public interface IApiBaseRef
    {
        string FullName { get; set; }
        int ListId { get; set; }
    }
    
    public interface IObjectRefBase 
    {
        string FullName { get; set; }
        int ListId { get; set; }
    }
    
    public class CustomerRef : IObjectRefBase
    {
        public string FullName { get; set; }
        public int ListId { get; set; }
    }
    
    public abstract class ObjectRefBase : ObjectBase, IObjectRefBase
    {
        public string FullName { get; set; }
        public int ListId { get; set; }
    
        public static T ConvertFromApiBaseRefType<T>(IApiBaseRef b)
            where T : IObjectRefBase
        {
    
            CustomerRef c = new CustomerRef();
            try
            {
                T r = (T)(object)c;
                r.FullName = b.FullName;
                r.ListId = b.ListId;
                return r;
            }
            catch
            {
                return default(T);
            }
        }
    }
    

    Wednesday, October 8, 2014 7:46 PM
  • >c# does not allow T r=new T();

    It does if you add the new() constraint to the type.

    T Foo<T>() where T : new()
    {
        T r = new T();
        return r;
    }

    David


    David http://blogs.msdn.com/b/dbrowne/

    • Marked as answer by dcapone Wednesday, October 8, 2014 11:09 PM
    • Unmarked as answer by dcapone Wednesday, October 8, 2014 11:09 PM
    • Marked as answer by dcapone Wednesday, October 8, 2014 11:09 PM
    Wednesday, October 8, 2014 9:37 PM
  • If you want to only return types that derive from your abstract class, then why don't you use the abstract class as the generic constraint.  Using the interface does not necessarily guarantee that T will be a type derived from ObjectRefBase.  It only guarantees that T implements the interface.

    Rudy   =8^D


    Mark the best replies as answers. "Fooling computers since 1971."

    http://thesharpercoder.com/


    Wednesday, October 8, 2014 10:30 PM
    Moderator
  • >c# does not allow T r=new T();

    It does if you add the new() constraint to the type.

    T Foo<T>() where T : new()
    {
        T r = new T();
        return r;
    }

    David


    David http://blogs.msdn.com/b/dbrowne/


    You can also use a Factory Method to return instances of your derived classes, too, if you use an abstract class as a generic constraint.

    Mark the best replies as answers. "Fooling computers since 1971."

    http://thesharpercoder.com/

    Wednesday, October 8, 2014 10:35 PM
    Moderator
  • I'm completely lost. If the method is always going to return the same thing (a CustomerRef), why on Earth do you need generic types? What's wrong with something like this...

            public static IObjectRefBase ConvertFromApiBaseRefType(IApiBaseRef b)
            {
                
                CustomerRef c = new CustomerRef();
                c.FullName = b.FullName.GetValue();
                c.ListId = b.ListID.GetValue();
                return c;
            }

    Wednesday, October 8, 2014 10:35 PM
  • This is almost my code exactly. The issue is that if I have 2 derived types, CustomerRef and VendorRef (for example), the following would technically be allowed:

    VendorRef.Convert...<CustomerRef>(object);

    I guess the goal is to be able to code a base abstract class that can be called...

    VendorRef.Convert...(object)

    and the base method would return a "VendorRef" type because the typeof(this) would be "VendorRef" or in the case of the static method the class would be VendorRef.

    Wednesday, October 8, 2014 10:47 PM
  • Technically anything that implements the interface could be converted with the logic, but yes the abstract base class is probably a better constraint.
    Wednesday, October 8, 2014 10:52 PM
  • I'm completely lost. If the method is always going to return the same thing (a CustomerRef), why on Earth do you need generic types? What's wrong with something like this...

    I only create an instance of the CustomerRef to create an instance of an object that was derived from IObjectRefBase to be able to perform the conversion.

    The generic is used because numerous types are derived from that base class, VendorRef, for example, and I did not/do not want to have to implement the conversion function in each derived class when the logic is exactly the same.

    My problem could be solved switching from an abstract class to standard class and simply creating an instance of ObjectRefBase, assigning the properties and returning the base type, however, the ONLY time this base type should ever be used would be for this function, so I do not think that would be proper best practice design either.

    Wednesday, October 8, 2014 10:57 PM
  • Best answer.

    The new() constraint can be added to the method only which I didn't realize.  I thought it could only be used in class declarations.

    Still wish there was a way for the abstract method signature to simply be:

    public D Convert(IApiBase b);

    and it would know D was the derived type calling the method, without needing to explicitly state the type as is the case with generics.

    In essence making "T"/"D" a reserved type that meant the type was generic and matched the type calling the method.

    Wednesday, October 8, 2014 11:15 PM
  •         private D Convert<D>(IApiBase b) where D : ObjectRefBase
            {
                return default(D);
            }
            protected virtual ObjectRefBase Test(IApiBase data)
            {
                Type type = this.GetType();
                ObjectRefBase OB = this.Convert<TestClass>(data);
                return OB;
            }


    Rudy   =8^D

    Mark the best replies as answers. "Fooling computers since 1971."

    http://thesharpercoder.com/


    Thursday, October 9, 2014 12:58 AM
    Moderator