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 /*...*/}
    }