gpt4 book ai didi

Is it possible to use a Func generic as a property that can be dynamically populated with a method?(是否可以使用Func泛型作为可以用方法动态填充的属性?)

转载 作者:bug小助手 更新时间:2023-10-22 18:19:06 35 4
gpt4 key购买 nike



I am working on a card game of sorts and I've been trying to figure out how to handle unique card effects on the Card class. I've included the class below. I'm trying to add an "effect" property to the class that can be populated in the constructor or later via a setter if needed. The problem I have is I don't know if this method will have a return type or the same return type. The simple way would seem to be to say that effect methods in the game cannot return values and simply define the property as an Action but it's definitely nice to be able to return something in certain situations (mostly testing situations where you might want to confirm the proper Card or List<Card> is returned or even the proper player or deck object).

我正在研究一款纸牌游戏,我一直在努力找出如何在纸牌类中处理独特的纸牌效果。我已经包括了下面的课程。我正在尝试向类添加一个“effect”属性,该属性可以在构造函数中填充,如果需要,可以稍后通过setter填充。我遇到的问题是,我不知道这个方法会有一个返回类型还是相同的返回类型。简单的方法似乎是说游戏中的效果方法不能返回值,并简单地将属性定义为Action,但在某些情况下能够返回一些东西肯定是很好的(主要是测试情况,您可能想确认返回了正确的卡或列表<卡>,甚至是正确的玩家或牌组对象)。


I'm extremely new to c# and am probably missing something or misunderstanding generics. I've added type object because that gets me out the door with the getter and setter but I don't know if object will inherently allow me to return a class the isn't actually extended from object.

我对c#非常陌生,可能会遗漏一些东西或误解泛型。我添加了类型对象,因为这让我可以使用getter和setter,但我不知道对象是否固有地允许我返回一个实际上不是从对象扩展的类。


using System;
[System.Serializable]

public class Card
{
public int Id { get; set; }
public string Title { get; set; }
public int Cost { get; set; }
public int Power { get; set; }
public string Description { get; set; }
public Func<object> Effect { get; set; }

public Card()
{

}

public Card(int id, string title, int cost, int power, string description, Func<object> effect)
{
Id = id;
Title = title;
Cost = cost;
Power = power;
Description = description;
Effect = effect;
}
}

I initially tried just defining it as:

我最初尝试将其定义为:


private Func<> effect;

public Func<> Effect
{
get { return effect; }
set { effect = value; }
}

I expected that without defining a type it would allow me to return a non-null type but I suspect I'm misunderstanding the usage of generics here.

我原以为在不定义类型的情况下,它会允许我返回一个非null类型,但我怀疑我误解了这里泛型的用法。


更多回答

One thing you definitely want to learn about is automatically-implemented properties: learn.microsoft.com/en-us/dotnet/csharp/programming-guide/… - all of your code other than the constructors could be done in just 6 lines. (I'd also recommend you follow conventions around parameter names, and remove those underscores.)

你肯定想了解的一件事是自动实现的属性:learn.microsoft.com/en-us/dotnet/csharp/programming guide/…-除了构造函数之外,你的所有代码都可以在6行中完成。(我还建议您遵循参数名称的约定,并删除这些下划线。)

well, you can use generics, however you have to provide a type-argument when you use the Card-class, e.g. new Card<MyType>(...) making the entire class itself generic - not just the property, which is not possible.

好吧,你可以使用泛型,但是当你使用Card类时,你必须提供一个类型参数,例如new Card<MyType>(…)使整个类本身成为泛型,而不仅仅是属性,这是不可能的。

if object will inherently allow me to return a class the isn't actually extended from object. .. that's impossible ;) object is the implicit mother class of everything in c#

如果对象本质上允许我返回一个类,那么它实际上并不是从对象扩展的。。这是不可能的;)object是c中所有事物的隐含母类#

Separately, it's basically not clear to me how the effect is going to be used. Maybe you want Card to be generic, but it's hard to know, because we don't know enough about the use case.

