当我使用 Action<> 设置对象时,分配的对象始终为 null
When I set an object using an Action<> the object assigned is always null
我的目标是创建一个 Action<> 用于在构造函数中设置配置对象。
我定义的Action<>,通过引用设置了两个配置对象,但问题是分配的对象总是空的。我认为在内部,对象是通过引用分配的,但似乎没有。
在示例代码中,我在主程序中创建了一个 CarConfiguration,我尝试使用 Action<> 将此配置引用到我的新 Car 中,该操作定义了主程序 CarConfiguration 和 Car 属性之间的分配配置。
即使在我的 Action<> 方法中通过引用分配,为什么我的汽车配置属性始终为 null?
主要Class:
CarConfiguration carConfiguration = new CarConfiguration()
{
CarName = "Ferrari",
CarModel = "LaFerrari",
Spolier = true,
BuildDate = new DateTime(2018, 01, 01)
};
//Thats not work because the "conf" parameter is never assign in the Car constructor
Car myOwnCar = new Car(conf =>
{
conf = carConfiguration;
});
Console.WriteLine(myOwnCar.CarConfigurationText());
//That works, but is not my purpose do it like this !
Car myOtherCar = new Car(carConfiguration);
Console.WriteLine(myOtherCar.CarConfigurationText());
配置Class:
public class CarConfiguration
{
public bool Spolier { get; set; } = false;
public string CarName { get; set; } = String.Empty;
public string CarModel { get; set; } = String.Empty;
public DateTime BuildDate { get; set; } = default(DateTime);
}
汽车Class:
public class Car
{
private CarConfiguration carConfiguration = null;
//Thats not work because carConfiguration is not assigned in the Action as a reference
public Car(Action<CarConfiguration> configureCar)
{
configureCar(carConfiguration);
}
//Thats works!
public Car(CarConfiguration configureCar)
{
carConfiguration = configureCar;
}
public string CarConfigurationText()
{
StringBuilder strBuilder = new StringBuilder();
if (carConfiguration != null)
{
strBuilder.AppendLine(carConfiguration.CarModel);
strBuilder.AppendLine(carConfiguration.CarName);
strBuilder.AppendLine(carConfiguration.Spolier.ToString());
strBuilder.AppendLine(carConfiguration.BuildDate.ToString("mm-DD-yyyy"));
}
else
{
strBuilder.AppendLine("Car is not configure!");
}
return strBuilder.ToString();
}
}
如果您使用 Action<ref CarConfiguration>
(假设这是合法的)而不是 Action<CarConfiguration>
来允许通过引用传递参数,您的代码将起作用。但是没有build-inAction<ref Τ>
,想要的还是自己做吧:
public delegate void RefAction<T>(ref T arg1);
...然后使用 RefAction<CarConfiguration>
而不是 Action<CarConfiguration>
。
您的操作是将配置分配给 lambda 参数,这没有任何效果,因为参数是输入值,它不会从 lambda 中返回。对象通过引用传递,但引用被复制到函数调用中的参数,即当您像这样调用操作时 conf
将收到对 carConfiguration
的引用的副本 configureCar(carConfiguration);
分配和覆盖此引用的本地副本没有任何用处。您必须使用 ref
关键字实质上将对引用(变量)的引用传递给对象。当分配给标有 ref
的变量时,它将覆盖原始成员变量中保存的引用,而不是 lambda 中的局部变量。这已经在另一个答案中得到证明。
实现您想要完成的目标的正确方法不是通过传递引用,而是通过在操作中配置对象。如果您想使用现有配置,只需像您已经这样做的那样传递对象。无需编写以显式方式接受对象引用的操作。
public Car(Action<CarConfiguration> configureCar)
{
carConfiguration = new CarConfiguration();
configureCar(carConfiguration);
}
// This is the common configuration pattern seen in .NET
Car myOwnCar = new Car(conf =>
{
conf.CarName = "Ferrari";
conf.CarModel = "LaFerrari"
/** etc **/
});
如果您想从现有配置中复制值,您可以编写一个方法来执行此操作
public static class CarConfigurationExtensions
{
public static void CopyTo(CarConfiguration this source, CarConfiguration dest){
dest.CarName = source.CarName;
dest.CarModel = source.CarModel;
// etc
}
}
Car myOwnCar = new Car(conf => carConfiguration.CopyTo(conf));
但是在任何情况下都不会编写接受 ref
到局部变量的操作。另一种选择是像这样使用 Func<CarConfiguration>
,也许如果你想进行延迟初始化。
public Car(Func<CarConfiguration> configurator)
{
_configurator = configurator;
}
private Func<CarConfiguration> _configurator;
private CarConfiguration _carConfiguration;
public CarConfiguration CarConfiguration =>
_carConfiguration ?? (_carConfiguration = _configurator());
Car myOwnCar = new Car(() => carConfiguration);
注意配置是如何实例化和存储的-第一次访问它,也许只有在构造函数中接受一个函数才有用。
我的目标是创建一个 Action<> 用于在构造函数中设置配置对象。
我定义的Action<>,通过引用设置了两个配置对象,但问题是分配的对象总是空的。我认为在内部,对象是通过引用分配的,但似乎没有。
在示例代码中,我在主程序中创建了一个 CarConfiguration,我尝试使用 Action<> 将此配置引用到我的新 Car 中,该操作定义了主程序 CarConfiguration 和 Car 属性之间的分配配置。
即使在我的 Action<> 方法中通过引用分配,为什么我的汽车配置属性始终为 null?
主要Class:
CarConfiguration carConfiguration = new CarConfiguration()
{
CarName = "Ferrari",
CarModel = "LaFerrari",
Spolier = true,
BuildDate = new DateTime(2018, 01, 01)
};
//Thats not work because the "conf" parameter is never assign in the Car constructor
Car myOwnCar = new Car(conf =>
{
conf = carConfiguration;
});
Console.WriteLine(myOwnCar.CarConfigurationText());
//That works, but is not my purpose do it like this !
Car myOtherCar = new Car(carConfiguration);
Console.WriteLine(myOtherCar.CarConfigurationText());
配置Class:
public class CarConfiguration
{
public bool Spolier { get; set; } = false;
public string CarName { get; set; } = String.Empty;
public string CarModel { get; set; } = String.Empty;
public DateTime BuildDate { get; set; } = default(DateTime);
}
汽车Class:
public class Car
{
private CarConfiguration carConfiguration = null;
//Thats not work because carConfiguration is not assigned in the Action as a reference
public Car(Action<CarConfiguration> configureCar)
{
configureCar(carConfiguration);
}
//Thats works!
public Car(CarConfiguration configureCar)
{
carConfiguration = configureCar;
}
public string CarConfigurationText()
{
StringBuilder strBuilder = new StringBuilder();
if (carConfiguration != null)
{
strBuilder.AppendLine(carConfiguration.CarModel);
strBuilder.AppendLine(carConfiguration.CarName);
strBuilder.AppendLine(carConfiguration.Spolier.ToString());
strBuilder.AppendLine(carConfiguration.BuildDate.ToString("mm-DD-yyyy"));
}
else
{
strBuilder.AppendLine("Car is not configure!");
}
return strBuilder.ToString();
}
}
如果您使用 Action<ref CarConfiguration>
(假设这是合法的)而不是 Action<CarConfiguration>
来允许通过引用传递参数,您的代码将起作用。但是没有build-inAction<ref Τ>
,想要的还是自己做吧:
public delegate void RefAction<T>(ref T arg1);
...然后使用 RefAction<CarConfiguration>
而不是 Action<CarConfiguration>
。
您的操作是将配置分配给 lambda 参数,这没有任何效果,因为参数是输入值,它不会从 lambda 中返回。对象通过引用传递,但引用被复制到函数调用中的参数,即当您像这样调用操作时 conf
将收到对 carConfiguration
的引用的副本 configureCar(carConfiguration);
分配和覆盖此引用的本地副本没有任何用处。您必须使用 ref
关键字实质上将对引用(变量)的引用传递给对象。当分配给标有 ref
的变量时,它将覆盖原始成员变量中保存的引用,而不是 lambda 中的局部变量。这已经在另一个答案中得到证明。
实现您想要完成的目标的正确方法不是通过传递引用,而是通过在操作中配置对象。如果您想使用现有配置,只需像您已经这样做的那样传递对象。无需编写以显式方式接受对象引用的操作。
public Car(Action<CarConfiguration> configureCar)
{
carConfiguration = new CarConfiguration();
configureCar(carConfiguration);
}
// This is the common configuration pattern seen in .NET
Car myOwnCar = new Car(conf =>
{
conf.CarName = "Ferrari";
conf.CarModel = "LaFerrari"
/** etc **/
});
如果您想从现有配置中复制值,您可以编写一个方法来执行此操作
public static class CarConfigurationExtensions
{
public static void CopyTo(CarConfiguration this source, CarConfiguration dest){
dest.CarName = source.CarName;
dest.CarModel = source.CarModel;
// etc
}
}
Car myOwnCar = new Car(conf => carConfiguration.CopyTo(conf));
但是在任何情况下都不会编写接受 ref
到局部变量的操作。另一种选择是像这样使用 Func<CarConfiguration>
,也许如果你想进行延迟初始化。
public Car(Func<CarConfiguration> configurator)
{
_configurator = configurator;
}
private Func<CarConfiguration> _configurator;
private CarConfiguration _carConfiguration;
public CarConfiguration CarConfiguration =>
_carConfiguration ?? (_carConfiguration = _configurator());
Car myOwnCar = new Car(() => carConfiguration);
注意配置是如何实例化和存储的-第一次访问它,也许只有在构造函数中接受一个函数才有用。