C# 混凝土类型的铸造IEnumerable接口
我有点像:C# 混凝土类型的铸造IEnumerable接口,c#,C#,我有点像: public interface IThing { string Id { get; } } public class Ball : IThing { public string Id { get; } } public class Car : IThing { public string Id { get; } } var things = (
public interface IThing
{
string Id { get; }
}
public class Ball : IThing
{
public string Id { get; }
}
public class Car : IThing
{
public string Id { get; }
}
var things = (inputs is IEnumerable<Ball>) ? input.Locations.Cast<Ball>() : input.Locations.Cast<Car>()
对于我的3-4个功能,我希望将球和车处理得一样。我使用的界面,所以我不必作出超载的方法(一个为汽车,一个为球)
最后,还有一个on函数,如果它是球
或车
,我有不同的逻辑。我得到一个IEnumerable
,我想将它转换为IEnumerable
或IEnumerable
,具体取决于它由什么组成。如果它是一个混合体,我希望它失败。它必须是所有的汽车或所有的球
我试过这样的方法:
public interface IThing
{
string Id { get; }
}
public class Ball : IThing
{
public string Id { get; }
}
public class Car : IThing
{
public string Id { get; }
}
var things = (inputs is IEnumerable<Ball>) ? input.Locations.Cast<Ball>() : input.Locations.Cast<Car>()
var things=(输入是IEnumerable)?input.Locations.Cast():input.Locations.Cast()
但它不喜欢这样。我可以有1个变量的推荐方法是什么
编辑:
我之所以想把它放到一个变量中,是因为我要把它发送给一个重载方法。所以我想这样做:
var things = (inputs is IEnumerable<Ball>) ? input.Locations.Cast<Ball>() : input.Locations.Cast<Car>()
for (var i = 0; i < numRequests; i++)
{
var thingsSet = things.Skip(i * 1000).Take(1000);
var results = callOverLoadedFunction(thingsSet);
}
var things=(输入是IEnumerable)?input.Locations.Cast():input.Locations.Cast()
对于(变量i=0;i
与此相反:
if (inputs is IEnumerable<Ball>)
{
var things = input.Locations.Cast<Ball>();
for (var i = 0; i < numRequests; i++)
{
var thingsSet = things.Skip(i * 1000).Take(1000);
var results = callOverLoadedFunction(thingsSet);
}
}
else
{
var things = input.Locations.Cast<Car>();
for (var i = 0; i < numRequests; i++)
{
var thingsSet = things.Skip(i * 1000).Take(1000);
var results = callOverLoadedFunction(thingsSet);
}
}
if(输入为IEnumerable)
{
var things=input.Locations.Cast();
对于(变量i=0;i
您可以使用convert方法,但这仍然会违反一些原则,因为您仍然需要放置if
语句。
我不确定,您是否以正确的方式使用接口来实现您想要实现的目标
如果您想让汽车
在特定情况下表现出与球
不同的行为,则汽车中的实现应与球中的实现不同
不要试图从外部调整接口。实现必须做到这一点
为什么不在IThing
中创建一个方法DoMySpecialStuff
,然后在这个特殊的方法中迭代您的枚举,该方法只调用所有元素上的DoMySpecialStuff
?
这就是避免你的if语句的方法
我刚刚看到您使用重载方法进行编辑
所以它可以这样工作:
for (var i = 0; i < numRequests; i++)
{
var thingsSet = things.Skip(i * 1000).Take(1000);
var results = callOverLoadedFunction(thingsSet);
}
void OverLoadedFunction(IThing thing)
{
thing.DoSpecialStuff(); // This does different things in car/ball
}
for(变量i=0;i
您可以使用convert方法,但这仍然会违反一些原则,因为您仍然需要放置if
语句。
我不确定,您是否以正确的方式使用接口来实现您想要实现的目标
如果您想让汽车
在特定情况下表现出与球
不同的行为,则汽车中的实现应与球中的实现不同
不要试图从外部调整接口。实现必须做到这一点
为什么不在IThing
中创建一个方法DoMySpecialStuff
,然后在这个特殊的方法中迭代您的枚举,该方法只调用所有元素上的DoMySpecialStuff
?
这就是避免你的if语句的方法
我刚刚看到您使用重载方法进行编辑
所以它可以这样工作:
for (var i = 0; i < numRequests; i++)
{
var thingsSet = things.Skip(i * 1000).Take(1000);
var results = callOverLoadedFunction(thingsSet);
}
void OverLoadedFunction(IThing thing)
{
thing.DoSpecialStuff(); // This does different things in car/ball
}
for(变量i=0;i
使用系统;
使用System.Collections.Generic;
使用System.Linq;
公共课程
{
公共静态void Main()
{
List testCollection=new List();
添加(newball());
testCollection.Add(新车());
尝试
{
如果(testCollection[0]为球形)
{
Console.WriteLine(testCollection.Cast().Count().ToString());
}
其他的
{
Console.WriteLine(testCollection.Cast().Count().ToString());
}
}
捕获(无效卡斯特例外)
{
控制台。WriteLine(“不允许混合!”);
}
}
}
公共接口
{
字符串Id{get;set;}
}
公共班级舞会:伊辛
{
公共字符串Id{get;set;}
}
公车:伊辛
{
公共字符串Id{get;set;}
}
此代码将在调用Cast
时抛出InvalidCastException,因为Car
对象无法被投射到Ball
。如果我没弄错的话,这应该是你想要的
代码将只检查第一个元素的类型,因为列表
不应混合,可以假设该列表
中的所有其他对象应具有相同的类型,如果不是,我认为,根据问题的编写方式,允许引发异常。使用系统;
使用System.Collections.Generic;
使用System.Linq;
公共课程
{
公共静态void Main()
{
List testCollection=new List();
添加(newball());
testCollection.Add(新车());
尝试
{
if(balls.Any() && cars.Any())
{
//You're not allowed to have balls and cars together
throw new Exception(...);
}
IEnumerable<Ball> balls = things.OfType<Ball>();
IEnumerable<Car> cars = things.OfType<Car>();
IEnumerable<Ball> balls = things.OfType<Ball>().Count() == things.Count() ? things.OfType<Ball>() : null; //or whatever you want
public class RemainingIEnumerator<T> : IEnumerable<T>
{
public IEnumerable<T> Enumerable { get; set; }
public int Nulls { get; set; }
public T First { get; set; }
public IEnumerator<T> Enumerator { get; set; }
public IEnumerator<T> GetEnumerator()
{
var enumerator = Enumerator;
if (enumerator == null)
{
return Enumerable.GetEnumerator();
}
return GetEnumerableRemaining().GetEnumerator();
}
private IEnumerable<T> GetEnumerableRemaining()
{
var enumerator = Enumerator;
Enumerator = null;
int nulls = Nulls;
Nulls = 0;
T first = First;
First = default(T);
for (int i = 0; i < nulls; i++)
{
yield return default(T);
}
yield return first;
while (enumerator.MoveNext())
{
yield return enumerator.Current;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
public static bool Is<T>(IEnumerable<T> enu, Type type, out IEnumerable<T> enu2)
{
IEnumerator<T> enumerator = null;
int nulls = 0;
try
{
enumerator = enu.GetEnumerator();
while (enumerator.MoveNext())
{
var current = enumerator.Current;
if (current == null)
{
nulls++;
continue;
}
enu2 = new RemainingIEnumerator<T>
{
Enumerable = enu,
Nulls = nulls,
First = current,
Enumerator = enumerator,
};
enumerator = null;
return current.GetType() == type;
}
// Only nulls case
enu2 = new T[nulls];
return false;
}
finally
{
if (enumerator != null)
{
enumerator.Dispose();
}
}
}
var enu1 = new object[] { null, new Dog(), new Cat(), new Dog() };
IEnumerable<object> enu2;
// From this line onward, you should use at least one enu2!
// It is the partially unwinded enu1 that has been rewinded through
// some magic :-)
bool isDog = Is(enu1, typeof(Dog), out enu2);
if (isDog)
{
// Note the use of enu2!
foreach (Dog dog in enu2.Cast<Dog>())
{
}
}
using System;
using System.Collections.Generic;
namespace ConsoleApplication34
{
interface I { };
class T1 : I { }
class T2 : I { }
class Program
{
// strongly typed arrays get assigned to base type IEnumerables.
static IEnumerable<I> i1 = new T1[] { new T1(), new T1() };
static IEnumerable<I> i2 = new T2[] { new T2(), new T2() };
static void Main(string[] args)
{
// Note: compile-time type of array elements is IEnumerable<I>!
IEnumerable<I>[] iEnumArr = new IEnumerable<I>[] { i1, i2 };
foreach (IEnumerable<I> ie in iEnumArr)
{
// ... but the run-time types of the IEnumerable objects
// are actually different.
Console.WriteLine("ienumerable is of T1: " + (ie is IEnumerable<T1>));
Console.WriteLine("ienumerable is of T2: " + (ie is IEnumerable<T2>));
}
}
}
}
ienumerable is of T1: True
ienumerable is of T2: False
ienumerable is of T1: False
ienumerable is of T2: True
for (var i = 0; i < numRequests; i++)
{
var thingsSet = things.Skip(i * 1000).Take(1000);
// I may see your problem: Now with thingsSet we have true
// Enumerables of Thing, and the tests below are always false.
// Hm.
var carSet = thingsSet as IEnumerable<car>;
var ballSet = thingsSet as IEnumerable<ball>;
bool results;
if(carSet != null ) { results = callOverLoadedFunction(carSet); }
else if(ballSet != null) { results = callOverLoadedFunction(ballSet); }
else { throw /*...*/}
}