简体   繁体   中英

C# interface method declaration - cannot execution implemention

I have a concrete class implementation of an interface that has a method declaration like so....

public interface IControllerContent
{
     IEnumerable<KeyValuePair<string, string>> LocalResource();
}

public class BaseControllerContent : IControllerContent
{

   public IEnumerable<KeyValuePair<string, string>> LocalResource()
   {
     ResourceSet resourceSet =
     ResourceManager.GetResourceSet(new CultureInfo(this.Tenant.Locale), true, false);

     IDictionaryEnumerator dictionaryEnumerator = resourceSet.GetEnumerator();

        while (dictionaryEnumerator.MoveNext())
        {
            //only string resources
            var value = dictionaryEnumerator.Value as string;
            if (value != null)
            {
                var key = (string)dictionaryEnumerator.Key;
                yield return new KeyValuePair<string, string>(key, value);
            }
        }
    }
}

All fairly straight forward. Declare an interface and implement from a concrete class. However when I try to call the LocalResource method of the concrete class I get an exception.

public T Build<T>() where T : class, IControllerContent
{
     var controllerContent = Activator.CreateInstance(typeof(T)) as T;
     try
     {
         **controllerContent.CDict = (Dictionary<string, string>) controllerContent.LocalResource();**
         controllerContent.CDict = (Dictionary<string, string>) JsonReader<T>.Parse(this.Content);
         return controllerContent;
      }
      catch (Exception ex)
      {
         throw new Exception();
      }
}

The exception occurs when trying to execute the LocalResource() method (highlighted above).

{System.InvalidCastException: Unable to cast object of type '<LocalResource>d__0' to type 'System.Collections.Generic.Dictionary`2[System.String,System.String]'. at FantasyLeague.Web.Mvc.ControllerContentBuilder.BuildT in C:\\Users\\andrew.knightley\\git\\FAST\\src\\ContentManagement\\FantasyLeague.Web.Mvc\\ControllerBase.cs:line 290}

Basically it appears that C# is trying to parse the interface method signature as a Dictionary, hence the error, however surely it should be trying to execute the concrete implementation. Anyone know whats going on here? I've tried casting to interface and concrete type and all combinations, it still isn't having it. I have reread all the MSDN stuff on interfaces, according to their articles there is nothing out of the ordinary here.

Many thanks in advance.

Simply put, your implementation isn't returning a Dictionary<string, string> , so you can't cast to it. You're just returning a sequence of key/value pairs - that's not the same thing as a dictionary.

Note that this has nothing to do with the method being declared on an interface - you're calling the right implementation, but just casting the result. You can see this by separating the two:

IEnumerable<KeyValuePair<string, string>> tmp = controllerContent.LocalResource();
controllerContent.CDict = (Dictionary<string, string>) tmp; // Bang!

The simplest fix would be to create a dictionary with LINQ:

controllerContent.CDict = controllerContent.LocalResource()
                                           .ToDictionary(x => x.Key, x => x.Value);

Note that an alternative implementation of your LocalResource() method could also use LINQ:

public IEnumerable<KeyValuePair<string, string>> LocalResource()
{
    ResourceSet resourceSet = ResourceManager.GetResourceSet(
        new CultureInfo(this.Tenant.Locale), true, false);
    return resourceSet.Cast<DictionaryEntry>()
                      .Where(de => de.Value is string)
                      .Select(de => new KeyValuePair((string) de.Key,
                                                     (string) de.Value));
}

That will end up boxing each DictionaryEntry , but it's somewhat simpler than your iterator block approach, IMO.

The problem is with the cast from the results of your method -> Dictionary<string,string>

Try the following code in LinqPad to see the issue.

void Main()
{

    Dictionary<string, string> results  = (Dictionary<string, string>)GetResults();
}

public IEnumerable<KeyValuePair<string, string>> GetResults()
{
    yield return new KeyValuePair<string,string>("a", "a");
    yield return new KeyValuePair<string,string>("b", "b");
    yield return new KeyValuePair<string,string>("c", "c");
}

You can't cast directly from an IEnumerable<KeyValuePair<string,string>> to Dictionary<string,string> .

Try changing your conversion to the following

var x = GetResults();
Dictionary<string, string> results  = x.ToDictionary(y => y.Key, y => y.Value);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM