简体   繁体   中英

Defining a generic converter method in abstract base class

I've got a generic abstract base class for my logic objects, which basically looks like this:

public abstract class LogicClass<TDal>
    where TDal : DataClass, new()
{
    protected TDal _dalObj;

    protected LogicClass(TDal dalObj)
    { _dalObj = dalObj; }

    // basic properties and default methods for validating, deleting etc.
}

Inside it are several static methods, used to fetch data using my own ORM. They look like this:

    protected static List<T> GetList<T>(string whereStatement)
        where T : LogicClass<TDal>, new()
    {
        var dalObjList = DataManager.GetCollection<TDal>(whereStatement);
        return dalObjList.ConvertAll(dalObj => new T() { _dalObj = dalObj });
    }

Most of this works perfectly, but the problem is using the default constructor and then setting the data object, because the parameterless ctor is used in subclasses to set default properties when creating data (for example, the country is set to the default country when adding a client object).

Since I also can't use the ctor with the parameter using generic constraints, I thought of this solution:

    protected static List<T> GetListT>(Converter<TDal, T> creator, string whereStatement)
        where T : LogicClass<TDal>
    {
        var dalObjList = DataManager.GetCollection<TDal>(whereStatement);
        return dalObjList.ConvertAll<T>(creator);
    }

Which works, but I need to use this converter multiple times and don't feel like passing it multiple times.

So my question, is there a way to define this generic converter only once?

I thought of something like this:

    protected abstract Converter<TDal, LogicClass<TDal>> DalConverter;

.. but it makes more sense to make it static, and then I can't make it abstract anymore.

I could make a Dictionary<Type, Converter<TDal, LogicClass<TDal>>> but I'm afraid it would bring a performance penalty.

Any ideas?

You can put the Converter in a static variable inside a generic class and initialize it once during program startup.

A generic class produces a new type for each combination of generic type parameters and each of the produced types has an independent set of static variables. Meaning that StaticConverter<Type1,Type2>.Converter is a totally different static variable than StaticConverter<Type3,Type4>.Converter

    class StaticConverter<TDal, T>
        where T : LogicClass<TDal>
    {
        public static Converter<TDal, T> Converter;
    }

A class like the one above can be used in your code to retrieve the converter for any set of types. Something like return dalObjList.ConvertAll<T>(StaticConverter<TDal, T>.Converter);

It must be initialized for every type that that you want to convert with it (unless you have some conversion code that works generically, then you could define the converter generically in the static class).

The initialization looks like the following and needs to be done one time. Since the variables are static the values will be retained until the program ends.

 StaticConverter<User, UserLogic>.Converter = v => new UserLogic();
 StaticConverter<Client, ClientLogic>.Converter = v => new ClientLogic("Brazil");

Edit

You could create a default converter like I show below. This defines a default value for the converter that you can override for converters that you want to customize.

Now you can be sure that converter is set for all types but provide an updated converter for only the types that differ from the default.

    public static T GetLogic<TDal, T>(TDal item)
    {
        return default(T);
    }

    class StaticConverter<TDal, T>
        where T : LogicClass<TDal>
    {
        public static Converter<TDal, T> Converter = c => GetLogic<TDal, T>(c);
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM