I introduced an interface in the constructor, then looped through a method to call the interface's methods, and finally used the interface's public properties, but this property is always changing. I know it's because of the reference variable. Like the code below, is there a better design pattern to implement. thank you very much!
// See https://aka.ms/new-console-template for more information
Console.WriteLine("Hello, World!");
var f = new Factory(new StdOperation());
var stdCollection = new List<Std>{ new Std("aa"),
new Std("bb/cc"),
new Std("cc/dd"),
new Std("dd/ee"),
new Std("ee/ff")
};
f.Do(stdCollection);
foreach (var item in stdCollection)
{
Console.WriteLine(item.NameAry?.Count);
}
//Output 0 0 0 2
public class Std
{
public Std(string name)
{
Name = name;
}
public string Name { get; set; }
public List<string> NameAry { get; set; }
}
public class Factory
{
private readonly IStudentOperation stdOpt;
public Factory(IStudentOperation stdOpt)
{
this.stdOpt = stdOpt;
}
public void Do(List<Std> stdAry)
{
var result = new List<string>();
foreach (var item in stdAry)
{
if (!this.stdOpt.IsMatch(item.Name))
{
continue;
}
item.NameAry = this.stdOpt.NameAry;
}
}
}
public interface IStudentOperation
{
List<string> NameAry { get; }
bool IsMatch(string name);
}
public class StdOperation : IStudentOperation
{
private List<string> _nameAry;
public bool IsMatch(string name)
{
this._nameAry?.Clear();
//do something...
if (name.IndexOf("/") == -1)
{
return false;
}
this._nameAry = name.Split("/").ToList();
return true;
}
public List<string> NameAry => this._nameAry;
}
CodePudding user response:
The reason for your issue is:
item.NameAry = this.stdOpt.NameAry;
Factory
has a method Do
that takes a whole list but has just a single IStudentOperation
with a field List<string> NameAry
. So you iterate one list and for every item in it you assign the same result list, so only the last one is correct.
Instead you could let IsMatch
return the NameAry
as an out-parameter:
public interface IStudentOperation
{
bool IsMatch(string name, out List<string> matches);
}
public class StdOperation : IStudentOperation
{
public bool IsMatch(string name, out List<string> matches)
{
if (name.IndexOf("/") == -1)
{
matches = new List<string>(0);
return false;
}
matches = name.Split("/").ToList();
return true;
}
}
Now Do
can consume it in this way:
public void Do(List<Std> stdAry)
{
foreach (var item in stdAry)
{
if (!this.stdOpt.IsMatch(item.Name, out var matches))
{
continue;
}
item.NameAry = matches;
}
}
Now the result is as expected:
2
2
2
2