【问题标题】:Implementing Interface in code在代码中实现接口
【发布时间】:2009-06-23 09:06:33
【问题描述】:

这几天我一直在摸不着头脑,但我仍然不明白如何实现这个接口。

这是我的代码:

namespace ConsoleApplication32 {
public static class ScanAndSerialize
{

    public static void Serialize()
    {

        List<string> dirs = FileHelper.GetFilesRecursive("s:\\");
        List<string> dirFiles = new List<string>();
        foreach (string p in dirs)
        {
            string path = p;
            string lastAccessTime = File.GetLastAccessTime(path).ToString();
            bool DirFile = File.Exists(path);
            DateTime lastWriteTime = File.GetLastWriteTime(p);
            //dirFiles.Add(p + " , " + lastAccessTime.ToString() + " , " + DirFile.ToString() + " , " + lastWriteTime.ToString());
            dirFiles.Add(p);
            dirFiles.Add(lastAccessTime);
            dirFiles.Add(DirFile.ToString());
            dirFiles.Add(lastWriteTime.ToString());
            dirFiles.Add(Environment.NewLine);

        }


        XmlSerializer SerializeObj = new XmlSerializer(dirFiles.GetType());
        string sDay = DateTime.Now.ToString("MMdd");
        string fileName = string.Format(@"s:\project\{0}_file.xml", sDay);
        TextWriter WriteFileStream = new StreamWriter(fileName);

        SerializeObj.Serialize(WriteFileStream, dirFiles);
        WriteFileStream.Close();


    }

    static class FileHelper
    {
        public static List<string> GetFilesRecursive(string b)
        {
            // 1.
            // Store results in the file results list.
            List<string> result = new List<string>();

            // 2.
            // Store a stack of our directories.
            Stack<string> stack = new Stack<string>();

            // 3.
            // Add initial directory.
            stack.Push(b);

            // 4.
            // Continue while there are directories to process
            while (stack.Count > 0)
            {
                // A.
                // Get top directory
                string dir = stack.Pop();

                try
                {
                    // B
                    // Add all files at this directory to the result List.
                    result.AddRange(Directory.GetFiles(dir, "*.*"));

                    // C
                    // Add all directories at this directory.
                    foreach (string dn in Directory.GetDirectories(dir))
                    {
                        stack.Push(dn);
                    }
                }
                catch
                {
                    // D
                    // Could not open the directory
                }
            }
            return result;
        }
    }



    public class MyInterface: IValidationRowSet
    {

        public int RowNumber { get; set; }

        public string RowAsString { get; set; }
        public IValidationRowSet MatchedRow { get; set; }
        public string FriendlyNameLabel { get; set; }
        public string KeyFieldLabel { get; set; }
        IList<string> lst = new List<string>();
        public string SourceWorksheetName { get; set; }
        public string SourceRangeName { get; set; }
        //public string SourceRangeName { get; set; }
        public bool bReported { get; set; }

        public int FieldCount { get { return lst.Count; } }
        public string FieldData(int id)
        {
            if (id <= lst.Count)
                return lst[id];
            else
                return null;
        }
        public string ValidationMessage { get; set; }




    }

这是界面的解释(我还在为这个而摸不着头脑)

namespace Validation {
/// <summary>
/// Implement this interface if you want the engine to callback when it finds exception
/// messages.  You will pass a reference to you class to the validation engine, and 
/// it will call "PostValidationMessage" for each exception example, including the message,
/// the entire row set of data (vr), and the id of the field that created the exception.
/// </summary>
public interface IValidationReporter
{
/// <param name="sMsg"></param>
/// <param name="vr"></param>
/// <param name="id"></param>
    void PostValidationMessage(string sMsg, IValidationRowSet vr, int id);
}


/// <summary>
/// Implement this interface in order to use the validation engine.
/// The validation engine takes 2 IList<IValidationRowSet> objects and compares them.
/// A class that implements this interface will contain an entire row of data that you'll
/// want to compare.
/// </summary>
public interface IValidationRowSet
{

    /// <summary>
    /// should return an int of the number of fields in this row
    /// </summary>
    int FieldCount { get; }

    /// <summary>
    /// should return an int of the row number that this row is in the set
    /// usually set when the data is assembled
    /// </summary>
    int RowNumber { get; set; }

    /// <summary>
    /// this is a function that should return the field data for this row at zero-indexed location "id"
    /// ex: if the row contains this data: smith|fred|2126782524|fred@smith.com|
    /// a call on this method of FieldData(2) will return the phone number 2126782524
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    string FieldData(int id);

