从另一个泛型类添加一个泛型方法约束 [英] Adding a generic method constraint from the another generic class

查看:127
本文介绍了从另一个泛型类添加一个泛型方法约束的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我不知道标题反映了我的意思的问题,但..结果
比方说,我有两个类,实体组件

I'm not sure the title reflect the question that I was meant, but..
Let's say I have two classes, Entity and Component:

public abstract class Entity
{
    private List<Component> _components = new List<Component>();

    public void AddComponent<T>()
        where T : Component
    {
        T component = (T)Activator.CreateInstance(typeof(T));
        component.Owner = this;

        _components.Add(component);
    }
}

public abstract class Component
{
    public Entity Owner { get; protected set; }

    public abstract void Update();
}

正如您可能注意到,上述类抽象类这意味着不打算直接使用。然而,在发展的后期,我知道,有些组件要求的能力,只有安装/由继承了实体<特定类添加/ code>类

As you may notice, above classes are abstract classes which mean is not intended for direct use. However, on the later stage of development, I'm aware that some Component require ability that only attachable / Added by specific class that inherited to Entity class.

所以,我添加了一个类组件< T> 继承组件

So, I added a class Component<T> that inherit Component:

public abstract class Entity
{
    private List<Component> _components = new List<Component>();

    public void AddComponent<T>()
        where T : Component
    {
        T component = (T)Activator.CreateInstance(typeof(T));
        component.Owner = this;

        _components.Add(component);
    }
}

public abstract class Component
{
    public Entity Owner { get; protected set; }

    public abstract void Update();
}

public abstract class Component<T> : Component
{
    // I hide the base.Owner with new keyword
    // feel free to suggest me in case there is better approach to do this
    new public T Owner 
    { 
        get { return (T)base.Owner; } 
        protected set { base.Owner = value; }
    }
}



现在,让我们说我有酒吧处理器类:

public class Foo : Entity
{
    public int FooValue { get; set; }
}

public class Bar : Entity
{
    public int BarValue { get; set; }
}

public class Processor : Component<Foo>
{
    public override void Update()
    {
        Owner.FooValue = 10;
    }
}



我想要做的就是让处理器类只加载能够通过对象。目前, AddComponent 忽略它,所以我不知道该怎么做:

What I want to do is to make Processor class only add-able by Foo object. Currently AddComponent ignore it, so I don't know how to do that:

var foo = new Foo();
var bar = new Bar();

foo.AddComponent<Processor>(); // OK
bar.AddComponent<Processor>(); // Compiler should give an error at this point



我也试着这样做:

I also tried to do this:

public void AddComponent<T, X>()
    where T : Component<X>
    where X : Entity
{
    T component = (T)Activator.CreateInstance(typeof(T));
    component.Owner = this;

    _components.Add(component);
}



然而,它要求我明确地指定x约束:

However, it require me to explicitly specify the X constraint:

foo.AddComponent<Processor, Foo>();
bar.AddComponent<Processor, Bar>(); // Error, but the syntax is weird!



任何想法?

Any ideas?

推荐答案

您文章没有什么明确的约束,如果有的话,你有你的基本实体组件类。所以,我不知道若跌破将在您的方案是可行的。不过,我相信,如果不是的话,你将无法做你想要什么,因为否则泛型类型参数不会被编译器知道。

Your post isn't clear on what constraints, if any, you have on your basic Entity and Component classes. So I don't know if the below will be feasible in your scenario. That said, I believe that if it's not, you won't be able to do what you want because otherwise the generic type parameters won't be known by the compiler.

解决方案,在没有任何其他限制,就是让你的实体类通用的,并提供子类类型本身的类型参数:

The solution, absent any other constraints, is to make your Entity class generic, and provide the sub-class type itself as the type parameter:

class Entity { }

class Entity<T> : Entity where T : Entity<T>
{
    public void AddComponent<U>(U value) where U : Component<T> { }
}

class Component<T> where T : Entity { }

class Foo : Entity<Foo> { }

class Bar : Entity<Bar> { }

class P : Component<Foo> { }



我知道这看起来很奇怪。但是你基本上要求泛型类型依赖的自我指涉的图形,并在C#代码上面是什么样子。

I know it looks weird. But you're basically asking for a self-referential graph of generic type dependencies, and in C# code the above is what that looks like.

您可以致电 AddComponent()使用方法类型推断(所以不需要泛型参数)。如果你试图用错误的类型元件与LT的称呼它; T> 的对象,你会得到一个编译器错误:

You can call the AddComponent() method using type inference (so no generic parameter needed). If you try to call it with the wrong type of Component<T> object, you'll get a compiler error:

Foo foo = new Foo();
Bar bar = new Bar();
P p = new P();

foo.AddComponent(p);
bar.AddComponent(p); // CS0311





注:我会强烈反对隐藏类成员。它并不真正影响你的问题的规定(即你可以离开这个细节完全出来),但具有相同名称的两个不同的属性只是要求的错误。如果你的必须的使用隐藏,恕我直言,你至少应该有新的属性使用隐藏属性。 。例如:


Note: I would strongly recommend against hiding class members. It doesn't really affect your question as stated (i.e. you could have left that detail out completely), but having two different properties with the same name is just asking for bugs. If you must use hiding, IMHO you should at least have the new property use the hidden property. E.g.:

class Component
{
    public Entity Owner { get; protected set; }
}

class Component<T> : Component where T : Entity
{
    new public T Owner
    {
        get { return (T)base.Owner; }
        set { base.Owner = value; }
    }
}

您不会得到编译时检查上分配到非通用 Component.Owner 属性,但至少在某些代码试图你会得到一个运行时错误取消引用所有者属性作为通用版本,如果当错误类型是由基本类型出于某种原因分配。

You won't get compile-time checking on assignments to the non-generic Component.Owner property, but at least you'll get a run-time error if some code tries to dereference the Owner property as the generic version, if and when the wrong type was assigned by the base type for some reason.

这篇关于从另一个泛型类添加一个泛型方法约束的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