2017-04-09 85 views
1

我有用户喜欢这样的简单结构:声明变量动态

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; 

    } 
} 

继承是基于操作他们能做到。系统将根据使用者的不同而有所不同。

管理员可以浏览和购买订单和货物,

客户可以浏览和购买。

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

要知道谁是我们的当前用户,我们需要我们的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,它必须是客户。如果由Admin调用,它必须是Admin。 我可以使用覆盖来做到这一点,但以后很难修改。

所以,我希望这样的:

(MyObject)Activator.CreateInstance(type); 

MyObject是,如果从一个客户,管理员称为如果从管理员叫游客。我错过了什么?当然我尝试了泛型,但是当我实现接口的时候,它需要一个具体的类型,所以基本上我需要在所有的后代类中实现它。

+0

如果您想为您的案例使用此方案,正如您已经指出的那样,不能解决问题。你需要改变类继承的方式。你不这么认为吗?我认为'IUser'需要一个公共的方法'登录' –

+0

谢谢你伸出援助之手。 这不仅取决于我,还有一大堆其他方法,我只是想在此保持简单。 我的经验是,我将在'IUser'中定义的方法中使用'reflection',比如'Get()',它将返回变量的实际类型。可行? – agiro

+1

我已经在一些我们制作的游戏中使用了这个功能。基本上,我们有'Monster'类和'User'类,它们来自'Unit'。我有一个方法'GetUnitType()'defiend在基类中。它也相当快:) –

回答

1

根据我们在评论中讨论的内容,这里是我们的服务器端游戏代码的直接复制粘贴。但需要记住的一点是:如果您定义了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; 
} 
+0

感谢您的回答。我无法做到这一点是我将如何实例化? 我用我正在尝试的一些代码更新我的问题,只是片刻... – agiro

+0

你为什么这样做?我不明白为什么一个实例应该有一个成员另外说明它是什么类型。你在那里做'if(someUnit.UnitType == typeof(BattleMonster))'吗?不要这样做。只要做'if(someUnit是BattleMonster)'而不是。对象已经有了一个实际的类型。 – poke

+0

@poke是的,我们确实在少数情况下会这样做。“if(someUnit.UnitType == typeof(BattleMonster))'。很少有任何情况下使用'is'是因为它会进行强制转换,并且在大多数情况下,最终您最终将转换该变量。 –

0

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

解决方案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”的口令。

市长缺点:

我无法使用动态的智能感知因。

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

这一个有点丑陋既实现和使用,但仍然可以利用智能感知的力量。

所以在这里我们有这个优良的扩展方法:

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); 
    } 
} 

这需要所有类有一个Get方法。 在我的情况,我将像这样在我的IUSER接口定义它:

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

T公司是一类,如果我以后在使用as关键字。

Get在我的客户中实现类似

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; 

在这里几乎没有任何边缘。

我能想到的基本上加载给定的属性值的一类,但因为我的创造IUser肯定会非常慢那会不会是相同的。