我需要向Printer
对象发送不同的IEnumerables。
然后,此打印机对象将在foreach循环内对它们执行某些操作。
class Printer
{
public Printer(IEnumerable list)
{
foreach (var enumerable in list)
{
//DO STUFF
}
}
}
这允许我将任何可枚举的内容(例如List<T>
)发送到打印机对象。
比如
var list = new List<string> {"myList"};
new Printer(list); //mylist
这很好用。
但是如果我发送Dictionary<T, T>
如:
var dictionary = new Dictionary<int, string> {{1, "mydict"}};
new Printer(dictionary); //[1, mydict]
它有一个键和一个值。我想要的是,可以单独访问Value
循环内的foreach
属性。我可以访问的是可枚举对象,它没有我可以使用的属性。
现在如果数据类型T是包含多个属性的对象(这适用于两个示例),该怎么办?如何在foreach循环中使用这些属性?
我真的必须创建一个构造函数的重载,foreach可能会发送给它的数据类型吗?
此外,我在foreach中需要做的就是不能依赖任何数据类型 - 因为它不会操纵所有内容。我确实需要访问所有属性。
此外,这只是示例代码,实际上不是我在我的应用程序中使用的生产代码。
答案 0 :(得分:4)
您可以更改Printer类的代码吗?如果它接受IEnumerable<IPrintable>
而不仅仅是IEnumerable
之类的内容,则会更容易。使用这样的界面:
interface IPrintable
{
void Print();
}
然后,将发送到Printer
的所有对象都需要实现该接口。然后你可以这样做:
class Printer
{
public Printer(IEnumerable<IPrintable> list)
{
foreach (var enumerable in list)
{
enumerable.Print();
}
}
}
如果您有可打印对象的字典,例如:
var dict = new Dictionary<int,IPrintable>();
您可以将值传递给函数:
var printer = new Printer(dict.Values);
答案 1 :(得分:4)
您可以修改方法以接受返回print方法所需数据的委托。像这样:
// You will not need this class, if you always want a single string result.
class PrinterData
{
public string Value { get; set; }
// More properties?
}
class Printer
{
public Printer<T>(IEnumerable<T> list, Func<T, PrinterData> func)
{
foreach (T item in list)
{
PrinterData data = func(item);
// Do something with the data.
}
}
}
用法:
int[] ints = new int[] {1,2,3};
new Printer().Print(ints, x => new PrinterData() { Value = x.ToString() });
var dictionary = new Dictionary<int, string> {{1, "mydict"}};
new Printer().Print(dictionary, x => new PrinterData() { Value = x.Name + " = " + x.Value });
Per Erik Stendahl的回答非常相似。
答案 2 :(得分:3)
在调用new Printer()之前,必须使用要传递的值提取可枚举项。在字典的情况下,这很简单:只使用dict.Values。更一般的情况是:
var list = List<MyObject>()...
var printer = new Printer(list.Select(x => x.MyProperty));
答案 3 :(得分:2)
如果您想以不同方式对待不同类型,您可能应该采用不同的方法。如果要对它们进行相同处理,则应接受通用接口,并仅使用为接口定义的方法。
可以做
if (list is Dictionary<int, string>) {
// do special case
}
但是我对这个想法感到不寒而栗。
您甚至可以检查:
class Printer<T>
{
public Printer<T>(IEnumerable list)
{
foreach (var enumerable in list)
{
if (list is Dictionary<T, T>) {
//DO STUFF
}
}
}
}
答案 4 :(得分:1)
问题是,虽然集合是可枚举的,但它可以容纳不同类型的对象,正如您在List
和Dictionary
之间看到的那样。
要解决此问题而不编码每种对象类型,您必须只接受您定义的某种类型的可枚举集合,例如IEnumerable<IMyType>
。
答案 5 :(得分:1)
如果你不能在被叫方做任何事情,那么由调用者来确保它传递一个对打印机有效的IEnumerable
,比如传递dictionary.Values
而不是{{1}在你的例子中。但是,如果该类是公开的并且将由第三方用户使用,则最好为其dictionary
添加一些通用约束,与其他人一样。
答案 6 :(得分:0)
结果如下: 我用你们的帮助,所以我想我不应该把自己作为答案。
class Printer
{
public Printer(IEnumerable<IPrintable> list) //Accepts any collection with an object that implements IPrintable interface
{
foreach (var enumerable in list) //iterate through list of objects
{
foreach (var printable in enumerable)//loops through properties in current object
{
//DO STUFF
}
}
}
}
interface IPrintable : IEnumerable { }
class SomeObject : IPrintable
{
public string Property1 { get; set; }
public string Property2 { get; set; }
public interface IEnumerable
{
IEnumerator GetEnumerator(); //Returns a Enumerator
}
public IEnumerator GetEnumerator()
{
yield return Property1;
yield return Property2;
}
}
我自然需要实现自定义GetEnumerator()foreach对象 - 虽然没问题!