如果我想将类作为参数传递的列表存储,我应该使用什么参数类型?

我是不是应该 Select IEumable,然后做类似于Items = items.ToList().AsReadOnly()的事情?但我如何避免多余的副本呢?如果列表是在构造函数调用内部创建的,那么肯定是ToList()个多了.

在C++中,我有一个非引用参数来确保传递列表的副本,但在C#中,这是不可能的.

我脑海中的一个例子是一个事件参数类,它包含一些东西的列表,这也是调用类的当前状态.列表在传递给各种事件处理程序后不应更改.

当按如下方式调用is时,可以在构造函数内创建副本:

SomethingHappened?.Invoke(this, new CustomEventArgs(_items));

但当它像这样被调用时,就会产生一个不必要的副本:

SomethingHappened?.Invoke(this, new CustomEventArgs(new List { item1, item2 }));

推荐答案

如果不想修改传递给类中构造函数的列表,那么可以将参数定义为IReadOnlyList<T>,然后通过调用原始列表上的AsReadOnly()来传递它.您仍将使用相同的列表,但AsReadOnly()提供了一个包装器来防止修改,如documentation:

public class YourClass
{
    private IReadOnlyList<SomeType> yourList;

    public YourClass(IReadOnlyList<SomeType> list)
    {
        yourList = list;
    }
}

然后调用构造函数,如下所示:

var someList = new List<SomeType>();

var yourClassInstance = new YourClass(someList.AsReadOnly());

您仍然可以更改原始列表引用,并且它将反映在只读引用中,因为它们实际上正在访问相同的列表,但您不能修改YourClass内的列表.

或者,如果不能在外部调用AsReadOnly(),则需要在构造函数内调用它,从技术上讲,这将允许您的类在存储只读引用之前进行修改:

public class YourClass
{
    private IReadOnlyList<SomeType> yourList;

    public YourClass(IList<SomeType> list)
    {
        yourList = list.AsReadOnly();
    }
}

如果您确实需要修改传递的列表,您将需要创建一个副本,然后YourClass将获得该副本的所有权:

public class YourClass
{
    private IList<SomeType> yourList;

    public YourClass(IList<SomeType> list)
    {
        yourList = new List<T>(list);
    }
}

由于被调用者本身无法知道是否应该复制,因此您可以向构造函数添加一个可选标志,以将责任转移给调用者:

public class YourClass
{
    private IList<SomeType> yourList;

    public YourClass(IList<SomeType> list, bool makeCopy = false)
    {
        yourList = makeCopy ? new List<T>(list) : list;
    }
}

这样,调用方必须决定是否需要复制:

var someList = new List<SomeType>();

//Make a copy explicitly
var yourClassInstance1 = new YourClass(someList, true);

//Do not make a copy
var yourClassInstance2 = new YourClass(new List<SomeType>{ object1, object2 });

Csharp相关问答推荐

C#如何克服getter的接口空性

读取配置文件(mytest. exe. config)

实现List T,为什么LINQ之后它不会返回MyList?<>(无法强制转换WhereListIterator `1类型的对象)'

C#DateTime.ToString在ubuntu和centos中返回不同的结果

从Blob存储中提取tar.gz文件并将提取结果上载到另一个Blob存储

.NET HttpClient、JsonSerializer或误用的Stream中的内存泄漏?

为什么SignalR在每个Blazor服务器应用程序启动时最多启动8个服务器?

XUNIT是否使用测试数据的源生成器?

如何从ASP.NET核心MVC视图和Blazor传递数据

System.Text.Json .NET 8多形态语法化

使用带有参数和曲面的注入失败(&Q;)

在两个已具有一对多关系的表之间添加另一个一对多关系

按需无缝转码单个HLS数据段

异步等待Foreach循环中的ConfigureAWait(FALSE)执行什么操作?

将J数组转换为列表,只保留一个嵌套的JToken

如何将默认区域性更改为fr-FR而不是en-US?

为什么Swashbakle/Swagger在参数中包含变量名?

Xamarin.Forms中具有类似AspectFill的图像zoom 的水平滚动视图

如何读取TagHelper属性的文本值?

在使用xUnit和Mock执行单元测试时,控制器ViewResult返回空的Model集合