C# “classwhere T:IList”和类型为“IList”的字段之间有什么区别

C# “classwhere T:IList”和类型为“IList”的字段之间有什么区别,c#,generics,inheritance,C#,Generics,Inheritance,这两者有什么区别,正确的是什么 public interface IMessage { /// <summary> /// Array used to hold all bytes that will be written. /// </summary> IList Buffer { get; set; } } 及 编辑1:已修复-接口上不能有字段。谢谢你 编辑2:已修复-接口上不能有封装。感谢KeithS如果不介意语法错误的话,它们在概

这两者有什么区别,正确的是什么

public interface IMessage
{
    /// <summary>
    /// Array used to hold all bytes that will be written.
    /// </summary>
    IList Buffer { get; set; }
}

编辑1:已修复-接口上不能有字段。谢谢你
编辑2:已修复-接口上不能有封装。感谢KeithS

如果不介意语法错误的话,它们在概念上都是正确的,在语义上的意思几乎是一样的——因为接口不能有字段,如果它们被定义为属性,这就很好了


泛型版本允许您返回除IList以外的类型-因此可以返回列表而不是接口类型。

如果不介意语法错误的话,这两种类型在概念上是正确的,在语义上的含义几乎相同-因为接口不能有字段,如果它们被定义为属性,这将很好


泛型版本允许您返回除IList之外的类型-因此可以返回列表而不是接口类型。

如果我记得正确,在第二个变体中,您可以使用IList作为自己的类。

如果我记得正确,在第二个变体中,您可以使用IList作为自己的类。

在第一种情况下,缓冲区定义为IList类型。在运行时,它可以被分配给IList的任何实现,该接口实现的任何创建者都不必确切知道将使用什么实现。但是,在运行时,代码无法知道使用了哪种具体的实现,因此在设计时,当将此属性作为接口的成员引用时,您将永远无法访问IList接口未显式公开的任何方法

在第二种情况下,您正在定义泛型。如果此泛型定义保持打开状态,并且未定义T,则仍将限制您使用IList的方法。但是,必须关闭此泛型,或者是接口的实现,或者是保持泛型打开的实现的特定实例的定义。一旦关闭泛型,就可以知道确切的、具体的缓冲区类型,并且可以对其调用不一定由IList定义的方法。但是,一旦关闭泛型,就不能为定义特定泛型类型的实例或类提供不同的IList实现来用作缓冲区

因此,一些示例假设您无法在接口上指定的受保护字段实际上是一个可变的公共属性:

//this class implements the non-generic interface, so buffer is an IList.
class MyMessage1: IMessage
{
   public IList buffer {get;set;}

   public MyMessage1()
   {
      buffer = new List<string>();

      //even though you "know" what you just assigned, 
      //you cannot refer to buffer as a List<string>, even here.
      buffer.Sort(); //error
   }
}

...

//The exact type of buffer cannot be known statically, 
//so only non-generic IList methods are allowed
var myMessage = new MyMessage1();
myMessage.buffer.Add("my message"); //valid; string literals are Objects
var firstLen = myMessage.buffer[0].Length; //error: indexer returns Objects.
myMessage.Sort(); //error: IList does not have a Sort() method.
firstLen = GetFirstLength(myMessage); //error: not an IMessage<List<string>>
//but, an IList is an IList no matter what, so this works.
myMessage.buffer = new List<int>(); 

...

//this class keeps the generic open so T can be any IList, determined at instantiation.
class MyMessage2<T>:IMessage<T> where T:IList
{
    public T buffer {get;set;}

    //buffer's exact type is still not known here,
    //so inside this class you are still restricted to IList members only
    public int BufferCount{get{return buffer.Count;}}

    public void SortBuffer()
    {
       buffer.Sort(); //error; no such method
    }    
}

...

//but, once you define an instance, you know exactly what buffer is
var myMessage = new MyMessage2<List<string>>();
myMessage.buffer.Add("my message");
var firstLen = myMessage.buffer[0].Length; //now we know the indexer produces strings.
myMessage.buffer.Sort(); //buffer is known to be a List<T> which has Sort()
firstLen = GetFirstLength(myMessage);

...

//and when you pass it as a parameter, you can close the generic of the interface
public string GetFirstLength(IMessage<List<string>> message) 
{
   //...so you still know what you're dealing with
   return message.buffer[0].Length;
}

...

//however, buffer is now "strongly typed" and the implementation can't change
myMessage.buffer = new List<int>(); //error; buffer is of type List<string>

...

//this class closes the generic within the declaration.
class MyMessage3:IMessage<IList<string>>
{
   //now we're closing the generic in the implementation itself,
   //so internally we know exactly what we're dealing with
   public List<string> buffer {get;set;}

