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

本文关键字:继承 关键字 动态 泛型 | 更新日期: 2023-09-27 17:55:14

我实际正在处理的问题与 MVC 中的映射器有关 ASP.NET 但这太复杂了,无法在 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 s传递为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,如果有人能解释发生了什么,那将不胜感激)。有没有更好的方法来实现我在这里想要做的事情?

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

有了约束,我要做的是从被覆盖的 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);
    }
}