C#使用泛型和动态关键字的继承

时间:2016-07-06 15:08:32

标签: c# generics dynamic

我实际上正在处理的问题与ASP.NET MVC中的映射器有关,但这太复杂了,无法在SO上发布,因此我简化了下面的问题。我将首先发布我的代码,因为它更容易解释我在代码之后想要实现的目标。

支持代码

public abstract class BaseFoo
{
    public int CommonProperty { get; set; }
}

public class Foo1 : BaseFoo
{
    public int SomeProperty { get; set; }
}

public class Foo2 : BaseFoo
{
    public int AnotherProperty { get; set; }
}

public interface IMyInterface<T>
{
    void SomeMethod(T t);
}

public abstract class BaseClass<T> : IMyInterface<T>
    where T : BaseFoo
{
    public virtual void SomeMethod(T t)
    {
        t.CommonProperty = 1;
    }
}

public class ConcreteClass1 : BaseClass<Foo1>
{
    public override void SomeMethod(Foo1 t)
    {
        t.SomeProperty = 57;
        base.SomeMethod(t);
    }
}

public class ConcreteClass2 : BaseClass<Foo2>
{
    public override void SomeMethod(Foo2 t)
    {
        t.AnotherProperty = 123;
        base.SomeMethod(t);
    }
}

public static class ConcreteClassFactory
{
    public enum ConcreteClassType
    {
        ConcreteClass1,
        ConcreteClass2
    }

    public static dynamic CreateClass(ConcreteClassType type)
    {
        dynamic toReturn = null;

        switch (type)
        {
            case ConcreteClassType.ConcreteClass1:
                toReturn = new ConcreteClass1();
                break;
            case ConcreteClassType.ConcreteClass2:
                toReturn = new ConcreteClass2();
                break;
            default:
                break;
        }

        return toReturn;
    }
}

我想要做的是动态创建不同的ConcreteClass并在该创建的对象上调用SomeMethod,基本上我想将ConcreteClass传递给BaseClass,就像你可以Foo传递BaseFoo一样。我已经使用以下代码:

class Program
{
    static void Main(string[] args)
    {
        BaseFoo foo = new Foo1();

        dynamic bar = ConcreteClassFactory.CreateClass(ConcreteClassFactory.ConcreteClassType.ConcreteClass1);

        bar.SomeMethod(foo as dynamic);
    }
}

然而,这似乎非常难以投射到一个动态(我也不完全理解为什么删除as dynamic抛出一个RuntimeBinderException,如果有人可以解释正在发生的事情,那将是值得赞赏的)。有没有更好的方法来实现我在这里要做的事情?

1 个答案:

答案 0 :(得分:1)

使用约束,我会做的是从被覆盖的SomeMethod中投射和抛出错误。

public abstract class BaseClass : IMyInterface<BaseFoo>
{
    public virtual void SomeMethod(BaseFoo t)
    {
        t.CommonProperty = 1;
    }
}

public class ConcreteClass1 : BaseClass
{
    public override void SomeMethod(BaseFoo t)
    {
        if(t == null)
            throw new ArgumentNullException(nameof(t));

        var foo1 = t as Foo1;
        if(foo1 == null)
            throw new NotSupportedException($"{nameof(ConcreteClass1)} does not support types other than {nameof(Foo1)}");

        foo1.SomeProperty = 57;
        base.SomeMethod(foo1);
    }
}

public class ConcreteClass2 : BaseClass
{
    public override void SomeMethod(BaseFoo t)
    {
        if (t == null)
            throw new ArgumentNullException(nameof(t));

        var foo2 = t as Foo2;
        if (foo2 == null)
            throw new NotSupportedException($"{nameof(ConcreteClass2)} does not support types other than {nameof(Foo2)}");

        foo2.AnotherProperty = 123;
        base.SomeMethod(foo2);
    }
}

public static class ConcreteClassFactory
{
    public enum ConcreteClassType
    {
        ConcreteClass1,
        ConcreteClass2
    }

    public static BaseClass CreateClass(ConcreteClassType type)
    {
        BaseClass toReturn = null;

        switch (type)
        {
            case ConcreteClassType.ConcreteClass1:
                toReturn = new ConcreteClass1();
                break;
            case ConcreteClassType.ConcreteClass2:
                toReturn = new ConcreteClass2();
                break;
            default:
                break;
        }

        return toReturn;
    }
}

一样使用
class Program
{
    static void Main(string[] args)
    {
        BaseFoo foo = new Foo1();

        var bar = ConcreteClassFactory.CreateClass(ConcreteClassFactory.ConcreteClassType.ConcreteClass1);

        bar.SomeMethod(foo);
    }
}