3

这是一件肮脏的事情,我为此感到肮脏:

public abstract class InterestRate {

    // irrelevant details

    public static T ImpliedRate<T>(
        double factor,
        double time,
        DayCounter dayCounter
    ) where T : NonCompoundedInterestRate {
        MethodInfo methodInfo = typeof(T).GetMethod(
            "ImpliedRate",
            BindingFlags.Static);
        return (T)methodInfo.Invoke(
            null,
            new object[] { factor, time, dayCounter }
        );
    }

    public static T ImpliedRate<T>(
        double factor,
        double time,
        DayCounter dayCounter,
        Frequency frequency
    ) where T : CompoundedInterestRate {
        MethodInfo methodInfo = typeof(T).GetMethod(
            "ImpliedRate",
            BindingFlags.Static);
        return (T)methodInfo.Invoke(
            null,
            new object[] { factor, time, dayCounter, frequency }
        );
}

在这里,我有类NonCompoundedInterestRate(抽象)并CompoundedInterestRate派生自抽象类InterestRate。我有几个具体的实现,NonCompoundedInterestRate它们具有使用适当签名命名的静态方法ImpliedRate,以使上述反射起作用。

使用反射来调用甚至不能保证在派生类上存在的静态方法只是臭气熏天。有没有更好的方法来处理这个?

4

6 回答 6

2

你应该感到肮脏。这里有一些肥皂:

public static class InterestRateFactories
{
    static InterestRateFactories()
    {
        _factories = new List<IInterestRateFactory>();
        //  register default factories, although you can also register them elsewhere, like in your ioc setup
    }
    private static readonly List<IInterestRateFactory> _factories;
    public static void RegisterFactory(IInterestRateFactory factory)
    {
        _factories.Add(factory);
    }
    public static T ImpliedRate<T>(double factor, double time, DayCounter dayCounter)
        where T : NonCompoundedInterestRate
    {
        var factory = _factories.FirstOrDefault(x => x.CanCreate(typeof(T), false));
        if (factory == null)
        {
            throw new NotSupportedException("Cannot create a non-compounded implied interest rate of type " + typeof(T).Name);
        }
        return (T)factory.Create(factor, time, dayCounter);
    }
    public static T ImpliedRate<T>(double factor, double time, DayCounter dayCounter, Frequency frequency)
        where T : CompoundedInterestRate
    {
        var factory = _factories.FirstOrDefault(x => x.CanCreate(typeof(T), false));
        if (factory == null)
        {
            throw new NotSupportedException("Cannot create a compounded implied interest rate of type " + typeof(T).Name);
        }
        return (T)factory.Create(factor, time, dayCounter, frequency);
    }
}

public interface IInterestRateFactory
{
    bool CanCreate(Type nonCompoundedInterestRateType, bool compounded);
    NonCompoundedInterestRate Create(double factor, double time, DayCounter dayCounter);
    CompoundInterestRate Create(double factor, double time, DayCounter dayCounter, Frequency frequency);
}
于 2011-02-14T02:01:49.433 回答
1

根据我的经验,您只能实例化泛型的无参数构造函数。

你想要达到的目标只能通过反思来完成。

于 2009-11-10T12:30:14.583 回答
1

似乎调用者可以轻松地调用派生类上的工厂方法,就像调用将派生类型作为 T 传递的此方法一样容易。

这里稍微更明确的约定是向 T 添加一个 new() 约束,调用默认 ctor,然后调用在基类上定义的 Init 抽象方法。

工厂模式具有可测试性优势,但不像您在这里使用的那样。第三种选择是让调用者传递一个工厂类的实例来使用(ImpliedRate 方法将在工厂接口上)。这对于单元测试来说很方便,但对于 API 的使用者来说可能很麻烦。

于 2009-11-10T05:31:27.953 回答
1

除了静态方法,您还可以使用普通方法和修改后的克隆/原型模式之类的东西。例如:

public static class InstanceMap
{
    private static readonly Dictionary<Type,object> instances = 
        new Dictionary<Type,object>();

    public static void AddInstance(object instance)
    {
        instances[instance.GetType()] = instance;
    }

    public static T GetInstance<T>() { return (T) instances[typeof(T)]; }  
}

public interface INonCompoundedInterestRate
{
    INonCompoundedInterestRate ImpliedRate(double factor,
        double time,
        DayCounter dayCounter);
}

public class MyNonCompoundedInterestRate: INonCompoundedInterestRate
{
    public INonCompoundedInterestRate ImpliedRate(double factor,
        double time,
        DayCounter dayCounter) { /* do smth*/ }

    static MyNonCompoundedInterestRate()
    {
        InstanceMap.AddInstance(new MyNonCompoundedInterestRate());
    } 
} 

public abstract class InterestRate {
    public static T ImpliedRate<T>(
        double factor,
        double time,
        DayCounter dayCounter
    ) where T : INonCompoundedInterestRate 
    {
        return InstanceMap.GetInstance<T>().
            ImpliedRate(factor, time, dayCounter);
    }
    // ...
}
于 2009-11-10T10:51:54.407 回答
1

尝试将静态(工厂)方法与继承混合时,您总是会遇到冲突。很难获得您正在寻找的多态行为。我有一个类似的问题,目前正在使用反射。如前所述,另一种选择是在不需要时不使用静态方法。然后,您可能可以使用模板方法,或任何其他可以很好地与继承配合使用的策略。

于 2009-11-10T20:31:34.160 回答
0

有什么理由不只是在泛型基础上声明的非泛型接口上定义它们,然后对 T 进行强制转换?我没有看到任何通用参数被传递......

于 2009-11-10T05:07:23.963 回答