用于派生功能的增强基类方法 - 减少代码

时间:2013-12-18 16:00:46

标签: c# instance derived-class

典型情况如下。

class ServiceBase
{
    public virtual InstanceBase GetObject() { return null; }
}

class ServiceA : ServiceBase
{
    public override InstanceBase GetObject()
    {
        var v = new InstanceA();
        v.Method();
        return v;
    }
}

class ServiceB : ServiceBase
{
    public override InstanceBase GetObject()
    {
        var v = new InstanceB();
        v.Method();
        return v;
    }
}

class InstanceBase
{
    public virtual void Method() { }
}

class InstanceA : InstanceBase
{
    public override void Method(){}
}

class InstanceB : InstanceBase
{
    public override void Method() { }
}

不同的服务处理不同的实例类。但是GetObject的代码对于所有服务都是类似的。我想通过扩展基类'执行最多的GetObject方法来减少代码库。

class ServiceBase
{
     public virtual InstanceBase GetObject<T>()
     {
         var v= (InstanceBase)Activator.CreateInstance(typeof(T), new object[] { });
         v.Method();
         return v;
     }
}

这似乎是一种实现方式。但是我不太担心使用反射,因为它可能会遇到性能问题。有没有更好的方法来实现这一目标?

3 个答案:

答案 0 :(得分:5)

是的,有两种方式:

1)通用方法:

class ServiceBase<T> where T : InstanceBase, new()
{
    public InstanceBase GetObject() //you can make the return type even 'T'
    {
        var v = new T();
        v.Method();
        return v;
    }
}

class ServiceA : ServiceBase<InstanceA> 
{

}

class ServiceB : ServiceBase<InstanceB> 
{

}

这更好,因为它具有最少的代码重复,但我不确定通用性是否会成为一个麻烦。

2)如果不适合,您可以要求基类提供自己的InstanceBase。这看起来更简洁。像:

abstract class ServiceBase
{
    public abstract InstanceBase Instance { get; }

    public InstanceBase GetObject() //you can make the return type even 'T'
    {
        Instance.Method();
        return Instance;
    }
}

class ServiceA : ServiceBase 
{
    public override InstanceBase Instance { get; } //return new InstanceA() here
}

class ServiceB : ServiceBase
{
    public override InstanceBase Instance { get; } //return new InstanceB() here
}

现在,从重写的属性Instance返回InstanceBase的新实例或已经实例化的实例。这取决于你的逻辑,但是从所显示的方法来看,你每次都必须返回一个新的实例。


哪种适合你取决于你的背景。不管是什么,请考虑一下:

1)这种做法很糟糕。

 public virtual InstanceBase GetObject<T>()
 {
     var v= (InstanceBase)Activator.CreateInstance(typeof(T), new object[] { });
     v.Method();
     return v;
 }

首先,你必须在调用函数时指定类型参数,二,每个人都有可能把事情搞得一团糟。

ServiceA a = new ServiceA();
a.GetObject<InstanceB>(); // not probably what you want.

2)在任何情况下,如果你想要它,你可以为泛型类型参数new()提供T约束。

3)如果要使用默认构造函数进行实例化,则无需指定空参数集合。这样做:

var v= (InstanceBase)Activator.CreateInstance(typeof(T));
// or just new T();

4)您似乎没有在GetObject方法中使用任何实例成员。如果是这种情况,那么您可以使用静态方法。这应该是静态的还是非静态的,取决于您想要进行的调用。请记住static

public static InstanceBase GetObject() //you can make the return type even 'T'
{
    var v = new T();
    v.Method();
    return v;
}

//can call like this too:
ServiceA.GetObject(); //etc

答案 1 :(得分:2)

只需指定T是可以实例化的类:

public virtual InstanceBase GetObject<T>() where T : class, new()

然后,您可以在不使用反射的情况下实例化对象:

T myInstance = new T();

答案 2 :(得分:0)

性能肯定会受到打击。请考虑以下代码:

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Create 1MM ServiceA...");

        var sw = new Stopwatch();
        sw.Start();
        for (int i = 0; i < 1000000; i++)
        {
            var o = new ServiceA();
            var obj = o.GetObject();
        }
        sw.Stop();

        Console.WriteLine("{0} ms", sw.ElapsedMilliseconds);
        Console.WriteLine();

        Console.WriteLine("Create 1MM ServiceB...");

        sw = new Stopwatch();
        sw.Start();
        for (int i = 0; i < 1000000; i++)
        {
            var o = new ServiceB();
            var obj = o.GetObject();
        }
        sw.Stop();

        Console.WriteLine("{0} ms", sw.ElapsedMilliseconds);
        Console.WriteLine();

        Console.WriteLine("Create 1MM GenericServiceA...");

        sw= new Stopwatch();
        sw.Start();
        for (int i = 0; i < 1000000; i++)
        {
            var o = new GenericServiceBase();
            var obj = o.GetObject<ServiceA>();
        }
        sw.Stop();

        Console.WriteLine("{0} ms", sw.ElapsedMilliseconds);
        Console.WriteLine();

        Console.WriteLine("Create 1MM GenericServiceB...");

        sw = new Stopwatch();
        sw.Start();
        for (int i = 0; i < 1000000; i++)
        {
            var o = new GenericServiceBase();
            var obj = o.GetObject<ServiceB>();
        }
        sw.Stop();

        Console.WriteLine("{0} ms", sw.ElapsedMilliseconds);
        Console.WriteLine();
    }
}

class GenericServiceBase
{
    public virtual InstanceBase GetObject<T>()
        where T : ServiceBase
    {
        var v = (ServiceBase)Activator.CreateInstance(typeof(T), new object[] { });
        return v.GetObject();
    }
}

class ServiceBase
{
    public virtual InstanceBase GetObject() { return null; }
}

class ServiceA : ServiceBase
{
    public override InstanceBase GetObject()
    {
        var v = new InstanceA();
        v.Method();
        return v;
    }
}

class ServiceB : ServiceBase
{
    public override InstanceBase GetObject()
    {
        var v = new InstanceB();
        v.Method();
        return v;
    }
}

class InstanceBase
{
    public virtual void Method() { }
}

class InstanceA : InstanceBase
{
    public override void Method() { }
}

class InstanceB : InstanceBase
{
    public override void Method() { }
}

及其输出:

Create 1MM ServiceA...
34 ms

Create 1MM ServiceB...
33 ms

Create 1MM GenericServiceA...
1226 ms

Create 1MM GenericServiceB...
1255 ms

更新:如果您在约束中使用new关键字加入小技巧,则会得到以下结果:

Create 1MM ServiceA...
35 ms

Create 1MM ServiceB...
32 ms

Create 1MM GenericServiceA...
182 ms

Create 1MM GenericServiceB...
177 ms

超过1MM的性能并不差,但它仍然存在。