如何强制实施嵌套 class 属性?

How to enforce implementation of nested class properties?

我正在尝试在 Blazor WASM 中实现我自己的多语言功能。没什么特别的,但我想确保我不会忘记用特定语言实现属性。在 TypeScript 中,这适用于键入或接口对象。在 C# 中,此类对象的等效项是 class。我尝试在 C# 中使用接口和抽象 classes,但没有得到想要的结果。

期望的结果是我的代码编辑器在我忘记实现 属性 时提示。我该如何进行?

我可以将所有属性直接放入 Translation class 中以强制执行它们,但是我会有一个很长的属性列表,我宁愿将它们切碎位.

    public class NavMenuProps
    {
        public string FirstMenuHeader { get; set; } = "Dogs";
        public string SecondMenuHeader { get; set; } = "Facilities";
        public string ThirdMenuHeader { get; set; } = "Profile";
    }
    
    public abstract class Translation
    {
        public abstract NavMenuProps NavMenu();
    }
    
    public class English : Translation
    {
        public override NavMenuProps NavMenu()
        {
            return new NavMenuProps();
        }
    }
        
    public class Dutch : Translation
    {
        public override NavMenuProps NavMenu()
        {
            return new NavMenuProps
            {
                FirstMenuHeader = "Honden",
                SecondMenuHeader = ""
            };
        }
    }

    public class French : Translation
    {
        public override NavMenuProps NavMenu()
        {
            throw new System.NotImplementedException();
        }
    }

在 TypeScript 中它会像这样工作:


type TNavMenuProps = {
    firstMenuHeader: string;
    secondMenuHeader: string;
    thirdMenuHeader: string;
    ...
}

type TLoginPageProps = {
    firstLabel: string;
    secondLabel: string;
    ...
}

type TTranslation = {
    navMenu: TNavMenuProps;
    loginPage: TLoginPageProps;
    ...
}

const englishTranslations: TTranslation = {
    navMenu: {
        firstMenuHeader: "first";
        secondMenuHeader: "second";
        // Would complain I forgot "thirdMenuHeader".
    },
    loginPage: {
        firstLabel: "1st label";
        secondLabel: "2nd label";
    },
    ...
}

如果我正确理解了您的要求,这可能是一种方法:制作 NavMenuProps abstract,并在 Translation 中实现 NavMenu()。现在,与其在继承 Translation 的所有 类 中实现 NavMenu(),不如在所有 类 中实现 NavMenuProps 中的所有属性。

public abstract class NavMenuProps
{
    public abstract string FirstMenuHeader { get; }
    public abstract string SecondMenuHeader { get; }
    public abstract string ThirdMenuHeader { get; }
}

public abstract class Translation : NavMenuProps
{
    public Translation NavMenu() => this;
}

public class English : Translation
{
    public override string FirstMenuHeader => "First";
    public override string SecondMenuHeader => "Second";
    public override string ThirdMenuHeader => "Third";
}

现在可以打电话了

var englishMenu = new English().NavMenu();

如果需要以任何其他方式为某些 类 实现 NavMenu(),您可以实现 virtual 并在需要的地方覆盖它:

public abstract class Translation : NavMenuProps
{
    public virtual Translation NavMenu() => this;
}

public class English : Translation
{
    //...

    public override Translation NavMenu()
    {
        //return base.NavMenu();
    }
}

如果我理解你的要求,这就是解决方案

将 NavMenu 属性声明为接口

public interface NavMenuProps
{
    public string FirstMenuHeader { get; set; }
    public string SecondMenuHeader { get; set; }
    public string ThirdMenuHeader { get; set; }
}

将翻译 class 声明为具有抽象属性的抽象

public abstract class Translation : NavMenuProps
{
    public abstract string FirstMenuHeader { get; set; }
    public abstract string SecondMenuHeader { get; set; }
    public abstract string ThirdMenuHeader { get; set; }
}

现在您可以实现每种语言的翻译,如果您不实现任何语言的 NavMenuProps 属性class,代码编辑器会抱怨“没有实现继承的抽象成员”

public class English : Translation
{
    public override string FirstMenuHeader { get; set; }
    public override string SecondMenuHeader { get; set; }
    public override string ThirdMenuHeader { get; set; }
}

public class Dutch : Translation
{
    public override string FirstMenuHeader { get; set; }
    public override string SecondMenuHeader { get; set; }
    public override string ThirdMenuHeader { get; set; }
}

public class French : Translation
{
    public override string FirstMenuHeader { get; set; }
    public override string SecondMenuHeader { get; set; }
    public override string ThirdMenuHeader { get; set; }
}

(代答题者,移至答案部分).

该解决方案并不比只有一个巨大的界面好多少,但它满足了我的需要,即具有可管理的界面并且 IDE 告诉我何时忘记实现一个字段。

受已接受答案启发的解决方案:


    public interface INavMenuProps
    {
        public string FirstMenuHeader { get; set; }
        public string SecondMenuHeader { get; set; }
        public string ThirdMenuHeader { get; set; }
    }

    public interface ILoginPageProps
    {
        public string FirstLabel { get; set; }
        public string SecondLabel { get; set; }
    }
    
    public interface Translation : INavMenuProps, ILoginPageProps
    {
    }
    
    public class English : Translation
    {
        public string FirstMenuHeader { get; set; } = "Dogs";
        public string SecondMenuHeader { get; set; } = "Facilities";
        public string ThirdMenuHeader { get; set; } = "Profile";

        public string FirstLabel { get; set; } = "1st label";
        public string SecondLabel { get; set; } = "2nd label";
    }
        
    public class Dutch : Translation
    {
        
    }

    public class French : Translation
    {
        
    }