   //...so this call is valid
   public void SortBuffer() { buffer.Sort(); }
}

//...and consuming code doesn't have to (get to?) specify the implementation of T
var myMessage = new MyMessage3();
//... but still knows exactly what that implementation is
myMessage.buffer.Add("my message");
var firstLen = myMessage.buffer[0].Length;
myMessage.buffer.Sort();

//and btw, MyMessage3 is still an IMessage<List<string>>
firstLen = GetFirstLength(myMessage);

//... and buffer's still a strongly-typed List<string>
myMessage.buffer = new List<int>(); //error

在第一种情况下,缓冲区被定义为IList类型。在运行时,它可以被分配给IList的任何实现,该接口实现的任何创建者都不必确切知道将使用什么实现。但是,在运行时,代码无法知道使用了哪种具体的实现,因此在设计时,当将此属性作为接口的成员引用时,您将永远无法访问IList接口未显式公开的任何方法

在第二种情况下,您正在定义泛型。如果此泛型定义保持打开状态,并且未定义T,则仍将限制您使用IList的方法。但是,必须关闭此泛型,或者是接口的实现,或者是保持泛型打开的实现的特定实例的定义。一旦关闭泛型,就可以知道确切的、具体的缓冲区类型,并且可以对其调用不一定由IList定义的方法。但是,一旦关闭泛型,就不能为定义特定泛型类型的实例或类提供不同的IList实现来用作缓冲区

因此,一些示例假设您无法在接口上指定的受保护字段实际上是一个可变的公共属性:

//this class implements the non-generic interface, so buffer is an IList.
class MyMessage1: IMessage
{
   public IList buffer {get;set;}

   public MyMessage1()
   {
      buffer = new List<string>();

      //even though you "know" what you just assigned, 
      //you cannot refer to buffer as a List<string>, even here.
      buffer.Sort(); //error
   }
}

...

//The exact type of buffer cannot be known statically, 
//so only non-generic IList methods are allowed
var myMessage = new MyMessage1();
myMessage.buffer.Add("my message"); //valid; string literals are Objects
var firstLen = myMessage.buffer[0].Length; //error: indexer returns Objects.
myMessage.Sort(); //error: IList does not have a Sort() method.
firstLen = GetFirstLength(myMessage); //error: not an IMessage<List<string>>
//but, an IList is an IList no matter what, so this works.
myMessage.buffer = new List<int>(); 

...

//this class keeps the generic open so T can be any IList, determined at instantiation.
class MyMessage2<T>:IMessage<T> where T:IList
{
    public T buffer {get;set;}

    //buffer's exact type is still not known here,
    //so inside this class you are still restricted to IList members only
    public int BufferCount{get{return buffer.Count;}}

    public void SortBuffer()
    {
       buffer.Sort(); //error; no such method
    }    
}

...

//but, once you define an instance, you know exactly what buffer is
var myMessage = new MyMessage2<List<string>>();
myMessage.buffer.Add("my message");
var firstLen = myMessage.buffer[0].Length; //now we know the indexer produces strings.
myMessage.buffer.Sort(); //buffer is known to be a List<T> which has Sort()
firstLen = GetFirstLength(myMessage);

...

//and when you pass it as a parameter, you can close the generic of the interface
public string GetFirstLength(IMessage<List<string>> message) 
{
   //...so you still know what you're dealing with
   return message.buffer[0].Length;
}

...

//however, buffer is now "strongly typed" and the implementation can't change
myMessage.buffer = new List<int>(); //error; buffer is of type List<string>

...

//this class closes the generic within the declaration.
class MyMessage3:IMessage<IList<string>>
{
   //now we're closing the generic in the implementation itself,
   //so internally we know exactly what we're dealing with
   public List<string> buffer {get;set;}

   //...so this call is valid
   public void SortBuffer() { buffer.Sort(); }
}

//...and consuming code doesn't have to (get to?) specify the implementation of T
var myMessage = new MyMessage3();
//... but still knows exactly what that implementation is
myMessage.buffer.Add("my message");
var firstLen = myMessage.buffer[0].Length;
myMessage.buffer.Sort();

//and btw, MyMessage3 is still an IMessage<List<string>>
firstLen = GetFirstLength(myMessage);

//... and buffer's still a strongly-typed List<string>
myMessage.buffer = new List<int>(); //error

都没有-接口不能有字段:PI不知道接口不能有字段。我还没有编译这段代码,所以VS没有触发任何错误/警告。谢谢你的建议。两者都不是-接口不能有字段:PI不知道接口不能有字段。我还没有编译这段代码,所以VS没有触发任何错误/警告。谢谢你的建议。