另外,我基本上不清楚这种效果将如何使用。也许您希望Card是通用的,但很难知道,因为我们对用例了解不够。

Thanks for the additional documentation @JonSkeet. I've updated the class to reflect that information. I was trying to follow the best standards I could find but a lot of youtube tutorial videos and such are dated. The idea here is for the Card class to be a blueprint for all cards in the game. Not a generic, but more of something for future cards to potentially extend. The effects property is meant to hold a method defined in the card constructor that might call a variety of other methods such as: Deck.PutOnTop(Card) Deck.Shuffle() Deck.Draw(int) Deck.Search(Card)

感谢JonSkeet提供的额外文档。我已经更新了课程以反映这些信息。我试图遵循我能找到的最好的标准,但很多youtube教程视频都过时了。这里的想法是让卡类成为游戏中所有卡的蓝图。不是通用的,但更多的是未来卡片可能扩展的东西。effects属性用于保存卡构造函数中定义的方法,该方法可能会调用各种其他方法,例如:Deck.PutOnTop(card)Deck.Shuffle()Deck.Draw(int)Deck.Search(card)

优秀答案推荐

Proper use of a generic would be e.g.

恰当地使用通用术语例如。


private Func<T> effect;
public Func<T> Effect => effect;

This would require though that Card itself is generic as well (Card<T>) with the same type restrictions.

这需要卡本身也是通用的(卡<T>),具有相同的类型限制。


The only exception is having a method which allows you to pass in the generic type once you call it

唯一的例外是有一个方法,它允许您在调用泛型类型时传入它


public Func<T> GetEffect<T>()
{
return ???;
}

This very much depends on your other code though and how exactly you are intending to consume this property. If you go for generics you will also need to explicitly provide a type when you consume it.

这在很大程度上取决于您的其他代码以及您打算如何使用此属性。如果你使用泛型,你还需要在使用它时显式地提供一个类型。


So I just claim now this is most probably not what you wanted to do anyway.

所以我现在声称这很可能不是你想做的。




I think instead you might want to rather have something like e.g.

相反,我认为你可能更想要一些类似的东西。


public interface ICardEffect
{
public void RunEffect(/*whatever you need like e.g. GameManager etc*/);
}

and then rather

然后


public ICardEffect Effect { get; private set; }

this you can pass in via the constructor and consume properly without needing to know/return the exact implementing type.

这可以通过构造函数传递并正确使用,而无需知道/返回确切的实现类型。


This will still make little sense in a [Serializable] class which you configure via the Inspector which will not use any special constructor but rather the default parameter-less one.

这在您通过Inspector配置的[Serializable]类中仍然没有什么意义,Inspector不会使用任何特殊的构造函数,而是使用默认的无参数构造函数。




Alternative Approach


I think in your Unity specific case you would be better of using ScriptableObject assets. A ScriptableObject is mainly intended to be a "data container" but in the end it is a c# class so it can also implement own behavior. Something I use to call "scriptable behavior".

我认为在您的Unity特定情况下,您最好使用ScriptableObject资产。ScriptableObject主要是作为一个“数据容器”,但最终它是一个c#类,因此它也可以实现自己的行为。我习惯称之为“可脚本化行为”。


[CreateAssetMenu]
public class Card : ScriptableObject
{
//[field: SerializeField] public int Id { get; private set;} // don't really need this as the asset reference is unique already
//[field: SerializeField] public string Title { get; private set;} // don't really need this as the asset itself already has a name
[field: SerializeField] public int Cost { get; private set;}
[field: SerializeField] public int Power { get; private set;}
[field: SerializeField] public string Description { get; private set;}

[field: SerializeField] public CardEffect Effect { get; private set;}
}

You create instances of this via the Assets -> right click -> Create -> Card

您可以通过“资产”->右键单击->“创建”->“卡片”来创建此实例


And then populate it via the Inspector. Later you can use this just as you would e.g. Textures and other assets and drag it into your game managers list for instance.

