C# 动态声明变量

C# 动态声明变量,c#,backend,code-organization,C#,Backend,Code Organization,我的用户结构很简单,如下所示: 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 {

我的用户结构很简单,如下所示:

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;

    }
}
继承基于他们可以执行的操作。该系统必须根据使用它的人的不同而工作

管理员可以浏览、购买和处理订单和商品

顾客可以浏览和购买

客人只能浏览(当然还有登录/注册)

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

所以问题是:我想加载那个字段或属性,我仍然想访问它的功能——但只有给定用户可以访问的功能,所以如果管理员登录,我想做管理员的工作。如果客户登录,我只希望能够列出商品等等。如何做到这一点

编辑:尝试反射

public class Guest : IUser
    {
        public Guest()
        {

        }

        public object Get()
        {
            Type type = this.GetType();
            var result = Activator.CreateInstance(type);
            return result;
        }
    }
Get()
方法只提供了一个
对象
,但如果它被
Guest
调用,它必须是Guest。如果由
管理员调用
,则必须是Admin。 我可以使用覆盖来实现这一点,但以后很难修改

因此,我希望:

(MyObject)Activator.CreateInstance(type);

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

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

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;
}
public void dosomething与作战单元(作战单元bUnit){
if(bUnit.UnitType==typeof(战斗怪物)){
var bMonster=布尼特作为战斗怪物;
b激活EAI();
}
公共抽象类作战单元{
公共抽象类型UnitType{get;}
}
公共级战斗怪物:战斗单位{
/// 
///此类的当前类型。
/// 
///微优化,而不是每次都使用这个.GetType()或调用typeof(BattleMonster)。
静态只读类型=类型(战斗怪物);
公共覆盖类型UnitType=>Type;
}
公共类战斗用户:战斗单位,IUser{
/// 
///此类的当前类型。
/// 
///微优化,而不是每次都使用这个.GetType()或调用typeof(BattleUser)。
私有静态只读类型=类型(用户);
公共覆盖类型UnitType=>Type;
}

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

解决方案1:
动态
关键字

我有这个接口
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);
    }
}
如果我以后要使用
作为
关键字,那么T必须是一个类

在my Guest中实现
Get
,如下所示

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

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

var stuff = (adm as Admin).Name;
所以这里几乎没有边缘


我可以考虑基本上用给定的属性值加载一个类,但这与我创建的
IUser
引用不同,而且肯定会非常缓慢。

如果您想在您的案例中使用此方案,正如您已经指出的那样,是行不通的。您需要更改类继承的方式。不要你不这么认为吗?我想,
IUser
需要一个公共方法
Login
谢谢你的帮助。这不仅取决于我,还有很多其他方法,我只是想在这里保持简单。我想,我将在
IUser
中定义的方法中使用
反射,比如
Get()
这将返回变量的实际类型。可行吗?我已经在我们制作的一些游戏中使用了它。基本上,我们有
Monster
类和
User
类,它们来自
Unit
。我有一个方法
GetUnitType()
在基类中定义。它也很快:)很高兴我们想到了同样的事情。你能告诉我你是如何在那里做到的吗?很明显,在我的类中使用if-elseif等等,但我需要一些通用的东西,现在我所能做的就是使用
Activator.CreateInstance(typeOfMyObject)
,但我必须将其强制转换为我的类型。或者我应该在我所有的类中重写这个
Get()
?“问题是,当我只有这个IUser时,当我实例化时,我基本上什么也做不了。”–这些用户类型有什么共同点?这就是公共界面中应该有的。如果它们没有任何共同点,那么它们可能根本就不共享相同的基本类型。谢谢你的回答。我无法理解的是,我该如何从中实例化?我用一些我正在尝试的代码更新我的问题,只是一个妈妈ent…你为什么要这样做?我不明白为什么一个实例应该有一个额外说明它是什么类型的成员。你是在做
if(someUnit.UnitType==typeof(BattleMonster))
吗?不要这样做。只要做
if(someUnit是BattleMonster)
就可以了
 IUser adm = new Admin("wut", "mehpw", 1000);
 var stuff = adm.Get<Admin>().Name;
var stuff = (adm as Admin).Name;