Строго типизированные функции поиска для класса? - PullRequest
0 голосов
/ 08 марта 2012

Я пытаюсь что-то выяснить с помощью кода на C #, и я не уверен на 100%, если это возможно, но я пытаюсь реализовать функциональность поиска по нескольким классам, которая упрощена и в целом проста для разработки.Сейчас у меня есть следующий код:

[DataContract(IsReference = true), Serializable]
public class ClassSearch
{
    [DataMember]
    public string Name { get; set; }

    [DataMember]
    public object Value { get; set; }

    public override string ToString()
    {
        return String.Format("{0} = {1}", Name, Value);
    }

    ... // additional logic
}

Однако я хотел бы включить строгую типизацию для значения объекта, чтобы его можно было установить только для переданного свойства, я думаю, что похоже (гипотетически, не уверен, сработает ли это)

[DataContract(IsReference = true), Serializable]
public class ClassSearch<TProperty>
{
    [DataMember]
    public TProperty Property {get; set; }


    public override string ToString()
    {
        return String.Format("{0} = '{1}'", Property.Name, Property);
    }

    ... // additional logic
}

public class MainClass
{
    public void Execute()
    {
        SomeClass someClass = new Class{
            Property = "Value";
        };

        ClassSearch search = new ClassSearch<SomeClass.Property>{
            Property = someClass.Property
        };

        var retString = search.ToString(); // Returns "Property = 'Value'"
    }
}

Ответы [ 2 ]

0 голосов
/ 08 марта 2012

Если нет более простых ответов, я бы попробовал это с этим.
Вы можете использовать выражения примерно так:

// Sample object with a property. 
SomeClass someClass = new SomeClass{Property = "Value"};

// Create the member expression.
Expression<Func<object /*prop owner object*/, object/*prop value*/>> e =
    owner => ((SomeClass)owner).Property;

// Get property name by analyzing expression.
string propName = ((MemberExpression)e.Body).Member.Name;

// Get property value by compiling and running expression.
object propValue = e.Compile().Invoke(someClass);

Вы передаете свою собственность участникувыражение owner => ((SomeClass)owner).Property.Это выражение содержит необходимую информацию: имя свойства и значение свойства.Последние две строки показывают, как получить имя и значение.


Следуя большему примеру :

class MainClass
{
  public static void Execute()
  {
    SomeClass someClass = new SomeClass{
        Property = "Value"
    };


    var search = new ClassSearch(s => ((SomeClass)s).Property);

    Console.Out.WriteLine("{0} = '{1}'", search.Property.Name, search.Property.GetValue(someClass));
  }
}

class Reflector
{
  public static string GetPropertyName(Expression<Func<object, object>> e)
  {
    if (e.Body.NodeType != ExpressionType.MemberAccess)
    {
      throw new ArgumentException("Wrong expression!");
    }

    MemberExpression me = ((MemberExpression) e.Body);

    return me.Member.Name;
  }
}

class ClassSearch
{
  public ClassSearch(Expression<Func<object, object>> e)
  {
    Property = new PropertyNameAndValue(e);
  }

  public PropertyNameAndValue Property { get; private set; }


  public override string ToString()
  {
    return String.Format("{0} = '{1}'", Property.Name, Property);
  }
}

class PropertyNameAndValue
{
  private readonly Func<object, object> _func;

  public PropertyNameAndValue(Expression<Func<object, object>> e)
  {
    _func = e.Compile();
    Name = Reflector.GetPropertyName(e);
  }

  public object GetValue(object propOwner)
  {
    return _func.Invoke(propOwner);
  }

  public string Name { get; private set; }
}


class SomeClass
{
  public string Property { get; set; }
}

Основной частью этого примера является метод Reflector.GetPropertyName(...), который возвращаетимя свойства в выражении.Т.е. Reflector.GetPropertyName(s => ((SomeClass)s).Property) вернул бы «Свойство».

Преимущество : Это типобезопасно, потому что при new ClassSearch(s => s.Property) компиляция завершится ошибкой, если SomeClass не будет иметь свойства 'Property'.

Недостаток : Это небезопасно, потому что если вы напишите, например, new ClassSearch(s => s.Method()) и там будетбудь метод 'Method', тогда не будет ошибки компиляции, но будет ошибка времени выполнения.

0 голосов
/ 08 марта 2012

Кажется, вы пытаетесь создать службу WCF, чтобы иметь возможность передавать любой тип, который вам нравится.

Прежде всего, это не подходит для WSDL. Все службы WCF должны быть доступны в WSDL. WSDL - это все о четко определенных контрактах, поэтому все типы должны быть определены. Так что общий подход не будет работать - в основном из-за WSDL. Сказав это, вы все еще можете использовать дженерики, но тогда вам придется использовать KnownType и фактически определить все возможные типы - что для меня побеждает объект.

Тем не менее, вы можете самостоятельно сериализовать объект и передать его имя типа по проводам. С другой стороны, вы можете забрать его десериализовать.

Так что-то вроде:

// NOTE: Not meant for production!
[DataContract]
public class GenericWcfPayload
{
   [DataMember]
   public byte[] Payload {get; set;}

   [DataMember]
   public string TypeName {get; set;}
}
...