然后通过Inspector进行填充。稍后,您可以像使用纹理和其他资产一样使用它,并将其拖动到游戏管理器列表中。


And then for the CardEffect you do the same and have e.g.

然后对于CardEffect,你也可以这样做,并有例如。


public abstract class CardEffect : ScriptableObject
{
public abstract void RunEffect(/*whatever you need like e.g. GameManager etc*/);
}

and then create specific effects like e.g. (I don't know your use case and types of course)

然后创建特定的效果,例如(我当然不知道你的用例和类型)


[CreateAssetMenu]
public class DrawEffect : CardEffect
{
[SerializeField][Min(1)] int amount = 1;

public override void RunEffect(GameManager game)
{
game.DrawCard(amount);
}
}

you can create as many subtypes of effects as you wish and reference them in your Card instances. You can even make the Card.Effect rather a list and chain combine multiple effects together.

您可以创建任意数量的效果子类型,并在您的卡实例中引用它们。你甚至可以把卡片效果做成一个列表和链条,把多个效果组合在一起。




The problem I have is I don't know if this method will have a return type or the same return type



You have to have specify some return type, possibly object, or a generic type. Using a generic type does not make much sense, since you cannot use it, since it is of some unknown type (unless you use a generic restriction). If you return an object you can at least check the type. But chances are you should use an event instead of an action/func property.

您必须指定一些返回类型,可能是对象或泛型类型。使用泛型类型没有多大意义,因为您不能使用它,因为它是某种未知类型(除非您使用泛型限制)。如果您返回一个对象,您至少可以检查类型。但您可能应该使用事件而不是action/func属性。



I don't know if object will inherently allow me to return a class the isn't actually extended from object



All types in c# derive from object. Note that value types will be boxed when used in this way.

c#中的所有类型都派生自对象。请注意,以这种方式使用时,值类型将被装箱。


更多回答

I think perhaps this ScriptableObject approach makes more sense but I had read about issues with ScriptableObject in multiplayer. I believe the stuff I read stated that scriptable object is shared between players and added some additional complication.

我认为这种ScriptableObject方法可能更有意义,但我读过关于多人游戏中ScriptableObject的问题。我相信我读到的东西表明,可编写脚本的对象在玩家之间共享,并增加了一些额外的复杂性。

Well ScriptableObject is an asset .. like material or texture .. so if you reference that in multiple places yes, you are using the same instance. But as you can see above the card asset itself only has some values and the effect does stuff .. it wouldn't matter at all if two things reference the same .. this has little to do with multiplayer at all tbh

Well ScriptableObject是一种资产。。类似材料或质地。。因此,如果你在多个地方引用了它,是的,你使用的是同一个实例。但正如你在上面看到的,卡片资产本身只有一些价值,效果确实很好。。如果两个事物引用相同的东西,那根本没关系。。这与多人游戏毫无关系

That totally makes sense, thanks for clarifying. I think I'll take a shot at it this way and this is actually more scalable to some of the other systems we wanted to implement as far as cards being upgraded with additional effects (ala Monster Train).

这完全有道理,谢谢你的澄清。我想我会用这种方式尝试一下,事实上,这对我们想要实现的其他一些系统来说更具可扩展性,比如升级带有额外效果的卡(比如怪物列车)。

when I use the example above it says that [MinValue(1)] is missing a namespace. I dug around and it appears that int32 Min Value should be in System.Runtime.dll but including "using System" or "using System.Runtime" didn't resolve it.

当我使用上面的例子时,它说[MinValue(1)]缺少一个名称空间。我仔细研究了一下,发现int32 Min Value应该在System.Runtime.dll中,但包括“using System”或“using System.Runtime”并没有解决它。

try [Min] instead ... is a Unity attribute and I always confuse them (I think Odin provides MinValue and MaxValue)^^

请尝试[Min]。。。是Unity属性,我总是混淆它们(我认为Odin提供了MinValue和MaxValue)^^

35 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com