    /// <summary>
    /// this will be modified by the validation process
    /// </summary>
    string ValidationMessage { get; set; }

    /// <summary>
    /// this will be modified by the validation process
    /// </summary>
    IValidationRowSet MatchedRow { get; set; }

    /// <summary>
    /// returns a string that uniquely identifies this row
    /// ex: if the row contains this data: smith|fred|2126782524|fred@smith.com|
    /// so for this example, the unique identifier could be the email address fred@smith.com
    /// </summary>
    string KeyFieldLabel { get; set; }

    /// <summary>
    /// returns a string with the "friendly" name of this row
    /// ex: if the row contains this data: smith|fred|2126782524|fred@smith.com|
    /// so for this example, FriendlyNameLabel could be the name, such as "Fred Smith"
    /// </summary>
    string FriendlyNameLabel { get; set; }

    /// <summary>
    /// returns all fields in the row as pipe delimited
    /// ex: 1,234.23|Fred Smith|Fred@smith.com|
    /// </summary>
    string RowAsString { get; set; }


    /// <summary>
    /// if this is an excel file comparison, this should return the name 
    /// of the worksheet from whence this data came
    /// </summary>
    string SourceWorksheetName { get; set; }


    /// <summary>
    /// if this is an excel file comparison, this should return the name 
    /// of the worksheet range from whence this data came
    /// </summary>
    string SourceRangeName { get; set; }

    /// <summary>
    /// this will be modified by the validation process
    /// </summary>
    bool bReported { get; set; }
}
}

我已经阅读了许多关于接口的文章/书籍/论坛帖子。这个概念对我来说就像一个黑洞……我正在一个项目中,我必须实现它。有人知道你是如何实现这个的吗?顺便说一句——我是一个完整的新手程序员......不到 2 个月的经验......所以请不要因为我的绿色而责备我。

提前致谢。

【问题讨论】:

  • 感谢大家帮助我理解接口是什么以及它做得更好:) 有人知道如何在我的项目中实现这个特定的接口吗?可悲的是,我在工作中的帮助为零,而且时间紧迫。
  • 你到底卡在哪里了?您必须完成从 FieldData 和 FieldCount 开始的工作 - 实现 all 方法。例如,RowNumber 可以简单地返回一个私有整数字段(“return rowNo;”},而 RowAsString 应该是一个连接字符串,如注释中所述。

标签: c# interface


【解决方案1】:

将接口视为要填充拼图的原型或模板 - 将它们视为放置碎片的空白和线条。您必须将接口派生为具体的类 - 漂亮的图片难题。

让我保存这个,我会举一个例子。

interface IFoo
{
    bool DoFoo(int number);
}

class Foo : IFoo
{
    public bool DoFoo(int number) {
         return (number++ >= 0); 
    }
}

class Foo2 : IFoo
{
    public bool DoFoo(int number) {
         return (number-- >= 0); 
    }
}

现在我有了它,我可以做这样的事情了。

IFoo foo;

if (!value)
    foo = new Foo();
else
    foo = new Foo2();

bool value2 = foo.DoFoo(27);

注意,我不能对接口执行此操作:

// WRONG
Foo2 foo2 = new Foo();

所以这基本上总结了一个接口的作用和它是如何工作的。你现在的工作是实现接口的那些具体实现。

【讨论】:

  • 我猜他确实知道什么是接口。至少——理论上。 :)
  • 没错,但他说这是一个“黑洞”/
  • 当我的意思是它就像一个“黑洞”时,在这篇文章之前,我对我所读到的内容几乎没有理解为什么地球上有人会使用它......此外,大多数人的实现我看到的在线示例是简单的小东西,对更复杂的实现没有帮助。很抱歉,如果我的新鲜感冒犯了这里的任何人。
  • @yeahumok - 我们都曾在某个时候出现过。我希望我的例子有所帮助。
【解决方案2】:

作为一名新开发人员,我发现将接口视为模板的最佳方式,该模板包含有关类的所有公共信息(属性、方法等)作为需要为类创建的列表实施它以完成这些方法等所需的工作。

现在应该有很多人会比我更好地解释这一点,并纠正我的错误,并希望以您(希望我)可以理解的方式解释与文章/书籍/帖子不同的界面:)

