IEnumerable.单一和铸造

发布于 2024-12-13 10:34:00 字数 479 浏览 0 评论 0原文

我有 2 个对象 A 和 B。B 继承自 A 并且具有更多属性。 我有 IEnumerable{A} 仅包含 B 对象。 我想做的是:

list.Single(b => b.PropertyThatOnlyExistOnB == "something")

我希望这样的事情能够工作:

list.Single((B) b => b.PropertyThatOnlyExistOnB == "something")

但它无法编译。现在我只是在做:

B result = null;
foreach (b in list)
{
     if((B)b.PropertyThatOnlyExistOnB == "something")
     {
      result = (B)b;
     }
}

有没有更短的方法? 谢谢

I a have 2 objects A and B. B is inherited from A and has some more properties.
I have IEnumerable{A} that contains only B objects.
What I want to do is:

list.Single(b => b.PropertyThatOnlyExistOnB == "something")

I would have expect something like this to work:

list.Single((B) b => b.PropertyThatOnlyExistOnB == "something")

But it doesn't compile. For now I just doing:

B result = null;
foreach (b in list)
{
     if((B)b.PropertyThatOnlyExistOnB == "something")
     {
      result = (B)b;
     }
}

Is there a shorter way?
Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

路弥 2024-12-20 10:34:00

使用 Enumerable.OfType过滤/转换的扩展方法。

list.OfType<B>().Single(b => b.PropertyThatOnlyExistOnB == "something")

Use the Enumerable.OfType<TResult> extension methods to filter/cast.

list.OfType<B>().Single(b => b.PropertyThatOnlyExistOnB == "something")
南风起 2024-12-20 10:34:00

虽然我最喜欢@VirtualBlackFox的答案,但为了完整起见:以下是如何让你的想法发挥作用:

list.Single(b => ((B)b).PropertyThatOnlyExistOnB == "something");

你并没有偏离轨道,只是你的一些语法感到困惑。 b =>; EXPRESSION 语法表示 lambda 表达式。除非您想添加(或删除)参数,否则您无法开始更改 => 之前的内容:

* `x => LAMBDA_WITH_ONE_PARAMETER`
* `(x) => LAMBDA_WITH_ONE_PARAMETER`
* `() => LAMBDA_WITH_NO_PARAMETERS`
* `(x, y, z) => LAMBDA_WITH_THREE_PARAMETERS`

Although I like @VirtualBlackFox's answer best, for completeness sake: Here is how to get your idea to work:

list.Single(b => ((B)b).PropertyThatOnlyExistOnB == "something");

You weren't that far off track, except that you got some of the syntax confused. The b => EXPRESSION syntax denotes a lambda expression. You can't start altering the stuff before the =>, unless you want to add (or remove) arguments:

* `x => LAMBDA_WITH_ONE_PARAMETER`
* `(x) => LAMBDA_WITH_ONE_PARAMETER`
* `() => LAMBDA_WITH_NO_PARAMETERS`
* `(x, y, z) => LAMBDA_WITH_THREE_PARAMETERS`
℉服软 2024-12-20 10:34:00

我有仅包含 B 对象的 IEnumerable


我会对这个关于你的变量的陈述提出质疑。您已指定它是 IEnumerable,但它仅包含 B 的实例。这样做的目的是什么?如果您在所有情况下都明确只需要 B 实例,那么最好将其设置为 IEnumerable,因为它可以防止可能在以下位置捕获的问题:编译时间。

考虑以下内容,我想您可能有一些类似于以下内容的代码:

var setOfA = // Get a set of A.
DoSomethingWithA(setOfA);

var instanceOfB = GetInstanceOfB(setOfA);

在这种情况下,我可以理解 IEnumerable 是完全有效的,除非您想执行后一个操作, GetInstanceOfB。让我们想象一下,定义是:

B GetInstanceOfB(IEnumerable<A> setOfA)
{
    return // The answer to your question.
}

现在,我希望您看到的最初问题是,您将所有卡片都放在这样的概念上:您的列表(在我的示例中为setOfA)始终只会去包含 B 的实例。虽然您可以保证从开发人员的角度来看,编译器不会做出这样的假设,但它只能保证 setOfA (列表)是 IEnumerable,这就是潜在的问题。

查看提供的答案(根据您的想法,所有这些答案都是完全有效的[@VirtualBlackFox 是最安全的答案]):

我有仅包含 B 对象的 IEnumerable


如果在将来的某些更改中,setOfA 还包含 C 的实例(A 的潜在未来子类),该怎么办?给出这个答案:

list.Single(b => ((B)b).PropertyThatOnlyExistOnB == "something");

如果 setOfA 实际上是:[CBB] 会怎样。您可以看到显式转换 (B)b 将导致抛出 InvalidCastException。由于 Single 操作的性质,它将继续枚举,直到第一个实例失败谓词(PropertyThatOnlyExistOnB == "something"),或者出现异常抛出。在这种情况下,可能会抛出意外的异常,并且可能未处理。这个答案类似于:

list.Cast<B>().Single(b => b.PropertyThatOnlyExistOnB == "something");

给出这个答案:

list.Single<A>(b => (b as B).PropertyThatOnlyExistOnB == "something")

在相同的情况下,异常将作为 NullReferenceException 的抛出实例出现,因为 C 的实例无法安全地键入转换为B

现在,请不要误会我的意思,我不会在这些答案中找漏洞,正如我所说,考虑到您的问题的范围,它们是完全有效的。但在代码发生更改的情况下,那些完全有效的答案将成为未来潜在的问题。

给出这个答案:

list.OfType<B>.Single(b => b.PropertyThatOnlyExistOnB == "something");

这允许您安全地类型转换为 A 的潜在子集,实际上是 B,并且编译器可以保证您的谓词仅用于一个 IEnumerable

但这会让我发现代码中的接合点正在尝试处理您的 IEnumerable 但在您真正想要 IEnumerable 的地方执行操作。在这种情况下,您不应该重构此代码以使其可能具有显式方法吗:

B GetMatchingInstanceOfB(IEnumerable<B> setOfB)
{
    if (setOfB == null) throw new ArgumentNullException("setOfB");

    return setOfB.Single(b => b.PropertyThatOnlyExistOnB == "something");
}

方法设计的更改确保它仅显式接受一组有效的 B,而您不需要不必担心该方法中的演员表。该方法只负责匹配B的单个项目。

这当然意味着您需要将转换推向不同的级别,但这仍然更加明确:

var b = GetMatchingInstanceOfB(setOfA.OfType<B>());

我还假设您在所有实例都失败的情况下有足够的错误处理。 >B,例如,超过 1 个项目满足 PropertyThatOnlyExistOnB == "something"

这可能是关于审查代码的毫无意义的咆哮,但我认为值得考虑可能出现的意外情况,以及调整变量如何可能在未来为您省去潜在的麻烦。

I have IEnumerable<A> that contains only B objects.

I would question this statement about your variable. You've specified that it is an IEnumerable<A>, but it contains only instances of B. What is the purpose of this? If you are explicitly only requiring instances of B in all circumstances, it would be better for this to be an IEnumerable<B>, as it safeguards problems that could be caught at compile time.

Consider the following, I would imagine that you may have some code similar to:

var setOfA = // Get a set of A.
DoSomethingWithA(setOfA);

var instanceOfB = GetInstanceOfB(setOfA);

In this case, I can understand that an IEnumerable<A> is perfectly valid, except when you want to perform the latter operation, GetInstanceOfB. Let's imagine, the definition is:

B GetInstanceOfB(IEnumerable<A> setOfA)
{
    return // The answer to your question.
}

Now, the initial problem I hope you see, is that you're putting all your cards on the notion that your list (setOfA in my example), is always only going to contain instances of B. While you may guarantee that from your developer point of view, the compiler can make no such assumption, it can only guarantee that setOfA (list) is an IEnumerable<A>, and therein lies the potential issue.

Looking at the answers provided (all of which are perfectly valid [@VirtualBlackFox being the safest answer] given your notion):

I have IEnumerable<A> that contains only B objects.

What if, in some future change, setOfA, also contains an instance of C (a potential future subclass of A). Given this answer:

list.Single(b => ((B)b).PropertyThatOnlyExistOnB == "something");

What if setOfA is actually: [C B B]. You can see that the explicit cast (B)b will cause an InvalidCastException to be thrown. Because of the nature of the Single operation, it will continue to enumerate until the first instance that something fails the predicate (PropertyThatOnlyExistOnB == "something"), or an exception is thrown. In this instance, the exception could be thrown which is unexpected, and likely unhandled. This answer, is similar to:

list.Cast<B>().Single(b => b.PropertyThatOnlyExistOnB == "something");

Given this answer:

list.Single<A>(b => (b as B).PropertyThatOnlyExistOnB == "something")

In the same situation, the exception would arise as a thrown instance of NullReferenceException, because the instance of C cannot be safely type cast to B.

Now, don't get me wrong, I am not picking holes with those answers, as I said they are perfectly valid given the remit of your question. But in circumstances where your code changes, those perfectly valid answers become potential future issues.

Given this answer:

list.OfType<B>.Single(b => b.PropertyThatOnlyExistOnB == "something");

This allows you to safely type cast to a potential subset of A that are in fact B, and the compiler can guarantee that your predicate is only being used on an IEnumerable<B>.

But this would lead me to discovering that the juncture in your code is trying to handle your IEnumerable<A> but perform an operation where you really want your IEnumerable<B>. In which case, shouldn't you refactor this code to possibly have an explicit method:

B GetMatchingInstanceOfB(IEnumerable<B> setOfB)
{
    if (setOfB == null) throw new ArgumentNullException("setOfB");

    return setOfB.Single(b => b.PropertyThatOnlyExistOnB == "something");
}

The change in the design of the method ensures that it will only explicitly accept a valid set of B, and you don't have to worry about your cast within that method. The method is responsible only for matching a single item of B.

This of course means you need to push your cast out to a different level, but that still is much more explicit:

var b = GetMatchingInstanceOfB(setOfA.OfType<B>());

I'm also assuming that you have sufficient error handling in place in circumstances where the predicate will fail where all instances are B, e.g., more than 1 item satisfies PropertyThatOnlyExistOnB == "something".

This might have been a pointless rant about reviewing your code, but I think it is worth considering unexpected situations that could arise, and how potentially tweaking your variables can save you a potential headache in the future.

嘿嘿嘿 2024-12-20 10:34:00

这应该可以正常工作:

list.Single<A>(b => (b as B).PropertyThatOnlyExistOnB == "something")

如果您不想冒抛出异常的风险,您可以这样做:

list.Single<A>(b => ((b is B)&&((b as B).PropertyThatOnlyExistOnB == "something")))

This should work fine:

list.Single<A>(b => (b as B).PropertyThatOnlyExistOnB == "something")

If you dont want to risk exceptions to be thrown you can do this:

list.Single<A>(b => ((b is B)&&((b as B).PropertyThatOnlyExistOnB == "something")))
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文