分配给只读字段的构造函数的简化
Simplification of Constructors Assigning to readonly Fields
我有以下 class:
public class MyCollection<T1, T2> : AnotherCollection<T1>
{
private readonly ICollection<T2> BaseCollection;
public MyCollection(IEnumerable<T1> collection, ICollection<T2> baseCollection) : base(collection)
{
BaseCollection = baseCollection;
}
public MyCollection(List<T1> collection, ICollection<T2> baseCollection) : base(collection)
{
BaseCollection = baseCollection;
}
}
有没有什么方法可以简化这段代码,使 BaseCollection = baseCollection;
只写一次?
IEnumerable 可以同时支持列表和集合。所以你不需要两个构造函数。使用这样的单个构造函数,您可以初始化一个 List 和 IEnumerable
public class MyCollection<T1, T2> : AnotherClass<T1>
{
private readonly ICollection<T2> BaseCollection;
public MyCollection(IEnumerable<T1> collection, ICollection<T2> baseCollection) : base(collection)
{
BaseCollection = baseCollection;
}
}
您的初始解决方案是完全可以接受的,特别是如果有基于类型的不同实现。
如果 IEnumerable 和 List 在基础 class 上有不同的实现,则检查类似这样的内容,但不推荐
记住,过度优化是万恶之源
public class AnotherClass<T1>
{
public AnotherClass(IEnumerable<T1> collection)
{
var type = collection.GetType();
if (type == typeof(IEnumerable<T1>))
{
//Do the implementation Detail for IEnumerable
}
else if (type == typeof(List<T1>))
{
//Do the implementation Detail for List
}
else if (type == typeof(Collection<T1>))
{
//Do the implementation Detail for ICollection
}
else
{
//Do the implementation Detail for Default
}
}
}
您可以让第二个构造函数调用第一个构造函数:
public MyCollection(IEnumerable<T1> collection, ICollection<T2> baseCollection) : base(collection)
{
BaseCollection = baseCollection;
}
public MyCollection(List<T1> collection, ICollection<T2> baseCollection)
: this((IEnumerable<T1>)collection, baseCollection)
{
// you can do additional initialisation for the List<T1> case here
}
注意需要将collection
转换为IEnumerable<T1>
,这样调用就不会再次解析到同一个构造函数,这是无效的。除了强制转换,您还可以使用 as IEnumerable<T1>
或 AsEnumerable()
.
如果您希望在调用者传入列表而不是 IEnumerable<T>
时执行一些额外的操作,这可能很有用。如果您不想做任何额外的事情,那么您实际上不需要两个构造函数。 List<T1>
实现了 IEnumerable<T1>
,所以你只需要 IEnumerable<T1>
一个。
如果这两个base(collection)
调用实际上是在调用基class的不同构造函数(实现不同),那么选择余地不多。我能想到的就是使用 dynamic
并且只有一个这样的构造函数:
public MyCollection(IEnumerable<T1> collection, ICollection<T2> baseCollection) : base((dynamic)collection)
{
BaseCollection = baseCollection;
}
这将使它根据传入的集合的运行时类型选择调用哪个构造函数。这意味着即使你有一个List<T1>
,你也不能选择调用IEnumerable<T1>
基础构造函数,像以前一样将其转换为 IEnumerable<T1>
。您必须创建一个新的 IEnumerable
,而不是 List
。
我在这里找到了解决方法:
How do I set a readonly field in an initialize method that gets called from the constructor?
在我的示例中实现为:
public class MyCollection<T1, T2> : AnotherCollection<T1>
{
private readonly ICollection<T2> BaseCollection;
public MyCollection(IEnumerable<T1> collection, ICollection<T2> baseCollection) : base(collection)
{
Init(baseCollection, out BaseCollection);
}
public MyCollection(List<T1> collection, ICollection<T2> baseCollection) : base(collection)
{
Init(baseCollection, out BaseCollection);
}
private void Init(ICollection<T2> baseCollection, out ICollection<T2> baseCollectionAssigment)
{
baseCollectionAssigment = baseCollection;
}
}
我喜欢的一件事是能够拥有一个 Init
方法,在该方法中我可以拥有两个构造函数共有的更多代码。如果我要添加另一个类似的构造函数,我将只需要为其编写一行代码。
我有以下 class:
public class MyCollection<T1, T2> : AnotherCollection<T1>
{
private readonly ICollection<T2> BaseCollection;
public MyCollection(IEnumerable<T1> collection, ICollection<T2> baseCollection) : base(collection)
{
BaseCollection = baseCollection;
}
public MyCollection(List<T1> collection, ICollection<T2> baseCollection) : base(collection)
{
BaseCollection = baseCollection;
}
}
有没有什么方法可以简化这段代码,使 BaseCollection = baseCollection;
只写一次?
IEnumerable 可以同时支持列表和集合。所以你不需要两个构造函数。使用这样的单个构造函数,您可以初始化一个 List 和 IEnumerable
public class MyCollection<T1, T2> : AnotherClass<T1>
{
private readonly ICollection<T2> BaseCollection;
public MyCollection(IEnumerable<T1> collection, ICollection<T2> baseCollection) : base(collection)
{
BaseCollection = baseCollection;
}
}
您的初始解决方案是完全可以接受的,特别是如果有基于类型的不同实现。
如果 IEnumerable 和 List 在基础 class 上有不同的实现,则检查类似这样的内容,但不推荐
记住,过度优化是万恶之源
public class AnotherClass<T1>
{
public AnotherClass(IEnumerable<T1> collection)
{
var type = collection.GetType();
if (type == typeof(IEnumerable<T1>))
{
//Do the implementation Detail for IEnumerable
}
else if (type == typeof(List<T1>))
{
//Do the implementation Detail for List
}
else if (type == typeof(Collection<T1>))
{
//Do the implementation Detail for ICollection
}
else
{
//Do the implementation Detail for Default
}
}
}
您可以让第二个构造函数调用第一个构造函数:
public MyCollection(IEnumerable<T1> collection, ICollection<T2> baseCollection) : base(collection)
{
BaseCollection = baseCollection;
}
public MyCollection(List<T1> collection, ICollection<T2> baseCollection)
: this((IEnumerable<T1>)collection, baseCollection)
{
// you can do additional initialisation for the List<T1> case here
}
注意需要将collection
转换为IEnumerable<T1>
,这样调用就不会再次解析到同一个构造函数,这是无效的。除了强制转换,您还可以使用 as IEnumerable<T1>
或 AsEnumerable()
.
如果您希望在调用者传入列表而不是 IEnumerable<T>
时执行一些额外的操作,这可能很有用。如果您不想做任何额外的事情,那么您实际上不需要两个构造函数。 List<T1>
实现了 IEnumerable<T1>
,所以你只需要 IEnumerable<T1>
一个。
如果这两个base(collection)
调用实际上是在调用基class的不同构造函数(实现不同),那么选择余地不多。我能想到的就是使用 dynamic
并且只有一个这样的构造函数:
public MyCollection(IEnumerable<T1> collection, ICollection<T2> baseCollection) : base((dynamic)collection)
{
BaseCollection = baseCollection;
}
这将使它根据传入的集合的运行时类型选择调用哪个构造函数。这意味着即使你有一个List<T1>
,你也不能选择调用IEnumerable<T1>
基础构造函数,像以前一样将其转换为 IEnumerable<T1>
。您必须创建一个新的 IEnumerable
,而不是 List
。
我在这里找到了解决方法:
How do I set a readonly field in an initialize method that gets called from the constructor?
在我的示例中实现为:
public class MyCollection<T1, T2> : AnotherCollection<T1>
{
private readonly ICollection<T2> BaseCollection;
public MyCollection(IEnumerable<T1> collection, ICollection<T2> baseCollection) : base(collection)
{
Init(baseCollection, out BaseCollection);
}
public MyCollection(List<T1> collection, ICollection<T2> baseCollection) : base(collection)
{
Init(baseCollection, out BaseCollection);
}
private void Init(ICollection<T2> baseCollection, out ICollection<T2> baseCollectionAssigment)
{
baseCollectionAssigment = baseCollection;
}
}
我喜欢的一件事是能够拥有一个 Init
方法,在该方法中我可以拥有两个构造函数共有的更多代码。如果我要添加另一个类似的构造函数,我将只需要为其编写一行代码。