【讨论】:

    【解决方案3】:

    您可以将界面想象成您的班级必须回答的问题列表。这样,您就可以创建许多类,它们都将以不同的方式回答这些问题。

    但对于提出问题的人(即 ValidationReporter)来说,获得答案很重要,而不是由谁来回答。

    一个。你需要告诉编译器你的类实现了接口

    // my class implements the interface
    public class MyValidationRowSet : IValidationRowSet
    

    b.您需要实现每个接口方法。这意味着您需要确保每个方法确实做了一些事情。在 Visual Studio 中,您可以通过右键单击上一行中的接口并从上下文菜单中选择“实现接口”来获得一些帮助。这将创建方法存根(您可以填写的空方法)。

    public class MyValidationRowSet : IValidationRowSet
    {
         public int FieldCount
         { 
             get
             {
                 // return something
             }
         }
    
        // you will need to implement each method from your
        // interface in order to compile successfully
    }
    

    我可以从您的代码 (public class MyInterface: IValidationRowSet) 中看到您没有实现任何方法 - 您将它们全部留空。在确定您的方法返回正确的结果之前,编译器不会让您运行程序。

    c。基本上就是这样。一旦你通过了点 a.,编译器不会让你运行程序,直到你在那个接口中实现了 all 方法。完成后,您可以为您的班级创建一个新的实例,它可以“给出答案”:

    // create a new instance of your class
    MyValidationRowSet instance = new MyValidationRowSet();
    

    【讨论】:

      【解决方案4】:

      作为取得进展的指南,我建议对所有方法进行硬编码以返回虚拟数据,或者抛出未实现的异常。

      例如:

      RowNumber // Always returns 1
      RowAsString // return "FirstName,LastName,PhoneNumber"
      MatchedRow  // throw exception
      FriendlyNameLabel // return "MyFriendlyRow"
      KeyFieldLabel// return "MyKeyField"
      SourceWorksheetName // return "DefaultWorksheet"
      SourceRangeName  // return "DefaultRange"
      bReported // return true;
      FieldCount // return 3 (to match the number of fields indicated in RowAsString
      FieldData // simple switch/case: 0=>FirstName, 1=>lastName, 2=>PhoneNumber
      ValidationMessage // return "Data not validated"
      

      这应该使您的代码编译...甚至可能运行,然后您可以开始调试它以弄清楚它应该如何使用。一点一点地,删除“虚拟”实现并放入“真实”代码。

      附注:您的初始代码块“ScanAndSerialize”似乎与 IValidationRowSet 无关。有没有我缺少的连接?

      【讨论】:

        【解决方案5】:

        很难说出您对界面的看法。

        接口是一个抽象概念。不仅字面上而且本质上是抽象类和接口不能被实例化。接口比抽象类更抽象,因为它不能包含任何可执行代码。它在接口的使用者和实现接口的类之间建立了契约。

        现在,如果您听到多态性并开始摸不着头脑,那么接口将是一个棘手的问题。接口是在应用程序中引入多态性的常用方法之一。您可以有许多 IValidationReporter 和 IValidationRowSet 的实现。由于您抽象了他们的合约,因此任何可以使用这些抽象的代码都将能够保持不变,即使在您切换这些合约的实现的情况下也是如此。

        您的代码实现了其中一个接口,但没有实现另一个。另请注意,静态构造不能在合约(接口)中表达

        【讨论】:

        • 我相信这并不难,只是需要一些练习。 :)
        【解决方案6】:

        不完全确定你在问什么,但这里有一些观察:

        公共类 MyInterface: IValidationRowSet { ... }

        MyInterface 不是您的类的“智能”名称,因为它不是接口。 它是接口的实际实现。我建议改为 ValidationRowSetImpl 或 MyRowSet 或类似的。

        还有,你有

        IList<string> lst = new List<string>();
        

        卡在你的接口实现中间。 应该明确提到它是“私有的”,并且出于良好组织的原因,应该在你的班级底部。接口中的所有方法都应该放在一起,与接口的顺序相同。所有使用的私人日期都应低于此日期。

        【讨论】:

        • 底部或顶部。但要保持一致:)
        【解决方案7】:

        如果您使用的是 Visual Studio,只需编写“public class foo : IValidationRowSet”。然后左键点击foo,然后shift+alt+f10,向下,回车。这将为接口实现生成一个存根。

        并且不要将类命名为“MyInterface”,这会造成混淆。它是接口的实现,而不是接口本身。 :)

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-12-03
          • 2011-03-30
          • 2011-08-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多