2011-05-27 68 views
4

有沒有辦法強制傳遞給屬性的類型參數實現特定的接口?強制類型的屬性參數

public interface IExpectedInterface 
{ 
    void InterfaceMethod(); 
} 

public class MyCustomAttribute : Attribute 
{ 
    public MyCustomAttribute(Type classType) 
    { 
     this.ConfirmAssignedClassType(); 

     _classType = classType; 
    } 

    public void SomeMethod<T>() where T : IExpectedInterface, new() 
    { 
     //var expectedType = Activator.CreateInstance(this._classType) as IExpectedInterface; 
     var expectedType = Activator.CreateInstance(typeof(T)) as IExpectedInterface; 

     if (expectedType == null) 
     { 
      // Wrong type 

      throw new ArgumentException(string.Format("Wrong type: {0} could not be created or converted to IActionAuthorization", _classType.ToString())); 
     } 

     // Do something with expectedType 

     expectedType.InterfaceMethod(); 
    } 

    private void ConfirmAssignedClassType() 
    { 
     if (!typeof(IExpectedInterface).IsAssignableFrom(_classType)) 
     { 
      // Wrong type 
      // Can we enforce it via language construct 

      throw new ArgumentException(string.Format("Wrong type: {0} must implement IExpectedInterface", _classType.ToString())); 
     } 

     if (this._classType.GetConstructor(Type.EmptyTypes) == null) 
     { 
      // Wrong type 
      // Can we enforce it via language construct 

      throw new ArgumentException(string.Format("Wrong type: {0} must have parameter less constructor", _classType.ToString())); 
     } 
    } 

    private Type _classType; 
} 

public class TestClass 
{ 
    [MyCustom(typeof(TestClassImplementsExpectedInterface))] 
    public void TestMethod1() 
    { 
    } 

    [MyCustom(typeof(TestClassDoesntImplementExpectedInterface))] 
    public void TestMethod2() 
    { 
    } 
} 

public class TestClassImplementsExpectedInterface : IExpectedInterface 
{ 
    public void InterfaceMethod() 
    { 
     return; 
    } 
} 

public class TestClassDoesntImplementExpectedInterface 
{ 
} 

回答

5

這不能用泛型來完成嗎? (編輯 - 不能創建屬性的一個通用的子類)

public class MyAttribute: Attribute 
    { 
     private Type _ClassType; 
     public MyAttribute(Type classType) 
     { 
      _ClassType = classType; 
     } 
     public void SomeMethod<T>() where T: IMyInterface 
     { 
      var expectedType = Activator.CreateInstance(typeof(T)) as IMyInterface; 
     // Do something with expectedType 
     } 
    } 

,當然還有其他答案的翻譯用「新」,使有很大的意義!

+1

不依據此http://msdn.microsoft.com/en-us/library/ms173129(v=VS.100).aspx – 2011-05-27 19:34:07

+0

@鄧肯 - 你是對的!我會修改我的答案... – 2011-05-27 19:35:49

+0

你是對的,事實上,它不會編譯一個非常具體的錯誤!我向VS投擲了一些東西,但沒有智能錯誤,所以我錯誤地認爲它是有效的。多麼奇怪。 – 2011-05-27 19:35:51

2

您可以將您的方法轉換爲通用方法,例如

public class MyAttribute : Attribute 
{ 
    public void SomeMethod<T>() where T : ISomeInterface, new() 
    { 
     var expectedType = new T(); 
     // Do something with expectedType 
    } 
} 

new()類型約束意味着該類型必須有一個公共,無參數構造函數,這意味着你可以做new T()。這消除了使用Activator的需要。

需要注意的是,鄧肯豪指出,泛型類型不能從Attribute繼承,所以你不能做public class MyAttribute<T> : Attribute

+0

編譯時沒有任何區別,請參閱更新的代碼。 – 2011-05-27 20:08:27

+0

我不確定你的意思。如果您的意圖是限制只能從給定接口繼承的類型,那麼這應該起作用 – 2011-05-27 20:37:57

+0

在屬性中我不知道具體類型。因此,即使在TestMethod2中,該屬性傳遞的類型也不正確。 – 2011-05-27 20:44:14

3

如果由於某種原因,你不想惹仿製藥(如把所有的屬性變成一個列表或其他東西),有什麼可以被認爲是一個稍微好一點的方法,但仍然沒有編譯時檢查。你可以調用Type.IsAssignableFrom方法,而不是調用Activator.CreateInstance(根據是否有0-param ctors,它可能會也可能不會工作)(儘管看起來你假設有一個0參數ctor,所以這個可能有點沒有意義)。

if (!typeof(SomeInterface).IsAssignableFrom(_ClassType))) 
// Throw exception 
+0

這可能是更好的方法 - 如果要將'Type'參數存儲在屬性中,並將此代碼放入setter中,則您的屬性將隱式地強制實現接口繼承。 – 2011-05-27 19:51:16

0

爲什麼你不只是通過構造函數(例如Public MyAttribute(IMyInterface myObject))傳遞對象並將其存儲在一個屬性。那麼如果你需要這個類型,明確地叫typeof(myObjectProperty)

+0

任何屬性參數必須是常量,typeof表達式,並且不能是「new Foo()」之類的東西。 – Jamie 2011-05-27 19:37:41

+0

非常真實 - 應該知道(我一直在那個坑!) – 2011-05-27 19:43:46