动态声明一个变量

Declaring a variable dynamically

我有这样一个简单的用户结构:

public Guest() : IUser
{
}

[Table("Users")]
public class Customer : Guest
{
    [Key]
    public string UserName { get; set; }
    public string Password { get; set; }
    public string Address { get; set; }
    public bool IsAdmin { get;protected set; }
    public UserCart UserCart { get; private set; }

    public Customer()
    {

    }

    public Customer(string username, string password, string address)
    {
        this.Address = address;
        this.UserName = username;
        this.Password = password;
        this.IsAdmin = false;
        this.UserCart = new UserCart();
    }
}

public class Admin : Customer
{
    public Admin()
    {

    }

    public Admin(string username, string password, 
        string address) 
        : base(username, password, address)
    {
        IsAdmin = true;

    }
}

继承基于他们可以执行的 Actions。该系统将不得不根据使用它的人以不同方式工作。

管理员可以浏览和购买以及随意处理订单和商品。

客户可以浏览购买。

访客只能浏览(当然 login/reg)。

要知道谁是我们的当前用户,我们需要 Authentication class 中的 属性 或字段,即 IUser,这样任何人、管理员、客户和访客也可以在其中实例化。 问题是,当我只有这个 IUser 时,当我实例化时,我基本上什么也做不了。

所以问题是:我想加载该字段或 属性 并且我仍然想访问它的功能 - 但仅限给定用户可以访问的功能,所以如果管理员登录,我想要做管理员的工作。如果客户登录,我只希望能够列出货物等。这该怎么做?

编辑: 尝试反射

public class Guest : IUser
    {
        public Guest()
        {

        }

        public object Get()
        {
            Type type = this.GetType();
            var result = Activator.CreateInstance(type);
            return result;
        }
    }

那个Get()方法只给出一个object但是如果它被一个Guest调用,它必须是Guest。如果由 Admin 调用,则必须是 Admin。 我可以使用覆盖来做到这一点,但以后很难修改。

所以我希望这样:

(MyObject)Activator.CreateInstance(type);

其中 MyObject 如果是来宾调用则为来宾,如果是管理员调用则为 Admin。我错过了什么?当然,我尝试过泛型,但是当我实现接口时,它需要一个具体类型,所以基本上我需要在我所有的后代 类 中实现它。

根据我们在评论中讨论的内容,这里是我们服务器端游戏代码的直接复制粘贴。但要记住:如果您定义了 IUser 接口,但总是像 var customer = iUser as Customer 一样将其转换为适当的 class。你可能走错了路。我们仅在少数情况下使用以下代码。

public void DoSomethingWithBattleUnit(BattleUnit bUnit){
    if(bUnit.UnitType==typeof(BattleMonster)){
    var bMonster = bUnit as BattleMonster;
    bMonster.ActivateAI();
}


public abstract class BattleUnit {
    public abstract Type UnitType { get; }
}

public class BattleMonster : BattleUnit {
    /// <summary>
    /// Current type for this class.
    /// </summary>
    /// <remarks>Micro optimization instead of using this.GetType() or calling typeof(BattleMonster) each time.</remarks>
    static readonly Type Type = typeof(BattleMonster);

    public override Type UnitType => Type;
}

public class BattleUser : BattleUnit, IUser {

    /// <summary>
    /// Current type for this class.
    /// </summary>
    /// <remarks>Micro optimization instead of using this.GetType() or calling typeof(BattleUser) each time.</remarks>
    private static readonly Type Type = typeof(BattleUser);

    public override Type UnitType => Type;
}

这实际上是可能的,甚至没有那么难。

解决方案 1:dynamic 关键字

我有这个界面IUser和一个属性

public interface IUser
{
    dynamic Instance { get; }
}

我只在祖先中实施它,在我的例子中是客人:

public class Guest : IUser
{
    public Guest()
    {

    }

    public dynamic Instance
    {
        get
        {
            return this;
        }
    }
}

这样我就可以在 Program.cs 中像这样声明一个 IUser:

 IUser user = new Admin("wat", "asd", 012);
 Console.WriteLine(user.Instance.PW);

我得到的密码是 "asd"。

主要缺点:

由于动态,我无法使用 Intellisense。

解决方案 2:使用扩展方法

这个在实施和使用上都有点难看,但仍然可以利用 Intellisense 的强大功能。

所以这里我们有这个很好的扩展方法:

public static class Extensions
{
    public static T Get<T>(this T input) where T:class
    {
        Type t = input.GetType();
        MethodInfo method = t.GetMethod("Get");
        MethodInfo generic = method.MakeGenericMethod(t);
        return (T)generic.Invoke(input,null);
    }
}

这要求所有 classes 都有一个 Get 方法。 在我的例子中,我将在我的 IUser 界面中定义它,如下所示:

public interface IUser
{
    T Get<T>() where T : class;
}

T 必须是 class 如果我稍后要使用 as 关键字。

Get 在我的 Guest 中的实现就像

public T Get<T>() where T:class
{
     var _instance = this;
     return _instance as T;
}

当然不需要后代再执行Get

完成后我们可以获得当前类型:

 IUser adm = new Admin("wut", "mehpw", 1000);
 var stuff = adm.Get<Admin>().Name;

缺点:

我必须知道我正在使用的对象的类型,所以基本上这只不过是使用

var stuff = (adm as Admin).Name;

这里几乎没有任何优势。

我可以考虑用给定的 属性 值加载一个 class,但这与我创建的 IUser 的引用不同,肯定是 非常慢。