C# 条件继承:基类依赖于环境变量
我有两个抽象类,“ValidationsWithStorage”继承了“Validations”C# 条件继承:基类依赖于环境变量,c#,inheritance,abstract-class,C#,Inheritance,Abstract Class,我有两个抽象类,“ValidationsWithStorage”继承了“Validations” public abstract class Validations { // methods.. } public abstract class ValidationsWithStorage : Validations { // ... } 我还有一门课: public abstract class TestsValidations : T T应取
public abstract class Validations {
// methods..
}
public abstract class ValidationsWithStorage : Validations {
// ...
}
我还有一门课:
public abstract class TestsValidations : T
T应取决于环境变量:
Environment.GetEnvironmentVariable("useStorage")
如果这个变量为null,我希望T是验证。
否则,我希望T将是带存储的验证
最好的方法是什么
谢谢我认为你不能用你的方式做你想做的事 为什么不让类
TestValidations
在其构造函数中采用Validations
或ValidationsWithStorage
类型的参数呢。如果它们都遵循相同的接口,那么您的TestsValidations
类就不需要知道(或关心)它使用的是这两个接口中的哪一个
所以基本上:
Validations
和ValidationsWithStorage
类创建一个接口TestsValidation
构造函数中那有帮助吗?我认为你不能用你的方式做你想做的事 为什么不让类
TestValidations
在其构造函数中采用Validations
或ValidationsWithStorage
类型的参数呢。如果它们都遵循相同的接口,那么您的TestsValidations
类就不需要知道(或关心)它使用的是这两个接口中的哪一个
所以基本上:
Validations
和ValidationsWithStorage
类创建一个接口TestsValidation
构造函数中这有帮助吗?我不确定您是否可以通过继承实现这一点。这不是继承的逻辑。如果您使用类似工厂模式的东西并更改当前的设计,效果会更好 也许你可以这样做。我没有测试,但我认为这样会更容易:
public interface Validations
{
void ValidationsStuff();
}
public class ValidationsWithStorage : Validations
{
public void ValidationsStuff()
{
//do something
}
}
public class TestsValidations : Validations
{
public void ValidationsStuff()
{
//do something
}
}
public class ValidationsFactory
{
public Validations geValidationsComponent(string useStorage)
{
if (string.IsNullOrEmpty(useStorage))
return new ValidationsWithStorage();
else
return new TestsValidations();
}
}
var validator = _validatorFactory.GetValidator(address.Country);
public interface IValidator
{
ValidationResult Validate(Something value);
}
public class ClassThatNeedsValidation
{
private readonly IValidator _validator;
public ClassThatNeedsValidation(IValidator validator)
{
_validator = validator;
}
// now the method that needs to use validation can
// use _validator.
}
var foo = new ClassThatNeedsValidation(new ValidationWithStorage());
var foo = new ClassThatNeedsValidation(
new ValidationWithStorage(
connectionString,
new SomethingElse(
new Whatever())));
services.AddSingleton<IValidator, ValidationWithStorage>();
services.AddSingleton<Whatever>();
services.AddSingleton<ISomethingElse, SomethingElse>();
services.AddSingleton<ClassThatNeedsValidation>();
我不确定你能用继承来做到这一点。这不是继承的逻辑。如果您使用类似工厂模式的东西并更改当前的设计,效果会更好 也许你可以这样做。我没有测试,但我认为这样会更容易:
public interface Validations
{
void ValidationsStuff();
}
public class ValidationsWithStorage : Validations
{
public void ValidationsStuff()
{
//do something
}
}
public class TestsValidations : Validations
{
public void ValidationsStuff()
{
//do something
}
}
public class ValidationsFactory
{
public Validations geValidationsComponent(string useStorage)
{
if (string.IsNullOrEmpty(useStorage))
return new ValidationsWithStorage();
else
return new TestsValidations();
}
}
var validator = _validatorFactory.GetValidator(address.Country);
public interface IValidator
{
ValidationResult Validate(Something value);
}
public class ClassThatNeedsValidation
{
private readonly IValidator _validator;
public ClassThatNeedsValidation(IValidator validator)
{
_validator = validator;
}
// now the method that needs to use validation can
// use _validator.
}
var foo = new ClassThatNeedsValidation(new ValidationWithStorage());
var foo = new ClassThatNeedsValidation(
new ValidationWithStorage(
connectionString,
new SomethingElse(
new Whatever())));
services.AddSingleton<IValidator, ValidationWithStorage>();
services.AddSingleton<Whatever>();
services.AddSingleton<ISomethingElse, SomethingElse>();
services.AddSingleton<ClassThatNeedsValidation>();
您可以使用条件编译来完成此操作:
public abstract class TestsValidations
#if USESTORAGE
: ValidationsWithStorage
#else
: Validations
#endif
{
}
您可以在项目配置中设置它,也可以通过将其他参数传递给msbuild:/p:DefineConstants=“USESTORAGE”
我认为这不是一个好的设计,但它是可行的。您可以使用条件编译:
public abstract class TestsValidations
#if USESTORAGE
: ValidationsWithStorage
#else
: Validations
#endif
{
}
您可以在项目配置中设置它,也可以通过将其他参数传递给msbuild:/p:DefineConstants=“USESTORAGE”
我不认为这是一个好的设计,但它是可行的。如果你想使用继承,我认为你的问题会得到解决如果你想使用继承,我认为你的问题会得到解决如果你使用继承,你的问题会得到解决 我不建议有条件地更改类的定义。这样做有一些奇怪的、一次性的原因,但我们很少遇到它们,不应该让它们成为我们编写代码的正常部分 我也不推荐工厂。工厂意味着您正在运行时、生产中决定使用“真实”类还是测试类。工厂只有在某些仅在运行时可用的数据决定要使用哪个实现时才有意义。例如,如果您想验证地址,您可以使用其国家/地区来确定是否向我们提供美国验证程序、加拿大验证程序等,如下所示:
public interface Validations
{
void ValidationsStuff();
}
public class ValidationsWithStorage : Validations
{
public void ValidationsStuff()
{
//do something
}
}
public class TestsValidations : Validations
{
public void ValidationsStuff()
{
//do something
}
}
public class ValidationsFactory
{
public Validations geValidationsComponent(string useStorage)
{
if (string.IsNullOrEmpty(useStorage))
return new ValidationsWithStorage();
else
return new TestsValidations();
}
}
var validator = _validatorFactory.GetValidator(address.Country);
public interface IValidator
{
ValidationResult Validate(Something value);
}
public class ClassThatNeedsValidation
{
private readonly IValidator _validator;
public ClassThatNeedsValidation(IValidator validator)
{
_validator = validator;
}
// now the method that needs to use validation can
// use _validator.
}
var foo = new ClassThatNeedsValidation(new ValidationWithStorage());
var foo = new ClassThatNeedsValidation(
new ValidationWithStorage(
connectionString,
new SomethingElse(
new Whatever())));
services.AddSingleton<IValidator, ValidationWithStorage>();
services.AddSingleton<Whatever>();
services.AddSingleton<ISomethingElse, SomethingElse>();
services.AddSingleton<ClassThatNeedsValidation>();
此外,这意味着“test”类将从生产代码中引用。这是不受欢迎的,而且有点奇怪
怎么办:
如果您在运行时没有做出这样的决定,那么这应该在合成根中确定——也就是说,在应用程序的启动部分,它决定了我们将使用哪些类
首先,您需要一个抽象概念。这通常是一个接口,如下所示:
public interface Validations
{
void ValidationsStuff();
}
public class ValidationsWithStorage : Validations
{
public void ValidationsStuff()
{
//do something
}
}
public class TestsValidations : Validations
{
public void ValidationsStuff()
{
//do something
}
}
public class ValidationsFactory
{
public Validations geValidationsComponent(string useStorage)
{
if (string.IsNullOrEmpty(useStorage))
return new ValidationsWithStorage();
else
return new TestsValidations();
}
}
var validator = _validatorFactory.GetValidator(address.Country);
public interface IValidator
{
ValidationResult Validate(Something value);
}
public class ClassThatNeedsValidation
{
private readonly IValidator _validator;
public ClassThatNeedsValidation(IValidator validator)
{
_validator = validator;
}
// now the method that needs to use validation can
// use _validator.
}
var foo = new ClassThatNeedsValidation(new ValidationWithStorage());
var foo = new ClassThatNeedsValidation(
new ValidationWithStorage(
connectionString,
new SomethingElse(
new Whatever())));
services.AddSingleton<IValidator, ValidationWithStorage>();
services.AddSingleton<Whatever>();
services.AddSingleton<ISomethingElse, SomethingElse>();
services.AddSingleton<ClassThatNeedsValidation>();
需要验证的类如下所示:
public interface Validations
{
void ValidationsStuff();
}
public class ValidationsWithStorage : Validations
{
public void ValidationsStuff()
{
//do something
}
}
public class TestsValidations : Validations
{
public void ValidationsStuff()
{
//do something
}
}
public class ValidationsFactory
{
public Validations geValidationsComponent(string useStorage)
{
if (string.IsNullOrEmpty(useStorage))
return new ValidationsWithStorage();
else
return new TestsValidations();
}
}
var validator = _validatorFactory.GetValidator(address.Country);
public interface IValidator
{
ValidationResult Validate(Something value);
}
public class ClassThatNeedsValidation
{
private readonly IValidator _validator;
public ClassThatNeedsValidation(IValidator validator)
{
_validator = validator;
}
// now the method that needs to use validation can
// use _validator.
}
var foo = new ClassThatNeedsValidation(new ValidationWithStorage());
var foo = new ClassThatNeedsValidation(
new ValidationWithStorage(
connectionString,
new SomethingElse(
new Whatever())));
services.AddSingleton<IValidator, ValidationWithStorage>();
services.AddSingleton<Whatever>();
services.AddSingleton<ISomethingElse, SomethingElse>();
services.AddSingleton<ClassThatNeedsValidation>();
这就是依赖注入<代码>需要验证的类不负责创建验证器实例。这将迫使它“了解”IValidator的实现。相反,它希望向其提供一个IValidator
。(换句话说,它的依赖性——它所需要的东西——被注入其中。)
现在,如果您正在创建需要验证的类的实例,它可能如下所示:
public interface Validations
{
void ValidationsStuff();
}
public class ValidationsWithStorage : Validations
{
public void ValidationsStuff()
{
//do something
}
}
public class TestsValidations : Validations
{
public void ValidationsStuff()
{
//do something
}
}
public class ValidationsFactory
{
public Validations geValidationsComponent(string useStorage)
{
if (string.IsNullOrEmpty(useStorage))
return new ValidationsWithStorage();
else
return new TestsValidations();
}
}
var validator = _validatorFactory.GetValidator(address.Country);
public interface IValidator
{
ValidationResult Validate(Something value);
}
public class ClassThatNeedsValidation
{
private readonly IValidator _validator;
public ClassThatNeedsValidation(IValidator validator)
{
_validator = validator;
}
// now the method that needs to use validation can
// use _validator.
}
var foo = new ClassThatNeedsValidation(new ValidationWithStorage());
var foo = new ClassThatNeedsValidation(
new ValidationWithStorage(
connectionString,
new SomethingElse(
new Whatever())));
services.AddSingleton<IValidator, ValidationWithStorage>();
services.AddSingleton<Whatever>();
services.AddSingleton<ISomethingElse, SomethingElse>();
services.AddSingleton<ClassThatNeedsValidation>();
然后,在单元测试项目中,您可能有一个ivalidor
的测试实现。(您也可以使用Moq之类的框架,但我同意您的看法——有时我更喜欢编写一个testdouble——一个实现接口的测试类。)
因此,在单元测试中,您可以编写以下代码:
var foo = new ClassThatNeedsValidation(new TestValidator());
这也意味着TestValidator
可以在测试项目中,而不是与生产代码混合
如何使其更容易:
在本例中:
var foo = new ClassThatNeedsValidation(new ValidationWithStorage());
你可以看到这会变得多么混乱。如果ValidationWithStorage
有它自己的依赖项怎么办?然后,您可能必须开始编写如下代码:
public interface Validations
{
void ValidationsStuff();
}
public class ValidationsWithStorage : Validations
{
public void ValidationsStuff()
{
//do something
}
}
public class TestsValidations : Validations
{
public void ValidationsStuff()
{
//do something
}
}
public class ValidationsFactory
{
public Validations geValidationsComponent(string useStorage)
{
if (string.IsNullOrEmpty(useStorage))
return new ValidationsWithStorage();
else
return new TestsValidations();
}
}
var validator = _validatorFactory.GetValidator(address.Country);
public interface IValidator
{
ValidationResult Validate(Something value);
}
public class ClassThatNeedsValidation
{
private readonly IValidator _validator;
public ClassThatNeedsValidation(IValidator validator)
{
_validator = validator;
}
// now the method that needs to use validation can
// use _validator.
}
var foo = new ClassThatNeedsValidation(new ValidationWithStorage());
var foo = new ClassThatNeedsValidation(
new ValidationWithStorage(
connectionString,
new SomethingElse(
new Whatever())));
services.AddSingleton<IValidator, ValidationWithStorage>();
services.AddSingleton<Whatever>();
services.AddSingleton<ISomethingElse, SomethingElse>();
services.AddSingleton<ClassThatNeedsValidation>();
那不好玩。这就是为什么我们经常使用IoC容器,也称为依赖注入容器
如果我们使用ASP.NETCore,这是很熟悉的,尽管知道我们不必使用ASP.NETCore来实现这一点很重要。我们可以向项目中添加、Windsor或其他
解释这一点有些超出了这个答案的范围,而且可能超出了您现在需要的范围。但它使我们能够编写如下代码:
public interface Validations
{
void ValidationsStuff();
}
public class ValidationsWithStorage : Validations
{
public void ValidationsStuff()
{
//do something
}
}
public class TestsValidations : Validations
{
public void ValidationsStuff()
{
//do something
}
}
public class ValidationsFactory
{
public Validations geValidationsComponent(string useStorage)
{
if (string.IsNullOrEmpty(useStorage))
return new ValidationsWithStorage();
else
return new TestsValidations();
}
}
var validator = _validatorFactory.GetValidator(address.Country);
public interface IValidator
{
ValidationResult Validate(Something value);
}
public class ClassThatNeedsValidation
{
private readonly IValidator _validator;
public ClassThatNeedsValidation(IValidator validator)
{
_validator = validator;
}
// now the method that needs to use validation can
// use _validator.
}
var foo = new ClassThatNeedsValidation(new ValidationWithStorage());
var foo = new ClassThatNeedsValidation(
new ValidationWithStorage(
connectionString,
new SomethingElse(
new Whatever())));
services.AddSingleton<IValidator, ValidationWithStorage>();
services.AddSingleton<Whatever>();
services.AddSingleton<ISomethingElse, SomethingElse>();
services.AddSingleton<ClassThatNeedsValidation>();
你在做决定,但你只做了一次。依赖于IValidator
的类不需要知道此决定。它不需要