Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
55 views
in Technique[技术] by (71.8m points)

c# - Different function parameters for child classes

I have a few classes-services that most of them share common code. So I created a parent class and they all inherit and override the functions when needed.

abstract class MyServiceBase<T>
    where T : class, IEntityBase, new()
{
    protected readonly IUnitOfWork _uow;
    protected MyServiceBase(IUnitOfWork uow)
    {
        _uow = uow;
    }

    public virtual IEnumerable<T> GetAll()
    {
        return _uow.GetRepository<T>().GetAll();
    }

    // more methods here needed for all the services that they are mostly the same for the subclasses but alot of them share the same problem
}

class AssetService : MyServiceBase<Asset>
{
    public AssetService(IUnitOfWork uow) : base(uow) { }
}

The problem comes when some services need more parameters to get the items.

class AssetCostService : MyServiceBase<AssetCost>
{
    public AssetCostService(IUnitOfWork uow) : base(uow) { }

    public virtual IEnumerable<AssetCost> GetAll(int asset)
    {
        return _uow.GetRepository<AssetCost>().GetAll();
    }
}

Now I can either not use the base class (MyServiceBase) or I will have multiple GetAll() for the same item. One way to work around it is to use params as parameters for the function.

abstract class MyServiceBase<T>
    where T : class, IEntityBase, new()
{
    protected readonly IUnitOfWork _uow;
    protected MyServiceBase(IUnitOfWork uow)
    {
        _uow = uow;
    }

    public virtual IEnumerable<T> GetAll(params int[] parameters)
    {
        return _uow.GetRepository<T>().GetAll();
    }
}

class AssetService : MyServiceBase<Asset>
{
    public AssetService(IUnitOfWork uow) : base(uow) { }
}

class AssetCostService : MyServiceBase<AssetCost>
{
    public AssetCostService(IUnitOfWork uow) : base(uow) { }

    public override IEnumerable<AssetCost> GetAll(params int[] parameters)
    {
        if (parameters.Length != 1)
            throw new System.Exception("AssetId is not defined!");

        return _uow.GetRepository<AssetCost>().GetAll(i => i.AssetId == parameters[0]);
    }
}

The problem with this is that I have to remember which parameters are required and it gets very complicated if parameters are the same (e.g. int and string), some are optional, etc.

Is there any way I can achieve this type of inheritance, without duplicated code for each type of nesting or a nice way around it?


Edit

As pointed in the comments, I might be trying to find a solution to a problem I wouldn't have if I used a strategy other than inheritance. So I'll try to explain why I went to that type of implementation and maybe somebody can point me to a different strategy for implementing the same thing.

My basic idea is to write a base class that does most of the things that all derived classes need. That way the derived class would not need to implement the same thing over and over and I can have minimal classes with Generics that they "automatically" have all the necessary functions.

For example an implementation of the Add() function that gets a DTO, adds it to the DB and returns the DTO back.

protected virtual ActionResult Put(TBaseDto dto, params int[] parameters)
{
    Initialize(parameters);

    TBase _i = GetSingleFromRepo(parameters);

    if (_i == null)
        throw new NotFoundException();

    UpdateChecks(dto, _i, parameters);

    MapDtoDataForEdit(dto, _i);

    ItemSpecificRules(dto, _i, false, parameters);

    SaveChanges();

    TBaseDto ret = _mapper.Map<TBaseDto>(_i);

    if (HasCustomMapping)
        CustomMapping(_i, ret);

    return ret;
}

And then have virtual functions for each call, so that child classes can implement their needs.

protected virtual void Initialize(params int[] parameters) { }
protected virtual void ItemSpecificRules(TBaseDto dto, TBase _new, bool isNew = false, params int[] parameters) { }
protected virtual void GetChecks(params int[] parameters) { }
protected virtual Base GetSingleFromRepo(params int[] parameters)
{
    return _repository.GetSingle(i => i.Id == parameters[0]);
}
protected bool HasCustomMapping { get; set; }
protected virtual void CustomMapping(TBase Base, TBaseDto Dto) { }

Likewise I have implementations for Get, Edit, Delete functions.

This type of implementation allows me to create some of my services just by inheriting the base and writing no additional code.

class AssetService : MyServiceBase<Asset>
{
    public AssetService(IUnitOfWork uow) : base(uow) { }
}

Most of them override only ItemSpecificRules and almost none of them overrides the Add method (only one from around 200 services).

Also when I need to change the Add, like adding a new check or something, I get to do it only once, in the Base (and the override, if needed).

Maybe my initial way of thinking led me to a dead end and I should change my strategy. I am restructuring my project either way, so I am open to suggestions!

question from:https://stackoverflow.com/questions/65942983/different-function-parameters-for-child-classes

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)
Waitting for answers

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...