2017-04-09 84 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肯定會非常慢那會不會是相同的。